diff --git a/.circleci/config.yml b/.circleci/config.yml index 7b36bed7c..83f554916 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,92 +1,79 @@ version: 2.1 -commands: - setup-toolchain: - parameters: - toolchain: - type: string - toolchain_url: - type: string - steps: -# - run: -# name: Make toolchain cache key -# command: echo "<< parameters.toolchain >>-<< parameters.toolchain_url>>" > toolchain_key -# - restore_cache: -# name: Restore Toolchain Cache -# key: deps-{{ checksum "toolchain_key" }} -# paths: -# - ~/cache/<< parameters.toolchain >> - - run: - name: Install Toolchain - command: | - # Only download if folder does not exist (not cached) - if [ ! -d ~/cache/<< parameters.toolchain >> ]; then - mkdir -p ~/cache/<< parameters.toolchain >> - wget << parameters.toolchain_url>> -O toolchain.tar.gz - tar -C ~/cache/<< parameters.toolchain >> -xaf toolchain.tar.gz - fi -# - save_cache: -# name: Save Toolchain Cache -# key: deps-{{ checksum "toolchain_key" }} -# paths: -# - ~/cache/<< parameters.toolchain >> - - run: - name: Setup build environment - command: | - echo "export PATH=$PATH:`echo ~/cache/<< parameters.toolchain >>/*/bin`" >> $BASH_ENV - # Install Ninja - NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip - wget $NINJA_URL -O ninja-linux.zip - unzip ninja-linux.zip -d ~/bin - - get-deps: - parameters: - family: - type: string - steps: - - run: - name: Get Dependencies - command: | - python tools/get_deps.py << parameters.family >> +setup: true +orbs: + continuation: circleci/continuation@1 jobs: - arm-clang: - parameters: - family: - type: string - build-system: - type: string - + set-matrix: + executor: continuation/default docker: - image: cimg/base:current - resource_class: medium - environment: - TOOLCHAIN_URL: https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-17.0.1/LLVMEmbeddedToolchainForArm-17.0.1-Linux-x86_64.tar.xz + resource_class: small steps: - checkout - - setup-toolchain: - toolchain: clang - toolchain_url: $TOOLCHAIN_URL - - get-deps: - family: << parameters.family >> - run: - name: Build + name: Set matrix command: | - # Only build one board per family for non PRs i.e commit to master - ONE_PER_FAMILY="" - if [ -z "$CIRCLE_PULL_REQUEST" ]; then - ONE_PER_FAMILY="--one-per-family" - fi - python tools/build.py $ONE_PER_FAMILY -s << parameters.build-system >> --toolchain clang << parameters.family >> + MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py) + echo "MATRIX_JSON=$MATRIX_JSON" + + BUILDSYSTEM_TOOLCHAIN=( + "cmake arm-clang" + "make aarch64-gcc" + "make arm-gcc" + "make msp430-gcc" + "make riscv-gcc" + "make rx-gcc" + "cmake esp-idf" + ) + + RESOURCE_LARGE='["nrf", "imxrt"]' + + for e in "${BUILDSYSTEM_TOOLCHAIN[@]}"; do + e_arr=($e) + build_system="${e_arr[0]}" + toolchain="${e_arr[1]}" + FAMILY=$(echo $MATRIX_JSON | jq -r ".\"$toolchain\".family") + echo "FAMILY_${toolchain}=$FAMILY" + + # FAMILY_LARGE = FAMILY - RESOURCE_LARGE + # Separate large from medium+ resources + FAMILY_LARGE=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[])))') + FAMILY=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[]) | not))') + + if [[ $toolchain == esp-idf ]]; then + echo " - build-vm:" >> .circleci/config2.yml + else + echo " - build:" >> .circleci/config2.yml + fi + echo " matrix:" >> .circleci/config2.yml + echo " parameters:" >> .circleci/config2.yml + echo " build-system: ['$build_system']" >> .circleci/config2.yml + echo " toolchain: ['$toolchain']" >> .circleci/config2.yml + echo " family: $FAMILY" >> .circleci/config2.yml + #echo " resource_class: ['medium+']" >> .circleci/config2.yml + + # add large resources + if [ "$(echo $FAMILY_LARGE | jq 'length')" -gt 0 ]; then + echo " - build:" >> .circleci/config2.yml + echo " matrix:" >> .circleci/config2.yml + echo " parameters:" >> .circleci/config2.yml + echo " build-system: ['$build_system']" >> .circleci/config2.yml + echo " toolchain: ['$toolchain']" >> .circleci/config2.yml + echo " family: $FAMILY_LARGE" >> .circleci/config2.yml + echo " resource_class: ['large']" >> .circleci/config2.yml + fi + done + + - continuation/continue: + configuration_path: .circleci/config2.yml workflows: - build: + set-matrix: + # Only build PR here, Push will be built by github action. + when: + and: + - not: << pipeline.git.branch.is_default >> jobs: - - arm-clang: - matrix: - parameters: - build-system: - - cmake - #family: ['stm32f1'] - #family: ['stm32f1', 'stm32f2'] - family: ['imxrt', 'kinetis_k kinetis_kl kinetis_k32l2', 'lpc11 lpc13 lpc15', 'lpc17 lpc18 lpc40 lpc43', 'lpc51 lpc54 lpc55', 'nrf', 'samd11 samd21 saml2x', 'samd5x_e5x samg', 'stm32f0 stm32f1 stm32f2 stm32f3', 'stm32f4', 'stm32f7', 'stm32g0 stm32g4 stm32h5', 'stm32h7', 'stm32l4 stm32u5 stm32wb'] + - set-matrix diff --git a/.circleci/config2.yml b/.circleci/config2.yml new file mode 100644 index 000000000..542c3d0d0 --- /dev/null +++ b/.circleci/config2.yml @@ -0,0 +1,183 @@ +version: 2.1 + +commands: + setup-toolchain: + parameters: + toolchain: + type: string + + steps: + - 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-17.0.1/LLVMEmbeddedToolchainForArm-17.0.1-Linux-x86_64.tar.xz", + "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v12.3.1-1.1/xpack-arm-none-eabi-gcc-12.3.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://llvm-gcc-renesas.com/downloads/get.php?f=rx/8.3.0.202004-gnurx/gcc-8.3.0.202004-GNURX-ELF.run" + }' + toolchain_url=$(echo $TOOLCHAIN_JSON | jq -r '.["<< parameters.toolchain >>"]') + + # only cache if not a github link + if [[ $toolchain_url != "https://github.com"* ]]; then + echo "<< parameters.toolchain >>-$toolchain_url" > toolchain_key + fi + echo "export toolchain_url=$toolchain_url" >> $BASH_ENV + + - restore_cache: + name: Restore Toolchain Cache + key: deps-{{ checksum "toolchain_key" }} + paths: + - ~/cache/<< parameters.toolchain >> + + - run: + name: Install Toolchain + command: | + # download if folder does not exist (not cached) + if [ ! -d ~/cache/<< parameters.toolchain >> ]; then + mkdir -p ~/cache/<< parameters.toolchain >> + wget --progress=dot:giga $toolchain_url -O toolchain.tar.gz + if [[ << parameters.toolchain >> == rx-gcc ]]; then + mv toolchain.tar.gz toolchain.run + chmod +x toolchain.run + ./toolchain.run -p ~/cache/<< parameters.toolchain >>/gnurx -y + else + tar -C ~/cache/<< parameters.toolchain >> -xaf toolchain.tar.gz + fi + fi + + # Add toolchain to PATH + echo "export PATH=$PATH:`echo ~/cache/<< parameters.toolchain >>/*/bin`" >> $BASH_ENV + + - save_cache: + name: Save Toolchain Cache + key: deps-{{ checksum "toolchain_key" }} + paths: + - ~/cache/<< parameters.toolchain >> + + build: + parameters: + build-system: + type: string + toolchain: + type: string + family: + type: string + + steps: + - checkout + - when: + condition: + not: + equal: [esp-idf, << parameters.toolchain >>] + steps: + - setup-toolchain: + toolchain: << parameters.toolchain >> + + - run: + name: Get Dependencies + command: | + python tools/get_deps.py << parameters.family >> + + # Install ninja if cmake build system + if [ << parameters.build-system >> == "cmake" ]; then + NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip + wget $NINJA_URL -O ninja-linux.zip + unzip ninja-linux.zip -d ~/bin + fi + + # rx-gcc is 32-bit binary + if [[ << parameters.toolchain >> == rx-gcc ]]; then + sudo dpkg --add-architecture i386 + sudo apt update + sudo apt install libc6:i386 libstdc++6:i386 zlib1g:i386 + fi + + # Install Pico SDK + if [ << parameters.family >> == "rp2040" ]; then + git clone --depth 1 https://github.com/raspberrypi/pico-sdk.git ~/pico-sdk + echo "export PICO_SDK_PATH=~/pico-sdk" >> $BASH_ENV + fi + + - run: + name: Build + command: | + if [ << parameters.toolchain >> == esp-idf ]; then + docker run --rm -v $PWD:/project -w /project espressif/idf:v5.1.1 python tools/build.py << parameters.family >> + else + # Toolchain option default is gcc + if [ << parameters.toolchain >> == arm-clang ]; then + TOOLCHAIN_OPTION="--toolchain clang" + elif [ << parameters.toolchain >> == arm-gcc ]; then + TOOLCHAIN_OPTION="--toolchain gcc" + fi + + python tools/build.py -s << parameters.build-system >> $TOOLCHAIN_OPTION << parameters.family >> + fi + +jobs: + # Build using docker + build: + parameters: + resource_class: + type: string + default: medium+ + build-system: + type: string + toolchain: + type: string + family: + type: string + + docker: + - image: cimg/base:current + resource_class: << parameters.resource_class >> + + steps: + - build: + build-system: << parameters.build-system >> + toolchain: << parameters.toolchain >> + family: << parameters.family >> + + # Build using VM + build-vm: + parameters: + resource_class: + type: string + default: large + build-system: + type: string + toolchain: + type: string + family: + type: string + + machine: + image: ubuntu-2404:current + resource_class: << parameters.resource_class >> + + steps: + - build: + build-system: << parameters.build-system >> + toolchain: << parameters.toolchain >> + family: << parameters.family >> + +workflows: + build: + jobs: +# - build: +# matrix: +# parameters: +# toolchain: [ 'arm-gcc' ] +# build-system: [ 'cmake' ] +# family: [ 'nrf' ] +# resource_class: ['large'] +# - build-vm: +# matrix: +# parameters: +# toolchain: ['esp-idf'] +# build-system: ['cmake'] +# family: ['-bespressif_kaluga_1'] +# resource_class: ['large'] diff --git a/.github/actions/setup_toolchain/action.yml b/.github/actions/setup_toolchain/action.yml index 19fe28b0c..5b9bc95ce 100644 --- a/.github/actions/setup_toolchain/action.yml +++ b/.github/actions/setup_toolchain/action.yml @@ -4,8 +4,8 @@ inputs: toolchain: description: 'Toolchain name' required: true - toolchain_url: - description: 'Toolchain URL or version' + toolchain_version: + description: 'Toolchain version' required: false outputs: @@ -27,7 +27,26 @@ runs: uses: ./.github/actions/setup_toolchain/espressif with: toolchain: ${{ inputs.toolchain }} - toolchain_url: ${{ inputs.toolchain_url }} + toolchain_version: ${{ inputs.toolchain_version }} + + - 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-17.0.1/LLVMEmbeddedToolchainForArm-17.0.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": "http://gcc-renesas.com/downloads/get.php?f=rx/8.3.0.202004-gnurx/gcc-8.3.0.202004-GNURX-ELF.run" + }' + TOOLCHAIN_URL=$(echo $TOOLCHAIN_JSON | jq -r '.["${{ inputs.toolchain }}"]') + echo "toolchain_url=$TOOLCHAIN_URL" + echo "toolchain_url=$TOOLCHAIN_URL" >> $GITHUB_OUTPUT + shell: bash - name: Download Toolchain if: >- @@ -37,7 +56,7 @@ runs: uses: ./.github/actions/setup_toolchain/download with: toolchain: ${{ inputs.toolchain }} - toolchain_url: ${{ inputs.toolchain_url }} + toolchain_url: ${{ steps.set-toolchain-url.outputs.toolchain_url }} - name: Set toolchain option id: set-toolchain-option diff --git a/.github/actions/setup_toolchain/espressif/action.yml b/.github/actions/setup_toolchain/espressif/action.yml index 46da02911..1e3ce18f1 100644 --- a/.github/actions/setup_toolchain/espressif/action.yml +++ b/.github/actions/setup_toolchain/espressif/action.yml @@ -4,8 +4,8 @@ inputs: toolchain: description: 'Toolchain name' required: true - toolchain_url: - description: 'Toolchain URL or version' + toolchain_version: + description: 'Toolchain version' required: true runs: @@ -22,14 +22,14 @@ runs: id: cache-toolchain-espressif with: path: ${{ env.DOCKER_ESP_IDF }} - key: ${{ inputs.toolchain }}-${{ inputs.toolchain_url }} + key: ${{ inputs.toolchain }}-${{ inputs.toolchain_version }} - name: Pull and Save Docker Image if: steps.cache-toolchain-espressif.outputs.cache-hit != 'true' run: | - docker pull espressif/idf:${{ inputs.toolchain_url }} + docker pull espressif/idf:${{ inputs.toolchain_version }} mkdir -p $(dirname $DOCKER_ESP_IDF) - docker save -o $DOCKER_ESP_IDF espressif/idf:${{ inputs.toolchain_url }} + docker save -o $DOCKER_ESP_IDF espressif/idf:${{ inputs.toolchain_version }} du -sh $DOCKER_ESP_IDF shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 712c7dd43..6ca9885f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,14 +51,13 @@ jobs: # Build CMake # --------------------------------------- cmake: - # if: false needs: set-matrix uses: ./.github/workflows/build_util.yml strategy: fail-fast: false matrix: toolchain: - # - 'arm-clang' is built by circle-ci + # - 'arm-clang' is built by circle-ci in PR - 'aarch64-gcc' - 'arm-gcc' - 'msp430-gcc' @@ -66,38 +65,38 @@ jobs: with: build-system: 'cmake' toolchain: ${{ matrix.toolchain }} - toolchain_url: ${{ fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain].toolchain_url }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain].family) }} - one-per-family: ${{ github.event_name != 'pull_request' }} + one-per-family: ${{ github.event_name == 'push' }} # --------------------------------------- - # Build Make + # Build Make (built by circle-ci in PR, only build on push here) # --------------------------------------- make: - # if: false + if: github.event_name == 'push' needs: set-matrix uses: ./.github/workflows/build_util.yml strategy: fail-fast: false matrix: toolchain: - # 'arm-clang' is built by circle-ci - - 'aarch64-gcc' + # 'arm-clang' - 'arm-gcc' + - 'aarch64-gcc' - 'msp430-gcc' - 'riscv-gcc' - 'rx-gcc' + - 'esp-idf' # buid-system is ignored with: build-system: 'make' toolchain: ${{ matrix.toolchain }} - toolchain_url: ${{ fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain].toolchain_url }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain].family) }} - one-per-family: ${{ github.event_name != 'pull_request' }} + one-per-family: true # --------------------------------------- # Build Make on Windows/MacOS # --------------------------------------- make-os: + if: github.event_name == 'pull_request' uses: ./.github/workflows/build_util.yml strategy: fail-fast: false @@ -110,31 +109,10 @@ jobs: build-args: '["stm32h7"]' one-per-family: true - # --------------------------------------- - # Build Espressif - # --------------------------------------- - espressif: - # if: false - uses: ./.github/workflows/build_util.yml - strategy: - fail-fast: false - matrix: - board: - # ESP32-S2 - - 'espressif_kaluga_1' - # ESP32-S3 skip since devkitm is also compiled in hil-test workflow - #- 'espressif_s3_devkitm' - with: - build-system: 'cmake' - toolchain: 'esp-idf' - toolchain_url: 'v5.1.1' - build-args: '["-b${{ matrix.board }}"]' - # --------------------------------------- # Build IAR on HFP self-hosted # --------------------------------------- arm-iar: - # if: false if: github.repository_owner == 'hathach' needs: set-matrix runs-on: [self-hosted, Linux, X64, hifiphile] diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index 49a9feabd..ff98aef2d 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -9,9 +9,6 @@ on: toolchain: required: true type: string - toolchain_url: - required: false - type: string build-args: required: true type: string @@ -40,7 +37,7 @@ jobs: uses: ./.github/actions/setup_toolchain with: toolchain: ${{ inputs.toolchain }} - toolchain_url: ${{ inputs.toolchain_url }} + toolchain_version: 'v5.1.1' - name: Get Dependencies uses: ./.github/actions/get_deps @@ -58,11 +55,10 @@ jobs: shell: bash - name: Build - if: inputs.toolchain != 'esp-idf' run: | - python tools/build.py -s ${{ inputs.build-system }} ${{ steps.setup-toolchain.outputs.build_option }} ${{ steps.set-one-per-family.outputs.build_option }} ${{ matrix.arg }} - - - name: Build using ESP-IDF docker - if: inputs.toolchain == 'esp-idf' - run: | - docker run --rm -v $PWD:/project -w /project espressif/idf:${{ inputs.toolchain_url }} python3 tools/build.py ${{ matrix.arg }} + if [ "${{ inputs.toolchain }}" == "esp-idf" ]; then + docker run --rm -v $PWD:/project -w /project espressif/idf:v5.1.1 python tools/build.py ${{ matrix.arg }} + else + python tools/build.py -s ${{ inputs.build-system }} ${{ steps.setup-toolchain.outputs.build_option }} ${{ steps.set-one-per-family.outputs.build_option }} ${{ matrix.arg }} + fi + shell: bash diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py index 5584b8312..4da26bfea 100644 --- a/.github/workflows/ci_set_matrix.py +++ b/.github/workflows/ci_set_matrix.py @@ -1,26 +1,29 @@ import json # toolchain, url -toolchain_list = { - "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-17.0.1/LLVMEmbeddedToolchainForArm-17.0.1-Linux-x86_64.tar.xz", - "arm-iar": "", - "arm-gcc": "", - "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": "http://gcc-renesas.com/downloads/get.php?f=rx/8.3.0.202004-gnurx/gcc-8.3.0.202004-GNURX-ELF.run", -} +toolchain_list = [ + "aarch64-gcc", + "arm-clang", + "arm-iar", + "arm-gcc", + "esp-idf", + "msp430-gcc", + "riscv-gcc", + "rx-gcc" +] # family: [supported toolchain] family_list = { "broadcom_32bit": ["arm-gcc"], "broadcom_64bit": ["aarch64-gcc"], "ch32v10x ch32v20x ch32v307 fomu gd32vf103": ["riscv-gcc"], + "da1469x": ["arm-gcc"], "imxrt": ["arm-gcc", "arm-clang"], "kinetis_k kinetis_kl kinetis_k32l2": ["arm-gcc", "arm-clang"], "lpc11 lpc13 lpc15": ["arm-gcc", "arm-clang"], "lpc17 lpc18 lpc40 lpc43": ["arm-gcc", "arm-clang"], "lpc51 lpc54 lpc55": ["arm-gcc", "arm-clang"], + "max32650 max32666 max32690 max78002": ["arm-gcc"], "mcx": ["arm-gcc"], "mm32": ["arm-gcc"], "msp430": ["msp430-gcc"], @@ -29,21 +32,25 @@ family_list = { "ra": ["arm-gcc"], "rp2040": ["arm-gcc"], "rx": ["rx-gcc"], - "samd11 samd21 saml2x": ["arm-gcc", "arm-clang"], + "samd11 saml2x": ["arm-gcc", "arm-clang"], + "samd21": ["arm-gcc", "arm-clang"], "samd5x_e5x samg": ["arm-gcc", "arm-clang"], "stm32f0 stm32f1 stm32f2 stm32f3": ["arm-gcc", "arm-clang", "arm-iar"], "stm32f4": ["arm-gcc", "arm-clang", "arm-iar"], "stm32f7": ["arm-gcc", "arm-clang", "arm-iar"], "stm32g0 stm32g4 stm32h5": ["arm-gcc", "arm-clang", "arm-iar"], "stm32h7": ["arm-gcc", "arm-clang", "arm-iar"], - "stm32l4 stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"], + "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"], } def set_matrix_json(): matrix = {} - for toolchain in toolchain_list.keys(): + for toolchain in toolchain_list: filtered_families = [family for family, supported_toolchain in family_list.items() if toolchain in supported_toolchain] @@ -54,7 +61,7 @@ def set_matrix_json(): hfp_boards = [f"-b{board['name']}" for board in hfp_data['boards']] filtered_families = filtered_families + hfp_boards - matrix[toolchain] = {"family": filtered_families, "toolchain_url": toolchain_list[toolchain]} + matrix[toolchain] = {"family": filtered_families} print(json.dumps(matrix)) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 622d261a0..d7f1fc066 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -26,7 +26,7 @@ jobs: with: oss-fuzz-project-name: 'tinyusb' language: c++ - fuzz-seconds: 600 + fuzz-seconds: 400 - name: Upload Crash uses: actions/upload-artifact@v4 diff --git a/.github/workflows/hil_test.yml b/.github/workflows/hil_test.yml index 39a9060a2..087374be2 100644 --- a/.github/workflows/hil_test.yml +++ b/.github/workflows/hil_test.yml @@ -17,31 +17,41 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + HIL_JSON: test/hil/rpi.json + jobs: - # --------------------------------------- - # Build Non Espressif - # --------------------------------------- - build: - if: github.repository_owner == 'hathach' + set-matrix: runs-on: ubuntu-latest outputs: - BOARDS_LIST: ${{ steps.parse_hil_json.outputs.BOARDS_LIST }} + json: ${{ steps.set-matrix-json.outputs.matrix }} steps: - name: Checkout TinyUSB uses: actions/checkout@v4 - - name: Parse HIL json - id: parse_hil_json + - name: Generate matrix json + id: set-matrix-json run: | - sudo apt install -y jq + MATRIX_JSON=$(jq -c '{ "arm-gcc": [.boards[] | select(.flasher != "esptool" and .flasher != "openocd_wch") | .name] }' ${{ env.HIL_JSON }}) + echo "matrix=$MATRIX_JSON" + echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - # Non-Espresif boards - BOARDS_LIST=$(jq -r '.boards[] | select(.flasher != "esptool") | "-b " + .name' test/hil/pi4.json | tr '\n' ' ') - echo "BOARDS_LIST=$BOARDS_LIST" - echo "BOARDS_LIST=$BOARDS_LIST" >> $GITHUB_ENV - echo "BOARDS_LIST=$BOARDS_LIST" >> $GITHUB_OUTPUT + # --------------------------------------- + # Build arm-gcc + # --------------------------------------- + build: + if: github.repository_owner == 'hathach' + needs: set-matrix + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + board: ${{ fromJSON(needs.set-matrix.outputs.json)['arm-gcc'] }} + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 - - name: Setup Toolchain + - name: Setup arm-gcc toolchain uses: ./.github/actions/setup_toolchain with: toolchain: 'arm-gcc' @@ -49,79 +59,27 @@ jobs: - name: Get Dependencies uses: ./.github/actions/get_deps with: - arg: ${{ env.BOARDS_LIST }} + arg: -b${{ matrix.board }} - name: Build - run: python tools/build.py $BOARDS_LIST + run: python tools/build.py -b${{ matrix.board }} - name: Upload Artifacts for Hardware Testing uses: actions/upload-artifact@v4 with: - name: hil_pi4 + name: ${{ matrix.board }} path: | cmake-build/cmake-build-*/*/*/*.elf cmake-build/cmake-build-*/*/*/*.bin - # --------------------------------------- - # Build Espressif - # --------------------------------------- - build-esp: - runs-on: ubuntu-latest - outputs: - BOARDS_LIST: ${{ steps.parse_hil_json.outputs.BOARDS_LIST }} - steps: - - name: Checkout TinyUSB - uses: actions/checkout@v4 - - - name: Parse HIL json - id: parse_hil_json - run: | - sudo apt install -y jq - # Espressif boards - BOARDS_LIST=$(jq -r '.boards[] | select(.flasher == "esptool") | "-b " + .name' test/hil/pi4.json | tr '\n' ' ') - echo "BOARDS_LIST=$BOARDS_LIST" - echo "BOARDS_LIST=$BOARDS_LIST" >> $GITHUB_ENV - echo "BOARDS_LIST=$BOARDS_LIST" >> $GITHUB_OUTPUT - - - name: Setup ESP-IDF - if: env.BOARDS_LIST != '' - uses: ./.github/actions/setup_toolchain - with: - toolchain: 'esp-idf' - toolchain_url: 'v5.1.1' - - - name: Get Dependencies - uses: ./.github/actions/get_deps - with: - arg: ${{ env.BOARDS_LIST }} - - - name: Build Espressif - if: env.BOARDS_LIST != '' - run: docker run --rm -v $PWD:/project -w /project espressif/idf:v5.1.1 python3 tools/build.py $BOARDS_LIST - - - name: Upload Artifacts for Hardware Testing - uses: actions/upload-artifact@v4 - with: - name: hil_pi4_esp - path: | - cmake-build/cmake-build-*/*/*/*.bin - cmake-build/cmake-build-*/*/*/bootloader/bootloader.bin - cmake-build/cmake-build-*/*/*/partition_table/partition-table.bin - cmake-build/cmake-build-*/*/*/config.env - cmake-build/cmake-build-*/*/*/flash_args - # --------------------------------------- # Hardware in the loop (HIL) - # Current self-hosted instance is running on an RPI4. For attached hardware checkout test/hil/pi4.json + # self-hosted running on an RPI. For attached hardware checkout test/hil/rpi.json # --------------------------------------- - hil-pi4: + hil-rpi: if: github.repository_owner == 'hathach' - needs: - - build - - build-esp - runs-on: [self-hosted, rp2040, nrf52840, esp32s3, hardware-in-the-loop] - env: - BOARDS_LIST: "${{ needs.build.outputs.BOARDS_LIST }} ${{ needs.build-esp.outputs.BOARDS_LIST }}" + needs: build + runs-on: [self-hosted, ARM64, rpi, hardware-in-the-loop] steps: - name: Clean workspace run: | @@ -129,12 +87,12 @@ jobs: rm -rf "${{ github.workspace }}" mkdir -p "${{ github.workspace }}" - # USB bus on rpi4 is not stable, reset it before testing - - name: Reset USB bus - run: | - # lsusb -t - # reset VIA Labs 2.0 hub - sudo usbreset 001/002 + # USB bus on rpi is not stable, reset it before testing +# - name: Reset USB bus +# run: | +# echo "1-2" | sudo tee /sys/bus/usb/drivers/usb/unbind +# sleep 5 +# echo "1-2" | sudo tee /sys/bus/usb/drivers/usb/bind - name: Checkout TinyUSB uses: actions/checkout@v4 @@ -144,19 +102,8 @@ jobs: - name: Download Artifacts uses: actions/download-artifact@v4 with: - name: hil_pi4 - path: cmake-build - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - name: hil_pi4_esp path: cmake-build + merge-multiple: true - name: Test on actual hardware - run: | - echo "BOARDS_LIST=$BOARDS_LIST" - echo "::group::{cmake-build contents}" - tree cmake-build - echo "::endgroup::" - python3 test/hil/hil_test.py $BOARDS_LIST pi4.json + run: python3 test/hil/hil_test.py ${{ env.HIL_JSON }} diff --git a/.gitignore b/.gitignore index 7a37d65dc..f2150a26f 100644 --- a/.gitignore +++ b/.gitignore @@ -31,62 +31,4 @@ cov-int __pycache__ cmake-build-* sdkconfig - -# submodules -hw/mcu/allwinner -hw/mcu/bridgetek/ft9xx/ft90x-sdk -hw/mcu/broadcom -hw/mcu/gd/nuclei-sdk -hw/mcu/infineon/mtb-xmclib-cat3 -hw/mcu/microchip -hw/mcu/mindmotion/mm32sdk -hw/mcu/nordic/nrfx -hw/mcu/nuvoton -hw/mcu/nxp/lpcopen -hw/mcu/nxp/mcux-sdk -hw/mcu/nxp/nxp_sdk -hw/mcu/raspberry_pi/Pico-PIO-USB -hw/mcu/renesas/rx -hw/mcu/silabs/cmsis-dfp-efm32gg12b -hw/mcu/sony/cxd56/spresense-exported-sdk -hw/mcu/st/cmsis_device_f0 -hw/mcu/st/cmsis_device_f1 -hw/mcu/st/cmsis_device_f2 -hw/mcu/st/cmsis_device_f3 -hw/mcu/st/cmsis_device_f4 -hw/mcu/st/cmsis_device_f7 -hw/mcu/st/cmsis_device_g0 -hw/mcu/st/cmsis_device_g4 -hw/mcu/st/cmsis_device_h5 -hw/mcu/st/cmsis_device_h7 -hw/mcu/st/cmsis_device_l0 -hw/mcu/st/cmsis_device_l1 -hw/mcu/st/cmsis_device_l4 -hw/mcu/st/cmsis_device_l5 -hw/mcu/st/cmsis_device_u5 -hw/mcu/st/cmsis_device_wb -hw/mcu/st/stm32f0xx_hal_driver -hw/mcu/st/stm32f1xx_hal_driver -hw/mcu/st/stm32f2xx_hal_driver -hw/mcu/st/stm32f3xx_hal_driver -hw/mcu/st/stm32f4xx_hal_driver -hw/mcu/st/stm32f7xx_hal_driver -hw/mcu/st/stm32g0xx_hal_driver -hw/mcu/st/stm32g4xx_hal_driver -hw/mcu/st/stm32h5xx_hal_driver -hw/mcu/st/stm32h7xx_hal_driver -hw/mcu/st/stm32l0xx_hal_driver -hw/mcu/st/stm32l1xx_hal_driver -hw/mcu/st/stm32l4xx_hal_driver -hw/mcu/st/stm32l5xx_hal_driver -hw/mcu/st/stm32u5xx_hal_driver -hw/mcu/st/stm32wbxx_hal_driver -hw/mcu/ti -hw/mcu/wch/ch32v20x -hw/mcu/wch/ch32v307 -hw/mcu/wch/ch32f20x -lib/CMSIS_5 -lib/FreeRTOS-Kernel -lib/lwip -lib/sct_neopixel -tools/uf2 +.PVS-Studio diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 1055e31d3..e8b46d468 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -3,140 +3,146 @@ - - - - - + + + + + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - + + + + + + + + - - - - - + + + + + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + - - + + + + - - - - - + + + + + + + + + \ No newline at end of file diff --git a/README.rst b/README.rst index 1ae8c5375..2ffe3823a 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -|Build Status| |Documentation Status| |Fuzzing Status| |License| +|Build Status| |CircleCI Status| |Documentation Status| |Fuzzing Status| |License| Sponsors ======== @@ -109,7 +109,9 @@ Following CPUs are supported, check out `Supported Devices`_ for comprehensive l +==============+============================================================+ | Allwinner | F1C100s/F1C200s | +--------------+------------------------------------------------------------+ -| Analog | MAX3421E (usb host shield) | +| Analog | max32: 650, 666, 690. max78002 | +| | | +| | max3421e (host) | +--------------+------------------------------------------------------------+ | Brigetek | FT90x | +--------------+------------------------------------------------------------+ @@ -195,8 +197,10 @@ Docs - `Structure`_ - `Porting`_ -.. |Build Status| image:: https://github.com/hathach/tinyusb/actions/workflows/cmake_arm.yml/badge.svg +.. |Build Status| image:: https://github.com/hathach/tinyusb/actions/workflows/build.yml/badge.svg :target: https://github.com/hathach/tinyusb/actions +.. |CircleCI Status| image:: https://dl.circleci.com/status-badge/img/circleci/4AYHvUhFxdnY4rA7LEsdqW/QmrpoL2AjGqetvFQNqtWyq/tree/master.svg?style=svg + :target: https://dl.circleci.com/status-badge/redirect/circleci/4AYHvUhFxdnY4rA7LEsdqW/QmrpoL2AjGqetvFQNqtWyq/tree/master .. |Documentation Status| image:: https://readthedocs.org/projects/tinyusb/badge/?version=latest :target: https://docs.tinyusb.org/en/latest/?badge=latest .. |Fuzzing Status| image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/tinyusb.svg diff --git a/docs/reference/supported.rst b/docs/reference/supported.rst index edb6b69ca..2bfa1b8d0 100644 --- a/docs/reference/supported.rst +++ b/docs/reference/supported.rst @@ -5,147 +5,142 @@ Supported Devices Supported MCUs ============== -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | -+==============+=======================+========+======+===========+===================+==============+ -| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Brigetek | FT90x | ✔ | | ✔ | ft9xx | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Espressif | ESP32 S2, S3 | ✔ | | ✖ | dwc2 or esp32sx | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Infineon | XMC4500 | ✔ | | ✖ | dwc2 | | -+--------------+-----+-----------------+--------+------+-----------+-------------------+--------------+ -| MicroChip | SAM | D11, D21 | ✔ | | ✖ | samd | | -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | D51, E5x | ✔ | | ✖ | samd | | -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | G55 | ✔ | | ✖ | samg | | -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | L21, L22 | ✔ | | ✖ | samd | | -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | | -| +-----+-----------------+--------+------+-----------+-------------------+--------------+ -| | PIC | 24 | ✔ | | | pic | ci_fs variant| -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant| -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | dsPIC33 | ✔ | | | pic | ci_fs variant| -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | 32mz | ✔ | | | pic32mz | musb variant | -+--------------+-----+-----------------+--------+------+-----------+-------------------+--------------+ -| Mind Montion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant| -+--------------+-----+-----------------+--------+------+-----------+-------------------+--------------+ -| NordicSemi | nRF52833, nRF52840 | ✔ | ✖ | ✖ | nrf5x | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | nRF5340 | ✔ | ✖ | ✖ | nrf5x | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | NUC121/NUC125 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | NUC126 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | NUC505 | ✔ | | ✔ | nuc505 | | -+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+ -| NXP | iMXRT | RT10xx | ✔ | ✔ | ✔ | ci_hs | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | RT11xx | ✔ | ✔ | ✔ | ci_hs | | -| +---------+-------------+--------+------+-----------+-------------------+--------------+ -| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant| -| +---------+-------------+--------+------+-----------+-------------------+--------------+ -| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40 | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | 54 | ✔ | | ✔ | lpc_ip3511 | | -| | +-------------+--------+------+-----------+-------------------+--------------+ -| | | 55 | ✔ | | ✔ | lpc_ip3511 | | -| +---------+-------------+--------+------+-----------+-------------------+--------------+ -| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs | | -+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+ -| Raspberry Pi | RP2040 | ✔ | ✔ | ✖ | rp2040, pio_usb | | -+--------------+-----+-----------------+--------+------+-----------+-------------------+--------------+ -| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | -| +-----+-----------------+--------+------+-----------+-------------------+--------------+ -| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | -| | +-----------------+--------+------+-----------+-------------------+--------------+ -| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | -+--------------+-----+-----------------+--------+------+-----------+-------------------+--------------+ -| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| ST STM32 | F0 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------+--------+------+-----------+-------------------+--------------+ -| | | 105, 107 | ✔ | | ✖ | dwc2 | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | F2 | ✔ | | ✔ | dwc2 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | F3 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | F4 | ✔ | | ✔ | dwc2 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | F7 | ✔ | | ✔ | dwc2 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | G0 | ✔ | | ✖ | stm32_fsdev | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | H5 | ✔ | | ✖ | stm32_fsdev | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | H7 | ✔ | | ✔ | dwc2 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | L0 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | L1 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------+--------+------+-----------+-------------------+--------------+ -| | | 4x5, 4x6 | ✔ | | ✖ | dwc2 | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | L4+ | ✔ | | ✖ | dwc2 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | L5 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | U5 | 535, 545 | ✔ | | ✖ | stm32_fsdev | | -| | +------------------+--------+------+-----------+-------------------+--------------+ -| | | 575, 585 | ✔ | | ✖ | dwc2 | | -| | +------------------+--------+------+-----------+-------------------+--------------+ -| | | 59x,5Ax,5Fx,5Gx | ✔ | | ✔ | dwc2 | | -| +----+------------------+--------+------+-----------+-------------------+--------------+ -| | WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | MSP432E4 | ✔ | | ✖ | musb | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | TM4C123 | ✔ | | ✖ | musb | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| WCH | CH32F20x | ✔ | | ✔ | ch32f205 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | CH32V20x | ✔ | | ✖ | ch32v20x | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | CH32V307 | ✔ | | ✔ | ch32v307 | | -+--------------+-----------------------+--------+------+-----------+-------------------+--------------+ ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | ++==============+=============================+========+======+===========+===================+===================+ +| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | +| | MAX78002 | | | | | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Brigetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Espressif | ESP32 S2, S3 | ✔ | | ✖ | dwc2 or esp32sx | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Infineon | XMC4500 | ✔ | | ✖ | dwc2 | | ++--------------+-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| MicroChip | SAM | D11, D21, L21, L22 | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | D51, E5x | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | G55 | ✔ | | ✖ | samg | 1-dir ep | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | 1-dir ep | +| +-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| | PIC | 24 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | dsPIC33 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | 32mz | ✔ | | | pic32mz | musb variant | ++--------------+-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| Mind Montion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant | ++--------------+-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is ISO | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | NUC121/NUC125 | ✔ | ✖ | ✖ | nuc121 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | NUC126 | ✔ | ✖ | ✖ | nuc121 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | NUC505 | ✔ | | ✔ | nuc505 | | ++--------------+---------+-------------------+--------+------+-----------+-------------------+-------------------+ +| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs | | +| +---------+-------------------+--------+------+-----------+-------------------+-------------------+ +| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | +| | +-------------------+--------+------+-----------+-------------------+-------------------+ +| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant | +| +---------+-------------------+--------+------+-----------+-------------------+-------------------+ +| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+-------------------+-------------------+ +| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40 | | +| | +-------------------+--------+------+-----------+-------------------+-------------------+ +| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs | | +| | +-------------------+--------+------+-----------+-------------------+-------------------+ +| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+-------------------+-------------------+ +| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | +| +---------+-------------------+--------+------+-----------+-------------------+-------------------+ +| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs | | ++--------------+---------+-------------------+--------+------+-----------+-------------------+-------------------+ +| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | | ++--------------+-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | +| +-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | +| | +-----------------------+--------+------+-----------+-------------------+-------------------+ +| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | ++--------------+-----+-----------------------+--------+------+-----------+-------------------+-------------------+ +| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| ST STM32 | F0 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | | +| | +------------------------+--------+------+-----------+-------------------+-------------------+ +| | | 105, 107 | ✔ | | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | F2 | ✔ | | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | F3 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | F4 | ✔ | | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | F7 | ✔ | | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | G0 | ✔ | | ✖ | stm32_fsdev | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | H5 | ✔ | | ✖ | stm32_fsdev | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | H7 | ✔ | | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | L0 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | L1 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | | +| | +------------------------+--------+------+-----------+-------------------+-------------------+ +| | | 4x5, 4x6 | ✔ | | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | L4+ | ✔ | | ✖ | dwc2 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | L5 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | U5 | 535, 545 | ✔ | | ✖ | stm32_fsdev | | +| | +------------------------+--------+------+-----------+-------------------+-------------------+ +| | | 575, 585 | ✔ | | ✖ | dwc2 | | +| | +------------------------+--------+------+-----------+-------------------+-------------------+ +| | | 59x,5Ax,5Fx,5Gx | ✔ | | ✔ | dwc2 | | +| +----+------------------------+--------+------+-----------+-------------------+-------------------+ +| | WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | MSP432E4 | ✔ | | ✖ | musb | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | TM4C123 | ✔ | | ✖ | musb | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ +| WCH | CH32F20x | ✔ | | ✔ | ch32f205 | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | CH32V20x | ✔ | | ✖ | ch32v20x | | +| +-----------------------------+--------+------+-----------+-------------------+-------------------+ +| | CH32V307 | ✔ | | ✔ | ch32v307 | | ++--------------+-----------------------------+--------+------+-----------+-------------------+-------------------+ Table Legend diff --git a/examples/build_system/cmake/cpu/cortex-m33-nodsp.cmake b/examples/build_system/cmake/cpu/cortex-m33-nodsp.cmake new file mode 100644 index 000000000..b3cd743fd --- /dev/null +++ b/examples/build_system/cmake/cpu/cortex-m33-nodsp.cmake @@ -0,0 +1,25 @@ +if (TOOLCHAIN STREQUAL "gcc") + set(TOOLCHAIN_COMMON_FLAGS + -mthumb + -mcpu=cortex-m33+nodsp + -mfloat-abi=hard + -mfpu=fpv5-sp-d16 + ) + set(FREERTOS_PORT GCC_ARM_CM33_NTZ_NONSECURE CACHE INTERNAL "") + +elseif (TOOLCHAIN STREQUAL "clang") + set(TOOLCHAIN_COMMON_FLAGS + --target=arm-none-eabi + -mcpu=cortex-m33+nodsp + -mfpu=fpv5-sp-d16 + ) + set(FREERTOS_PORT GCC_ARM_CM33_NTZ_NONSECURE CACHE INTERNAL "") + +elseif (TOOLCHAIN STREQUAL "iar") + set(TOOLCHAIN_COMMON_FLAGS + --cpu cortex-m33+nodsp + --fpu VFPv5-SP + ) + set(FREERTOS_PORT IAR_ARM_CM33_NTZ_NONSECURE CACHE INTERNAL "") + +endif () diff --git a/examples/build_system/make/rules.mk b/examples/build_system/make/rules.mk index 102c6db0c..86de17b6c 100644 --- a/examples/build_system/make/rules.mk +++ b/examples/build_system/make/rules.mk @@ -145,6 +145,12 @@ OPENOCD_WCH_OPTION ?= flash-openocd-wch: $(BUILD)/$(PROJECT).elf $(OPENOCD_WCH) $(OPENOCD_WCH_OPTION) -c init -c halt -c "flash write_image $<" -c reset -c exit +# --------------- wlink-rs ----------------- +# flash with https://github.com/ch32-rs/wlink +WLINK_RS ?= wlink +flash-wlink-rs: $(BUILD)/$(PROJECT).elf + $(WLINK_RS) flash $< + # --------------- dfu-util ----------------- DFU_UTIL_OPTION ?= -a 0 flash-dfu-util: $(BUILD)/$(PROJECT).bin @@ -160,6 +166,11 @@ flash-bmp: $(BUILD)/$(PROJECT).elf debug-bmp: $(BUILD)/$(PROJECT).elf $(GDB) -ex 'target extended-remote $(BMP)' -ex 'monitor swdp_scan' -ex 'attach 1' $< +# --------------- TI Uniflash ----------------- +DSLITE ?= dslite.sh +flash-uniflash: $(BUILD)/$(PROJECT).hex + ${DSLITE} ${UNIFLASH_OPTION} -f $< + #-------------- Artifacts -------------- # Create binary directory diff --git a/examples/device/audio_4_channel_mic_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/audio_4_channel_mic_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h index 6cc7a6577..869500ad2 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h +++ b/examples/device/audio_4_channel_mic_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h @@ -67,6 +67,7 @@ #define configENABLE_FPU 1 #define configENABLE_TRUSTZONE 0 #define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) +#define configRUN_FREERTOS_SECURE_ONLY 1 #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 diff --git a/examples/device/audio_test_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/audio_test_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h index 6cc7a6577..869500ad2 100644 --- a/examples/device/audio_test_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h +++ b/examples/device/audio_test_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h @@ -67,6 +67,7 @@ #define configENABLE_FPU 1 #define configENABLE_TRUSTZONE 0 #define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) +#define configRUN_FREERTOS_SECURE_ONLY 1 #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c index 1167a5d50..ef12186f2 100644 --- a/examples/device/cdc_dual_ports/src/main.c +++ b/examples/device/cdc_dual_ports/src/main.c @@ -119,6 +119,26 @@ static void cdc_task(void) { } } +// Invoked when cdc when line state changed e.g connected/disconnected +// Use to reset to DFU when disconnect with 1200 bps +void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) { + (void)rts; + + // DTR = false is counted as disconnected + if (!dtr) { + // touch1200 only with first CDC instance (Serial) + if (instance == 0) { + cdc_line_coding_t coding; + tud_cdc_get_line_coding(&coding); + if (coding.bit_rate == 1200) { + if (board_reset_to_bootloader) { + board_reset_to_bootloader(); + } + } + } + } +} + //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index de2505c07..7776eb958 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -98,19 +98,19 @@ enum #define EPNUM_CDC_1_OUT 0x05 #define EPNUM_CDC_1_IN 0x85 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_CDC_0_NOTIF 0x81 +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_CDC_0_NOTIF 0x83 #define EPNUM_CDC_0_OUT 0x02 - #define EPNUM_CDC_0_IN 0x83 + #define EPNUM_CDC_0_IN 0x81 - #define EPNUM_CDC_1_NOTIF 0x84 + #define EPNUM_CDC_1_NOTIF 0x86 #define EPNUM_CDC_1_OUT 0x05 - #define EPNUM_CDC_1_IN 0x86 + #define EPNUM_CDC_1_IN 0x84 -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_0_NOTIF 0x81 #define EPNUM_CDC_0_OUT 0x02 diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c index 2afa24903..4b6b88041 100644 --- a/examples/device/cdc_msc/src/usb_descriptors.c +++ b/examples/device/cdc_msc/src/usb_descriptors.c @@ -93,19 +93,7 @@ enum { #define EPNUM_MSC_OUT 0x05 #define EPNUM_MSC_IN 0x85 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x83 - - #define EPNUM_MSC_OUT 0x04 - #define EPNUM_MSC_IN 0x85 - #elif CFG_TUSB_MCU == OPT_MCU_CXD56 - // CXD56 doesn't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) #define EPNUM_CDC_NOTIF 0x83 @@ -115,8 +103,8 @@ enum { #define EPNUM_MSC_OUT 0x05 #define EPNUM_MSC_IN 0x84 -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 #define EPNUM_CDC_OUT 0x02 diff --git a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h index 6cc7a6577..869500ad2 100644 --- a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h +++ b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h @@ -67,6 +67,7 @@ #define configENABLE_FPU 1 #define configENABLE_TRUSTZONE 0 #define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) +#define configRUN_FREERTOS_SECURE_ONLY 1 #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index c8a04bb74..d2f8628f1 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,6 +28,9 @@ #if CFG_TUD_MSC +// whether host does safe-eject +static bool ejected = false; + // Some MCU doesn't have enough 8KB SRAM to store the whole disk // We will use Flash as read-only disk with board that has // CFG_EXAMPLE_MSC_READONLY defined @@ -137,7 +140,14 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { (void) lun; - return true; // RAM disk is always ready + // RAM disk is ready until ejected + if (ejected) { + // Additional Sense 3A-00 is NOT_FOUND + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); + return false; + } + + return true; } // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size @@ -166,6 +176,7 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo }else { // unload disk storage + ejected = true; } } @@ -187,6 +198,17 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff return (int32_t) bufsize; } +bool tud_msc_is_writable_cb (uint8_t lun) +{ + (void) lun; + +#ifdef CFG_EXAMPLE_MSC_READONLY + return false; +#else + return true; +#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) diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c index 9c29701c7..405a57fe4 100644 --- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c +++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c @@ -42,8 +42,7 @@ //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = -{ +tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, @@ -69,8 +68,7 @@ tusb_desc_device_t const desc_device = // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ +uint8_t const *tud_descriptor_device_cb(void) { return (uint8_t const *) &desc_device; } @@ -78,8 +76,7 @@ uint8_t const * tud_descriptor_device_cb(void) // Configuration Descriptor //--------------------------------------------------------------------+ -enum -{ +enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, ITF_NUM_MSC, @@ -96,8 +93,18 @@ enum #define EPNUM_MSC_OUT 0x05 #define EPNUM_MSC_IN 0x85 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG - // SAMG doesn't support a same endpoint number with different direction IN and OUT +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_CDC_NOTIF 0x83 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x81 + + #define EPNUM_MSC_OUT 0x05 + #define EPNUM_MSC_IN 0x84 + +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 #define EPNUM_CDC_OUT 0x02 diff --git a/examples/device/cdc_uac2/src/uac2_app.c b/examples/device/cdc_uac2/src/uac2_app.c index c57d98a1a..70b0949a9 100644 --- a/examples/device/cdc_uac2/src/uac2_app.c +++ b/examples/device/cdc_uac2/src/uac2_app.c @@ -141,7 +141,7 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1)); } - else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { if (request->bRequest == AUDIO_CS_REQ_RANGE) { diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c index 72a695622..9f7255d8a 100644 --- a/examples/device/cdc_uac2/src/usb_descriptors.c +++ b/examples/device/cdc_uac2/src/usb_descriptors.c @@ -97,18 +97,8 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_CDC_OUT 0x02 #define EPNUM_CDC_IN 0x82 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_AUDIO_IN 0x01 - #define EPNUM_AUDIO_OUT 0x02 - - #define EPNUM_CDC_NOTIF 0x83 - #define EPNUM_CDC_OUT 0x04 - #define EPNUM_CDC_IN 0x85 - -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 #define EPNUM_AUDIO_OUT 0x02 diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c index 7f35b4b22..0a2049288 100644 --- a/examples/device/dynamic_configuration/src/usb_descriptors.c +++ b/examples/device/dynamic_configuration/src/usb_descriptors.c @@ -132,21 +132,8 @@ enum #define EPNUM_1_MSC_OUT 0x02 #define EPNUM_1_MSC_IN 0x82 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG - // SAMG doesn't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_0_CDC_NOTIF 0x81 - #define EPNUM_0_CDC_OUT 0x02 - #define EPNUM_0_CDC_IN 0x83 - - #define EPNUM_0_MIDI_OUT 0x04 - #define EPNUM_0_MIDI_IN 0x85 - - #define EPNUM_1_MSC_OUT 0x01 - #define EPNUM_1_MSC_IN 0x82 - -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_0_CDC_NOTIF 0x81 #define EPNUM_0_CDC_OUT 0x02 diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c index 7ad5c53c2..c2aef502d 100644 --- a/examples/device/hid_boot_interface/src/main.c +++ b/examples/device/hid_boot_interface/src/main.c @@ -161,8 +161,8 @@ void hid_task(void) { uint8_t const report_id = 0; uint8_t const button_mask = 0; - uint8_t const vertical = 0; - uint8_t const horizontal = 0; + int8_t const vertical = 0; + int8_t const horizontal = 0; int8_t const delta = 5; tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, vertical, horizontal); diff --git a/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h index 6cc7a6577..869500ad2 100644 --- a/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h +++ b/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h @@ -67,6 +67,7 @@ #define configENABLE_FPU 1 #define configENABLE_TRUSTZONE 0 #define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) +#define configRUN_FREERTOS_SECURE_ONLY 1 #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 diff --git a/examples/device/midi_test/src/usb_descriptors.c b/examples/device/midi_test/src/usb_descriptors.c index 9781d3d6f..3870eaaf0 100644 --- a/examples/device/midi_test/src/usb_descriptors.c +++ b/examples/device/midi_test/src/usb_descriptors.c @@ -84,15 +84,24 @@ enum #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - #define EPNUM_MIDI_OUT 0x02 - #define EPNUM_MIDI_IN 0x02 -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // On Bridgetek FT9xx endpoint numbers must be unique... - #define EPNUM_MIDI_OUT 0x02 - #define EPNUM_MIDI_IN 0x03 + #define EPNUM_MIDI_OUT 0x02 + #define EPNUM_MIDI_IN 0x82 + +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_MIDI_OUT 0x02 + #define EPNUM_MIDI_IN 0x81 + +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h + // e.g EP1 OUT & EP1 IN cannot exist together + #define EPNUM_MIDI_OUT 0x01 + #define EPNUM_MIDI_IN 0x82 + #else - #define EPNUM_MIDI_OUT 0x01 - #define EPNUM_MIDI_IN 0x01 + #define EPNUM_MIDI_OUT 0x01 + #define EPNUM_MIDI_IN 0x81 #endif uint8_t const desc_fs_configuration[] = diff --git a/examples/device/msc_dual_lun/src/usb_descriptors.c b/examples/device/msc_dual_lun/src/usb_descriptors.c index c0610945f..efb9a966d 100644 --- a/examples/device/msc_dual_lun/src/usb_descriptors.c +++ b/examples/device/msc_dual_lun/src/usb_descriptors.c @@ -85,17 +85,17 @@ enum #define EPNUM_MSC_OUT 0x02 #define EPNUM_MSC_IN 0x82 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG - // SAMG doesn't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_MSC_OUT 0x01 - #define EPNUM_MSC_IN 0x82 +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_MSC_OUT 0x02 + #define EPNUM_MSC_IN 0x81 -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_MSC_OUT 0x01 - #define EPNUM_MSC_IN 0x82 + #define EPNUM_MSC_OUT 0x01 + #define EPNUM_MSC_IN 0x82 #else #define EPNUM_MSC_OUT 0x01 diff --git a/examples/device/net_lwip_webserver/CMakeLists.txt b/examples/device/net_lwip_webserver/CMakeLists.txt index c39fd32c5..13923b583 100644 --- a/examples/device/net_lwip_webserver/CMakeLists.txt +++ b/examples/device/net_lwip_webserver/CMakeLists.txt @@ -5,7 +5,14 @@ include(${CMAKE_CURRENT_LIST_DIR}/../../../hw/bsp/family_support.cmake) # gets PROJECT name for the example (e.g. -) family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) +# Prefer the tinyusb lwip set(LWIP ${TOP}/lib/lwip) + +# If we can't find one from tinyusb then check cmake var before giving up +if (NOT EXISTS ${LWIP}/src) + set(LWIP ${TINYUSB_LWIP_PATH}) +endif() + if (NOT EXISTS ${LWIP}/src) family_example_missing_dependency(${PROJECT} "lib/lwip") return() diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index d3e094517..22082fc81 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -91,6 +91,8 @@ extern "C" { #define USE_ECM 1 #elif TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F1) #define USE_ECM 1 +#elif TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002) + #define USE_ECM 1 #else #define USE_ECM 0 #define INCLUDE_IPERF diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index da628c8be..d061f5076 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -113,8 +113,15 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_NET_OUT 0x02 #define EPNUM_NET_IN 0x82 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_NET_NOTIF 0x83 + #define EPNUM_NET_OUT 0x02 + #define EPNUM_NET_IN 0x81 + +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_NET_NOTIF 0x81 #define EPNUM_NET_OUT 0x02 diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index 0ea6e7025..c285211b8 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -229,7 +229,7 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1)); } - else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { if (request->bRequest == AUDIO_CS_REQ_RANGE) { diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index ff4dc2acc..bc9160d5e 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -84,21 +84,21 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO_OUT 0x03 #define EPNUM_AUDIO_INT 0x01 +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + // #define EPNUM_AUDIO_IN 0x01 + // #define EPNUM_AUDIO_OUT 0x02 + // #define EPNUM_AUDIO_INT 0x03 + #elif CFG_TUSB_MCU == OPT_MCU_NRF5X // ISO endpoints for NRF5x are fixed to 0x08 (0x88) #define EPNUM_AUDIO_IN 0x08 #define EPNUM_AUDIO_OUT 0x08 #define EPNUM_AUDIO_INT 0x01 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_AUDIO_IN 0x01 - #define EPNUM_AUDIO_OUT 0x02 - #define EPNUM_AUDIO_INT 0x03 - -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 #define EPNUM_AUDIO_OUT 0x02 diff --git a/examples/device/uac2_speaker_fb/CMakeLists.txt b/examples/device/uac2_speaker_fb/CMakeLists.txt new file mode 100644 index 000000000..e92a57148 --- /dev/null +++ b/examples/device/uac2_speaker_fb/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.17) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + +project(${PROJECT} C CXX ASM) + +# Checks this example is valid for the family and initializes the project +family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) + +# Espressif has its own cmake build system +if(FAMILY STREQUAL "espressif") + return() +endif() + +add_executable(${PROJECT}) + +# Example source +target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c + ) + +# Example include +target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +# Configure compilation flags and libraries for the example without RTOS. +# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. +family_configure_device_example(${PROJECT} noos) diff --git a/examples/device/uac2_speaker_fb/Makefile b/examples/device/uac2_speaker_fb/Makefile new file mode 100644 index 000000000..7fa475da5 --- /dev/null +++ b/examples/device/uac2_speaker_fb/Makefile @@ -0,0 +1,11 @@ +include ../../build_system/make/make.mk + +INC += \ + src \ + $(TOP)/hw \ + +# Example source +EXAMPLE_SOURCE += $(wildcard src/*.c) +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) + +include ../../build_system/make/rules.mk diff --git a/examples/device/uac2_speaker_fb/skip.txt b/examples/device/uac2_speaker_fb/skip.txt new file mode 100644 index 000000000..234f1ebed --- /dev/null +++ b/examples/device/uac2_speaker_fb/skip.txt @@ -0,0 +1,8 @@ +mcu:LPC11UXX +mcu:LPC13XX +mcu:NUC121 +mcu:SAMD11 +mcu:SAME5X +mcu:SAMG +board:stm32l052dap52 +family:broadcom_64bit diff --git a/examples/device/uac2_speaker_fb/src/audio_debug.py b/examples/device/uac2_speaker_fb/src/audio_debug.py new file mode 100644 index 000000000..336c46c01 --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/audio_debug.py @@ -0,0 +1,69 @@ +# Install python3 HID package https://pypi.org/project/hid/ +# Install python3 matplotlib package https://pypi.org/project/matplotlib/ + +from ctypes import * +try: + import hid + import matplotlib.pyplot as plt + import matplotlib.animation as animation +except: + print("Missing import, please try 'pip install hid matplotlib' or consult your OS's python package manager.") + +# Example must be compiled with CFG_AUDIO_DEBUG=1 +VID = 0xcafe +PID = 0x4014 + +CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX = 2 + +class audio_debug_info_t (Structure): + _fields_ = [("sample_rate", c_uint32), + ("alt_settings", c_uint8), + ("mute", (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1) * c_int8), + ("volume", (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1) * c_int16), + ("fifo_size", c_uint16), + ("fifo_count", c_uint16), + ("fifo_count_avg", c_uint16) + ] + +dev = hid.Device(VID, PID) + +if dev: + # Create figure for plotting + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1) + fifo_avg = [] + fifo_cnt = [] + # This function is called periodically from FuncAnimation + def animate(i): + info = None + for i in range(30): + try: + str_in = dev.read(64, 50) + info = audio_debug_info_t.from_buffer_copy(str_in) + + global fifo_avg + global fifo_cnt + fifo_avg.append(info.fifo_count_avg) + fifo_cnt.append(info.fifo_count) + except: + exit(1) + # Limit to 1000 items + fifo_avg = fifo_avg[-1000:] + fifo_cnt = fifo_cnt[-1000:] + + if info is not None: + # Draw x and y lists + ax.clear() + ax.plot(fifo_cnt, label='FIFO count') + ax.plot(fifo_avg, label='FIFO average') + ax.legend() + ax.set_ylim(bottom=0, top=info.fifo_size) + + # Format plot + plt.title('FIFO information') + plt.grid() + + print(f'Sample rate:{info.sample_rate} | Alt settings:{info.alt_settings} | Volume:{info.volume[:]}') + + ani = animation.FuncAnimation(fig, animate, interval=10) + plt.show() diff --git a/src/portable/mentor/musb/musb_msp432e.h b/examples/device/uac2_speaker_fb/src/common_types.h similarity index 69% rename from src/portable/mentor/musb/musb_msp432e.h rename to examples/device/uac2_speaker_fb/src/common_types.h index fce21de88..174e26671 100644 --- a/src/portable/mentor/musb/musb_msp432e.h +++ b/examples/device/uac2_speaker_fb/src/common_types.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2021, Ha Thach (tinyusb.org) + * Copyright (c) 2023 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,20 +21,32 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * - * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MUSB_MSP432E_H_ -#define _TUSB_MUSB_MSP432E_H_ +#ifndef _COMMON_TYPES_H_ +#define _COMMON_TYPES_H_ -#ifdef __cplusplus - extern "C" { +enum +{ + ITF_NUM_AUDIO_CONTROL = 0, + ITF_NUM_AUDIO_STREAMING, +#if CFG_AUDIO_DEBUG + ITF_NUM_DEBUG, #endif + ITF_NUM_TOTAL +}; -#include "msp.h" - -#ifdef __cplusplus - } +#if CFG_AUDIO_DEBUG +typedef struct + { + uint32_t sample_rate; + uint8_t alt_settings; + int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; + int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; + uint16_t fifo_size; + uint16_t fifo_count; + uint16_t fifo_count_avg; + } audio_debug_info_t; #endif #endif diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c new file mode 100644 index 000000000..0a8529a61 --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/main.c @@ -0,0 +1,505 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Jerzy Kasenberg + * + * 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. + * + */ + +#include +#include + +#include "bsp/board_api.h" +#include "tusb.h" +#include "usb_descriptors.h" +#include "common_types.h" + +#ifdef CFG_QUIRK_OS_GUESSING +#include "quirk_os_guessing.h" +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTOTYPES +//--------------------------------------------------------------------+ + +// List of supported sample rates +#if defined(__RX__) + const uint32_t sample_rates[] = {44100, 48000}; +#else + const uint32_t sample_rates[] = {44100, 48000, 88200, 96000}; +#endif + +uint32_t current_sample_rate = 44100; + +#define N_SAMPLE_RATES TU_ARRAY_SIZE(sample_rates) + +/* Blink pattern + * - 25 ms : streaming data + * - 250 ms : device not mounted + * - 1000 ms : device mounted + * - 2500 ms : device is suspended + */ +enum +{ + BLINK_STREAMING = 25, + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +enum +{ + VOLUME_CTRL_0_DB = 0, + VOLUME_CTRL_10_DB = 2560, + VOLUME_CTRL_20_DB = 5120, + VOLUME_CTRL_30_DB = 7680, + VOLUME_CTRL_40_DB = 10240, + VOLUME_CTRL_50_DB = 12800, + VOLUME_CTRL_60_DB = 15360, + VOLUME_CTRL_70_DB = 17920, + VOLUME_CTRL_80_DB = 20480, + VOLUME_CTRL_90_DB = 23040, + VOLUME_CTRL_100_DB = 25600, + VOLUME_CTRL_SILENCE = 0x8000, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + +// Audio controls +// Current states +int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 +int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 + +// Buffer for speaker data +uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ/2]; + +void led_blinking_task(void); +void audio_task(void); + +#if CFG_AUDIO_DEBUG +void audio_debug_task(void); +uint8_t current_alt_settings; +uint16_t fifo_count; +uint32_t fifo_count_avg; +#endif + +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + + // init device stack on configured roothub port + tud_init(BOARD_TUD_RHPORT); + + if (board_init_after_tusb) { + board_init_after_tusb(); + } + + TU_LOG1("Speaker running\r\n"); + + while (1) + { + tud_task(); // TinyUSB device task + led_blinking_task(); +#if CFG_AUDIO_DEBUG + audio_debug_task(); +#endif + audio_task(); + } +} + +//--------------------------------------------------------------------+ +// Device callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void)remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; +} + +//--------------------------------------------------------------------+ +// Application Callback API Implementations +//--------------------------------------------------------------------+ + +// Helper for clock get requests +static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request) +{ + TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); + + if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) + { + if (request->bRequest == AUDIO_CS_REQ_CUR) + { + TU_LOG1("Clock get current freq %lu\r\n", current_sample_rate); + + audio_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf)); + } + else if (request->bRequest == AUDIO_CS_REQ_RANGE) + { + audio_control_range_4_n_t(N_SAMPLE_RATES) rangef = + { + .wNumSubRanges = tu_htole16(N_SAMPLE_RATES) + }; + TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES); + for(uint8_t i = 0; i < N_SAMPLE_RATES; i++) + { + rangef.subrange[i].bMin = (int32_t) sample_rates[i]; + rangef.subrange[i].bMax = (int32_t) sample_rates[i]; + rangef.subrange[i].bRes = 0; + TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes); + } + + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef)); + } + } + else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && + request->bRequest == AUDIO_CS_REQ_CUR) + { + audio_control_cur_1_t cur_valid = { .bCur = 1 }; + TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur); + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_valid, sizeof(cur_valid)); + } + TU_LOG1("Clock get request not supported, entity = %u, selector = %u, request = %u\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + return false; +} + +// Helper for clock set requests +static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) +{ + (void)rhport; + + TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); + TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + + if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) + { + TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t)); + + current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *)buf)->bCur; + + TU_LOG1("Clock set current freq: %ld\r\n", current_sample_rate); + + return true; + } + else + { + TU_LOG1("Clock set request not supported, entity = %u, selector = %u, request = %u\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + return false; + } +} + +// Helper for feature unit get requests +static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request) +{ + TU_ASSERT(request->bEntityID == UAC2_ENTITY_FEATURE_UNIT); + + if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR) + { + audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] }; + TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1)); + } + else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + { + if (request->bRequest == AUDIO_CS_REQ_RANGE) + { + audio_control_range_2_n_t(1) range_vol = { + .wNumSubRanges = tu_htole16(1), + .subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) } + }; + TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber, + range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256); + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &range_vol, sizeof(range_vol)); + } + else if (request->bRequest == AUDIO_CS_REQ_CUR) + { + audio_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) }; + TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256); + return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_vol, sizeof(cur_vol)); + } + } + TU_LOG1("Feature unit get request not supported, entity = %u, selector = %u, request = %u\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + + return false; +} + +// Helper for feature unit set requests +static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) +{ + (void)rhport; + + TU_ASSERT(request->bEntityID == UAC2_ENTITY_FEATURE_UNIT); + TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + + if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) + { + TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t)); + + mute[request->bChannelNumber] = ((audio_control_cur_1_t const *)buf)->bCur; + + TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]); + + return true; + } + else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + { + TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t)); + + volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur; + + TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256); + + return true; + } + else + { + TU_LOG1("Feature unit set request not supported, entity = %u, selector = %u, request = %u\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + return false; + } +} + +// Invoked when audio class specific get request received for an entity +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) +{ + audio_control_request_t const *request = (audio_control_request_t const *)p_request; + + if (request->bEntityID == UAC2_ENTITY_CLOCK) + return tud_audio_clock_get_request(rhport, request); + if (request->bEntityID == UAC2_ENTITY_FEATURE_UNIT) + return tud_audio_feature_unit_get_request(rhport, request); + else + { + TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + } + return false; +} + +// Invoked when audio class specific set request received for an entity +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) +{ + audio_control_request_t const *request = (audio_control_request_t const *)p_request; + + if (request->bEntityID == UAC2_ENTITY_FEATURE_UNIT) + return tud_audio_feature_unit_set_request(rhport, request, buf); + if (request->bEntityID == UAC2_ENTITY_CLOCK) + return tud_audio_clock_set_request(rhport, request, buf); + TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n", + request->bEntityID, request->bControlSelector, request->bRequest); + + return false; +} + +bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void)rhport; + + uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); + uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); + + if (ITF_NUM_AUDIO_STREAMING == itf && alt == 0) + blink_interval_ms = BLINK_MOUNTED; + + return true; +} + +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void)rhport; + uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); + uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); + + TU_LOG2("Set interface %d alt %d\r\n", itf, alt); + if (ITF_NUM_AUDIO_STREAMING == itf && alt != 0) + blink_interval_ms = BLINK_STREAMING; + +#if CFG_AUDIO_DEBUG + current_alt_settings = alt; +#endif + + return true; +} + +void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) +{ + (void)func_id; + (void)alt_itf; + // Set feedback method to fifo counting + feedback_param->method = AUDIO_FEEDBACK_METHOD_FIFO_COUNT; + feedback_param->sample_freq = current_sample_rate; +} + +#if CFG_AUDIO_DEBUG +bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) +{ + (void)rhport; + (void)n_bytes_received; + (void)func_id; + (void)ep_out; + (void)cur_alt_setting; + + fifo_count = tud_audio_available(); + // Same averaging method used in UAC2 class + fifo_count_avg = (uint32_t)(((uint64_t)fifo_count_avg * 63 + ((uint32_t)fifo_count << 16)) >> 6); + + return true; +} +#endif + +#if CFG_QUIRK_OS_GUESSING +bool tud_audio_feedback_format_correction_cb(uint8_t func_id) +{ + (void)func_id; + if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) { + return true; + } else { + return false; + } +} +#endif +//--------------------------------------------------------------------+ +// AUDIO Task +//--------------------------------------------------------------------+ + +void audio_task(void) +{ + // Replace audio_task() with your I2S transmit callback. + // Here we simulate a callback called every 1ms. + static uint32_t start_ms = 0; + uint32_t curr_ms = board_millis(); + if ( start_ms == curr_ms ) return; // not enough time + start_ms = curr_ms; + + uint16_t length = current_sample_rate/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + + if (current_sample_rate == 44100 && (curr_ms % 10 == 0)) + { + // Take one more sample every 10 cycles, to have a average reading speed of 44.1 + // This correction is not needed in real world cases + length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + } else + if (current_sample_rate == 88200 && (curr_ms % 5 == 0)) + { + // Take one more sample every 5 cycles, to have a average reading speed of 88.2 + // This correction is not needed in real world cases + length += CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX; + } + + tud_audio_read(i2s_dummy_buffer, length); +} + +//--------------------------------------------------------------------+ +// BLINKING TASK +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if (board_millis() - start_ms < blink_interval_ms) return; + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; +} + +#if CFG_AUDIO_DEBUG +//--------------------------------------------------------------------+ +// HID interface for audio debug +//--------------------------------------------------------------------+ +// Every 1ms, we will sent 1 debug information report +void audio_debug_task(void) +{ + static uint32_t start_ms = 0; + uint32_t curr_ms = board_millis(); + if ( start_ms == curr_ms ) return; // not enough time + start_ms = curr_ms; + + audio_debug_info_t debug_info; + debug_info.sample_rate = current_sample_rate; + debug_info.alt_settings = current_alt_settings; + debug_info.fifo_size = CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ; + debug_info.fifo_count = fifo_count; + debug_info.fifo_count_avg = fifo_count_avg >> 16; + for (int i = 0; i < CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1; i++) + { + debug_info.mute[i] = mute[i]; + debug_info.volume[i] = volume[i]; + } + + if(tud_hid_ready()) + tud_hid_report(0, &debug_info, sizeof(debug_info)); +} + +// Invoked when received GET_REPORT control request +// Unused here +uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) itf; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// Unused here +void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // This example doesn't use multiple report and report ID + (void) itf; + (void) report_id; + (void) report_type; + (void) buffer; + (void) bufsize; +} + +#endif diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c new file mode 100644 index 000000000..965bbd6cf --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 HiFiPhile + * + * 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. + * + */ + +#include "quirk_os_guessing.h" + +static tusb_desc_type_t desc_req_buf[2]; +static int desc_req_idx = 0; + +// Place at the start of tud_descriptor_device_cb() +void quirk_os_guessing_desc_device_cb() { + desc_req_idx = 0; +} + +// Place at the start of tud_descriptor_configuration_cb() +void quirk_os_guessing_desc_configuration_cb() { + // Skip redundant request + if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) { + desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION; + } +} + +// Place at the start of tud_descriptor_bos_cb() +void quirk_os_guessing_desc_bos_cb() { + // Skip redundant request + if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) { + desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS; + } +} + +// Place at the start of tud_descriptor_string_cb() +void quirk_os_guessing_desc_string_cb() { + // Skip redundant request + if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) { + desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING; + } +} + +// Each OS request descriptors differently: +// Windows 10 - 11 +// Device Desc +// Config Desc +// BOS Desc +// String Desc +// Linux 3.16 - 6.8 +// Device Desc +// BOS Desc +// Config Desc +// String Desc +// OS X Ventura - Sonoma +// Device Desc +// String Desc +// Config Desc || BOS Desc +// BOS Desc || Config Desc +quirk_os_guessing_t quirk_os_guessing_get(void) { + if (desc_req_idx < 2) { + return QUIRK_OS_GUESSING_UNKNOWN; + } + + if (desc_req_buf[0] == TUSB_DESC_BOS && desc_req_buf[1] == TUSB_DESC_CONFIGURATION) { + return QUIRK_OS_GUESSING_LINUX; + } else if (desc_req_buf[0] == TUSB_DESC_CONFIGURATION && desc_req_buf[1] == TUSB_DESC_BOS) { + return QUIRK_OS_GUESSING_WINDOWS; + } else if (desc_req_buf[0] == TUSB_DESC_STRING && (desc_req_buf[1] == TUSB_DESC_BOS || desc_req_buf[1] == TUSB_DESC_CONFIGURATION)) { + return QUIRK_OS_GUESSING_OSX; + } + + return QUIRK_OS_GUESSING_UNKNOWN; +} diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h new file mode 100644 index 000000000..1120355c9 --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 HiFiPhile + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _QUIRK_OS_GUESSING_H_ +#define _QUIRK_OS_GUESSING_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "tusb.h" + +//================================== !!! WARNING !!! ==================================== +// This quirk operate out of USB specification in order to workaround specific issues. +// It may not work on your platform. +//======================================================================================= +// +// Prerequisites: +// - Set USB version to at least 2.01 in Device Descriptor +// - Has a valid BOS Descriptor, refer to webusb_serial example +// +// Attention: +// Windows detection result comes out after Configuration Descriptor request, +// meaning it will be too late to do descriptor adjustment. It's advised to make +// Windows as default configuration and adjust to other OS accordingly. + +typedef enum { + QUIRK_OS_GUESSING_UNKNOWN, + QUIRK_OS_GUESSING_LINUX, + QUIRK_OS_GUESSING_OSX, + QUIRK_OS_GUESSING_WINDOWS, +} quirk_os_guessing_t; + +// Get Host OS type +quirk_os_guessing_t quirk_os_guessing_get(void); + +// Place at the start of tud_descriptor_device_cb() +void quirk_os_guessing_desc_device_cb(void); + +// Place at the start of tud_descriptor_configuration_cb() +void quirk_os_guessing_desc_configuration_cb(void); + +// Place at the start of tud_descriptor_bos_cb() +void quirk_os_guessing_desc_bos_cb(void); + +// Place at the start of tud_descriptor_string_cb() +void quirk_os_guessing_desc_string_cb(void); + +#ifdef __cplusplus + } +#endif + +#endif /* _QUIRK_OS_GUESSING_H_ */ diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h new file mode 100644 index 000000000..fd4925c7f --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/tusb_config.h @@ -0,0 +1,168 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Jerzy Kasenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "usb_descriptors.h" + +//--------------------------------------------------------------------+ +// Board Specific Configuration +//--------------------------------------------------------------------+ + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif + +// RHPort max operational speed can defined by board.mk +#ifndef BOARD_TUD_MAX_SPEED +#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED +#endif + +//-------------------------------------------------------------------- +// Common Configuration +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// It's recommended to disable debug unless for control requests debugging, +// as the extra time needed will impact data stream ! +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +// Enable Device stack +#define CFG_TUD_ENABLED 1 + +// Default is max speed that hardware controller could support with on-chip PHY +#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +/* (Needed for Full-Speed only) + * Enable host OS guessing to workaround UAC2 compatibility issues between Windows and OS X + * The default configuration only support Windows and Linux, enable this option for OS X + * support. Otherwise if you don't need Windows support you can make OS X's configuration as + * default. + */ +#define CFG_QUIRK_OS_GUESSING 1 + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +// Expose audio class debug information via HID interface +#ifndef CFG_AUDIO_DEBUG +#define CFG_AUDIO_DEBUG 1 +#endif + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +#define CFG_TUD_HID_EP_BUFSIZE 64 + +//------------- CLASS -------------// +#define CFG_TUD_AUDIO 1 + +#if CFG_AUDIO_DEBUG +#define CFG_TUD_HID 1 +#else +#define CFG_TUD_HID 0 +#endif + +#define CFG_TUD_CDC 0 +#define CFG_TUD_MSC 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 + +//-------------------------------------------------------------------- +// AUDIO CLASS DRIVER CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN + +// Enable if Full-Speed on OSX, also set feedback EP size to 3 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 + +// Audio format type I specifications +#if defined(__RX__) +#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000 +#else +#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000 +#endif + +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2 + +// 16bit in 16bit slots +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2 +#define CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX 16 + +// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 + +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device + +// Enable feedback EP +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 + +// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 + +// Size of control request buffer +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.c b/examples/device/uac2_speaker_fb/src/usb_descriptors.c new file mode 100644 index 000000000..ee1b92225 --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.c @@ -0,0 +1,288 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 HiFiPhile + * + * 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. + * + */ + +#include "bsp/board_api.h" +#include "tusb.h" +#include "usb_descriptors.h" +#include "common_types.h" + +#ifdef CFG_QUIRK_OS_GUESSING +#include "quirk_os_guessing.h" +#endif + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) ) + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0201, + + // Use Interface Association Descriptor (IAD) for Audio + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ +#if CFG_QUIRK_OS_GUESSING + quirk_os_guessing_desc_device_cb(); +#endif + return (uint8_t const *)&desc_device; +} + +#if CFG_AUDIO_DEBUG +//--------------------------------------------------------------------+ +// HID Report Descriptor +//--------------------------------------------------------------------+ + +uint8_t const desc_hid_report[] = +{ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ + HID_USAGE ( 0x01 ),\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ + HID_USAGE ( 0x02 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX_N ( 0xff, 2 ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( sizeof(audio_debug_info_t) ),\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + HID_COLLECTION_END +}; + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) +{ + (void) itf; + return desc_hid_report; +} +#endif + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ + +#if CFG_AUDIO_DEBUG + #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN + TUD_HID_DESC_LEN) +#else + #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN) +#endif + +#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX + // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number + // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... + #define EPNUM_AUDIO_FB 0x03 + #define EPNUM_AUDIO_OUT 0x03 + #define EPNUM_DEBUG 0x04 + +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X + // ISO endpoints for NRF5x are fixed to 0x08 (0x88) + #define EPNUM_AUDIO_FB 0x08 + #define EPNUM_AUDIO_OUT 0x08 + #define EPNUM_DEBUG 0x01 + +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h + // e.g EP1 OUT & EP1 IN cannot exist together + #define EPNUM_AUDIO_FB 0x01 + #define EPNUM_AUDIO_OUT 0x02 + #define EPNUM_DEBUG 0x03 + +#else + #define EPNUM_AUDIO_FB 0x01 + #define EPNUM_AUDIO_OUT 0x01 + #define EPNUM_DEBUG 0x02 +#endif + +uint8_t const desc_configuration_default[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size, + TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 4), + +#if CFG_AUDIO_DEBUG + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) +#endif +}; + +#if CFG_QUIRK_OS_GUESSING +// OS X needs 3 bytes feedback endpoint on FS +uint8_t const desc_configuration_osx_fs[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size, + TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 3), + +#if CFG_AUDIO_DEBUG + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) +#endif +}; +#endif + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void)index; // for multiple configurations + +#if CFG_QUIRK_OS_GUESSING + quirk_os_guessing_desc_configuration_cb(); + if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) { + return desc_configuration_osx_fs; + } +#endif + return desc_configuration_default; +} + +//--------------------------------------------------------------------+ +// BOS Descriptor, required for OS guessing quirk +//--------------------------------------------------------------------+ + +#define TUD_BOS_USB20_EXT_DESC_LEN 7 + +#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_USB20_EXT_DESC_LEN) + +// BOS Descriptor is required for webUSB +uint8_t const desc_bos[] = +{ + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), + + // USB 2.0 Extension Descriptor + 0x07, TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_USB20_EXTENSION, 0x00, 0x00, 0x00,0x00 +}; + +uint8_t const * tud_descriptor_bos_cb(void) +{ +#if CFG_QUIRK_OS_GUESSING + quirk_os_guessing_desc_bos_cb(); +#endif + return desc_bos; +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// String Descriptor Index +enum { + STRID_LANGID = 0, + STRID_MANUFACTURER, + STRID_PRODUCT, + STRID_SERIAL, +}; + +// array of pointer to string descriptors +char const *string_desc_arr[] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Speaker", // 2: Product + NULL, // 3: Serials will use unique ID if possible + "UAC2 Speaker", // 4: Audio Interface +}; + +static uint16_t _desc_str[32 + 1]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void) langid; + size_t chr_count; + +#if CFG_QUIRK_OS_GUESSING + quirk_os_guessing_desc_string_cb(); +#endif + + switch ( index ) { + case STRID_LANGID: + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + break; + + case STRID_SERIAL: + chr_count = board_usb_get_serial(_desc_str + 1, 32); + break; + + default: + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + + const char *str = string_desc_arr[index]; + + // Cap at max char + chr_count = strlen(str); + size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type + if ( chr_count > max_count ) chr_count = max_count; + + // Convert ASCII string into UTF-16 + for ( size_t i = 0; i < chr_count; i++ ) { + _desc_str[1 + i] = str[i]; + } + break; + } + + // first byte is length (including header), second byte is string type + _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); + + return _desc_str; +} diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.h b/examples/device/uac2_speaker_fb/src/usb_descriptors.h new file mode 100644 index 000000000..9511bf797 --- /dev/null +++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.h @@ -0,0 +1,82 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 HiFiPhile + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _USB_DESCRIPTORS_H_ +#define _USB_DESCRIPTORS_H_ + +// Defined in TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR +#define UAC2_ENTITY_CLOCK 0x04 +#define UAC2_ENTITY_INPUT_TERMINAL 0x01 +#define UAC2_ENTITY_FEATURE_UNIT 0x02 +#define UAC2_ENTITY_OUTPUT_TERMINAL 0x03 + +#define TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) + +#define TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.7.2.5) */\ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.7.2.8) */\ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS,/*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ + /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1)\ + +#endif diff --git a/examples/device/usbtmc/src/usb_descriptors.c b/examples/device/usbtmc/src/usb_descriptors.c index 54948291e..85acd990a 100644 --- a/examples/device/usbtmc/src/usb_descriptors.c +++ b/examples/device/usbtmc/src/usb_descriptors.c @@ -38,7 +38,7 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) -#define USB_VID 0xCafe +#define USB_VID 0xcafe #define USB_BCD 0x0200 //--------------------------------------------------------------------+ @@ -48,8 +48,8 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = 0x00, + .bcdUSB = USB_BCD, + .bDeviceClass = TUSB_CLASS_UNSPECIFIED, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, @@ -57,7 +57,7 @@ tusb_desc_device_t const desc_device = .idVendor = USB_VID, .idProduct = USB_PID, - .bcdDevice = USB_BCD, + .bcdDevice = 0x0100, .iManufacturer = 0x01, .iProduct = 0x02, @@ -112,17 +112,6 @@ enum #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_USBTMC_DESC_LEN) -#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX - // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number - // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - // Note: since CDC EP ( 1 & 2), HID (4) are spot-on, thus we only need to force - // endpoint number for MSC to 5 - #define EPNUM_MSC 0x05 -#else - #define EPNUM_MSC 0x03 -#endif - - uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -151,7 +140,7 @@ tusb_desc_device_qualifier_t const desc_device_qualifier = .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, .bcdUSB = USB_BCD, - .bDeviceClass = 0x00, + .bDeviceClass = TUSB_CLASS_UNSPECIFIED, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index 21483a2da..3a6daa3d3 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -106,7 +106,7 @@ #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256 // use bulk endpoint for streaming interface -#define CFG_TUD_VIDEO_STREAMING_BULK 1 + #define CFG_TUD_VIDEO_STREAMING_BULK 0 //#define CFG_EXAMPLE_VIDEO_READONLY //#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index 5011bee18..b3e19b0f0 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -118,6 +118,8 @@ enum { #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // nRF5x ISO can only be endpoint 8 #define EPNUM_VIDEO_IN (CFG_TUD_VIDEO_STREAMING_BULK ? 0x81 : 0x88) +#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) + #define EPNUM_VIDEO_IN 0x81 #else #define EPNUM_VIDEO_IN 0x81 #endif diff --git a/examples/device/webusb_serial/src/usb_descriptors.c b/examples/device/webusb_serial/src/usb_descriptors.c index b01fae8e3..2b69a5b56 100644 --- a/examples/device/webusb_serial/src/usb_descriptors.c +++ b/examples/device/webusb_serial/src/usb_descriptors.c @@ -87,29 +87,40 @@ enum #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... - #define EPNUM_CDC_IN 2 - #define EPNUM_CDC_OUT 2 - #define EPNUM_VENDOR_IN 5 - #define EPNUM_VENDOR_OUT 5 -#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X - // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x82 + + #define EPNUM_VENDOR_OUT 0x05 + #define EPNUM_VENDOR_IN 0x85 + +#elif CFG_TUSB_MCU == OPT_MCU_CXD56 + // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number + // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) + #define EPNUM_CDC_NOTIF 0x83 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x81 + + #define EPNUM_VENDOR_OUT 0x05 + #define EPNUM_VENDOR_IN 0x84 + +#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_CDC_IN 2 - #define EPNUM_CDC_OUT 3 - #define EPNUM_VENDOR_IN 4 - #define EPNUM_VENDOR_OUT 5 -#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X - // FT9XX doesn't support a same endpoint number with different direction IN and OUT - // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_CDC_IN 2 - #define EPNUM_CDC_OUT 3 - #define EPNUM_VENDOR_IN 4 - #define EPNUM_VENDOR_OUT 5 + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x83 + + #define EPNUM_VENDOR_OUT 0x04 + #define EPNUM_VENDOR_IN 0x85 + #else - #define EPNUM_CDC_IN 2 - #define EPNUM_CDC_OUT 2 - #define EPNUM_VENDOR_IN 3 - #define EPNUM_VENDOR_OUT 3 + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x82 + + #define EPNUM_VENDOR_OUT 0x03 + #define EPNUM_VENDOR_IN 0x83 #endif uint8_t const desc_configuration[] = @@ -118,7 +129,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, EPNUM_CDC_OUT, 0x80 | EPNUM_CDC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, 0x80 | EPNUM_CDC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), // Interface number, string index, EP Out & IN address, EP size TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 5, EPNUM_VENDOR_OUT, 0x80 | EPNUM_VENDOR_IN, TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c index 5be531098..443cc4674 100644 --- a/examples/dual/host_info_to_device_cdc/src/main.c +++ b/examples/dual/host_info_to_device_cdc/src/main.c @@ -24,7 +24,7 @@ */ /* Host example will get device descriptors of attached devices and print it out via device cdc as follows: - * Device 1: ID 046d:c52f + * Device 1: ID 046d:c52f SN 11223344 Device Descriptor: bLength 18 bDescriptorType 1 @@ -147,7 +147,21 @@ void print_device_info(uint8_t daddr) { return; } - cdc_printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct); + // Get String descriptor using Sync API + uint16_t serial[64]; + uint16_t buf[128]; + + cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device.idVendor, desc_device.idProduct); + xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial)); + if (XFER_RESULT_SUCCESS != xfer_result) { + serial[0] = 'n'; + serial[1] = '/'; + serial[2] = 'a'; + serial[3] = 0; + } + print_utf16(serial, TU_ARRAY_SIZE(serial)); + tud_cdc_write_str("\r\n"); + cdc_printf("Device Descriptor:\r\n"); cdc_printf(" bLength %u\r\n" , desc_device.bLength); cdc_printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType); @@ -160,9 +174,6 @@ void print_device_info(uint8_t daddr) { cdc_printf(" idProduct 0x%04x\r\n" , desc_device.idProduct); cdc_printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice); - // Get String descriptor using Sync API - uint16_t buf[128]; - cdc_printf(" iManufacturer %u " , desc_device.iManufacturer); xfer_result = tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf)); if (XFER_RESULT_SUCCESS == xfer_result ) { @@ -178,10 +189,7 @@ void print_device_info(uint8_t daddr) { tud_cdc_write_str("\r\n"); cdc_printf(" iSerialNumber %u " , desc_device.iSerialNumber); - xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf)); - if (XFER_RESULT_SUCCESS == xfer_result) { - print_utf16(buf, TU_ARRAY_SIZE(buf)); - } + tud_cdc_write_str((char*)serial); // serial is already to UTF-8 tud_cdc_write_str("\r\n"); cdc_printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations); diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index f0d42a08f..6bb3a2072 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -235,6 +235,7 @@ 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) dev_addr; + (void) len; uint8_t const rpt_count = hid_info[instance].report_count; tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info; diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c index bff830ca2..6ffe0b6d4 100644 --- a/examples/host/hid_controller/src/hid_app.c +++ b/examples/host/hid_controller/src/hid_app.c @@ -253,6 +253,7 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) void process_sony_ds4(uint8_t const* report, uint16_t len) { + (void)len; const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" }; // previous report used to compare for changes diff --git a/examples/typec/power_delivery/src/main.c b/examples/typec/power_delivery/src/main.c index 489d01aa1..a8214f34e 100644 --- a/examples/typec/power_delivery/src/main.c +++ b/examples/typec/power_delivery/src/main.c @@ -98,7 +98,7 @@ bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo; uint32_t const voltage_mv = fixed->voltage_50mv*50; uint32_t const current_ma = fixed->current_max_10ma*10; - printf("[Fixed] %lu mV %lu mA\r\n", voltage_mv, current_ma); + printf("[Fixed] %"PRIu32" mV %"PRIu32" mA\r\n", voltage_mv, current_ma); if (voltage_mv <= VOLTAGE_MAX_MV && current_ma >= CURRENT_MAX_MA) { // Found a suitable PDO diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h index eee9ed9c5..a458a3fdc 100644 --- a/hw/bsp/board_api.h +++ b/hw/bsp/board_api.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _BOARD_API_H_ -#define _BOARD_API_H_ +#ifndef BOARD_API_H_ +#define BOARD_API_H_ #ifdef __cplusplus extern "C" { @@ -72,6 +72,9 @@ void board_init(void); // Init board after tinyusb is initialized void board_init_after_tusb(void) TU_ATTR_WEAK; +// Jump to bootloader +void board_reset_to_bootloader(void) TU_ATTR_WEAK; + // Turn LED on or off void board_led_write(bool state); diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h index 013eb1c83..d3a33cf36 100644 --- a/hw/bsp/board_mcu.h +++ b/hw/bsp/board_mcu.h @@ -170,6 +170,18 @@ #elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) // no header needed +#elif CFG_TUSB_MCU == OPT_MCU_MAX32690 + #include "max32690.h" + +#elif CFG_TUSB_MCU == OPT_MCU_MAX32650 + #include "max32650.h" + +#elif CFG_TUSB_MCU == OPT_MCU_MAX32666 + #include "max32665.h" + +#elif CFG_TUSB_MCU == OPT_MCU_MAX78002 + #include "max78002.h" + #else #error "Missing MCU header" #endif diff --git a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.cmake b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.cmake index 3dd87d3de..4aae6bdc2 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.cmake +++ b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.cmake @@ -1,6 +1,8 @@ set(MCU_VARIANT D6) -set(LD_FLASH_SIZE 64K) +# 64KB zero-wait, 224KB total flash +#set(LD_FLASH_SIZE 64K) +set(LD_FLASH_SIZE 224K) set(LD_RAM_SIZE 20K) # set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/${CH32_FAMILY}_tinyuf2.ld) diff --git a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h index 64eaf931e..692cf11bf 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h +++ b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h @@ -6,7 +6,7 @@ extern "C" { #endif #define LED_PORT GPIOA -#define LED_PIN GPIO_Pin_15 +#define LED_PIN GPIO_Pin_0 #define LED_STATE_ON 0 #define UART_DEV USART1 diff --git a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.mk b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.mk index 7d5894629..bdd15f737 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.mk +++ b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.mk @@ -2,8 +2,10 @@ MCU_VARIANT = D6 CFLAGS += \ -DSYSCLK_FREQ_144MHz_HSE=144000000 \ + -DCH32_FLASH_ENHANCE_READ_MODE=1 \ -DCFG_EXAMPLE_MSC_DUAL_READONLY \ +# 64KB zero-wait, 224KB total flash LDFLAGS += \ - -Wl,--defsym=__FLASH_SIZE=64K \ + -Wl,--defsym=__FLASH_SIZE=224K \ -Wl,--defsym=__RAM_SIZE=20K \ diff --git a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.cmake b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.cmake index 6e5305212..ecb8b378f 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.cmake +++ b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.cmake @@ -1,6 +1,8 @@ set(MCU_VARIANT D6) -set(LD_FLASH_SIZE 32K) +# 32KB zero-wait, 224KB total flash +#set(LD_FLASH_SIZE 32K) +set(LD_FLASH_SIZE 224K) set(LD_RAM_SIZE 10K) function(update_board TARGET) diff --git a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h index d6c3a64c8..783831edd 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h +++ b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h @@ -7,7 +7,7 @@ extern "C" { #define LED_PORT GPIOA #define LED_PIN GPIO_Pin_0 -#define LED_STATE_ON 1 +#define LED_STATE_ON 0 #define UART_DEV USART2 #define UART_CLOCK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE) diff --git a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.mk b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.mk index e5e4d63ba..f71f53478 100644 --- a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.mk +++ b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.mk @@ -2,8 +2,10 @@ MCU_VARIANT = D6 CFLAGS += \ -DSYSCLK_FREQ_144MHz_HSI=144000000 \ + -DCH32_FLASH_ENHANCE_READ_MODE=1 \ -DCFG_EXAMPLE_MSC_DUAL_READONLY \ +# 32KB zero-wait, 224KB total flash LDFLAGS += \ - -Wl,--defsym=__FLASH_SIZE=32K \ + -Wl,--defsym=__FLASH_SIZE=224K \ -Wl,--defsym=__RAM_SIZE=10K \ diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake index f8dc862a7..6c7712cdd 100644 --- a/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake @@ -1,6 +1,8 @@ set(MCU_VARIANT D6) +# 64KB zero-wait, 224KB total flash set(LD_FLASH_SIZE 64K) +#set(LD_FLASH_SIZE 224K) set(LD_RAM_SIZE 20K) function(update_board TARGET) diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk index 7d5894629..362aace47 100644 --- a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk @@ -2,8 +2,10 @@ MCU_VARIANT = D6 CFLAGS += \ -DSYSCLK_FREQ_144MHz_HSE=144000000 \ + -DCH32_FLASH_ENHANCE_READ_MODE=1 \ -DCFG_EXAMPLE_MSC_DUAL_READONLY \ +# 64KB zero-wait , 224KB total flash LDFLAGS += \ - -Wl,--defsym=__FLASH_SIZE=64K \ + -Wl,--defsym=__FLASH_SIZE=224K \ -Wl,--defsym=__RAM_SIZE=20K \ diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index ea98a5e19..43dd7e032 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -62,7 +62,6 @@ void USBWakeUp_IRQHandler(void) { #if CFG_TUSB_OS == OPT_OS_NONE - volatile uint32_t system_ticks = 0; __attribute__((interrupt)) @@ -84,7 +83,6 @@ uint32_t SysTick_Config(uint32_t ticks) { uint32_t board_millis(void) { return system_ticks; } - #endif void board_init(void) { @@ -139,6 +137,34 @@ void board_init(void) { __enable_irq(); } +void board_reset_to_bootloader(void) { +// board_led_write(true); +// +// __disable_irq(); +// +// #if CFG_TUD_ENABLED +// tud_deinit(0); +// RCC_APB1PeriphResetCmd(RCC_APB1Periph_USB, ENABLE); +// RCC_APB1PeriphResetCmd(RCC_APB1Periph_USB, DISABLE); +// #endif +// +// SysTick->CTLR = 0; +// for (int i = WWDG_IRQn; i< DMA1_Channel8_IRQn; i++) { +// NVIC_DisableIRQ(i); +// } +// +// __enable_irq(); +// +// // define function pointer to BOOT ROM address +// void (*bootloader_entry)(void) = (void (*)(void))0x1FFF8000; +// +// bootloader_entry(); +// +// board_led_write(false); + + // while(1) { } +} + void board_led_write(bool state) { GPIO_WriteBit(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); } @@ -147,6 +173,17 @@ uint32_t board_button_read(void) { return false; } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + volatile uint32_t* ch32_uuid = ((volatile uint32_t*) 0x1FFFF7E8UL); + uint32_t* serial_32 = (uint32_t*) (uintptr_t) id; + serial_32[0] = ch32_uuid[0]; + serial_32[1] = ch32_uuid[1]; + serial_32[2] = ch32_uuid[2]; + + return 12; +} + int board_uart_read(uint8_t *buf, int len) { (void) buf; (void) len; @@ -166,3 +203,7 @@ int board_uart_write(void const *buf, int len) { return len; } + +//-------------------------------------------------------------------- +// Neopixel +//-------------------------------------------------------------------- diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index faa79ed66..380ef190d 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -72,6 +72,12 @@ function(add_board_target BOARD_TARGET) update_board(${BOARD_TARGET}) + if (LD_FLASH_SIZE STREQUAL 224K) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CH32_FLASH_ENHANCE_READ_MODE=1 + ) + endif() + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") target_compile_options(${BOARD_TARGET} PUBLIC -mcmodel=medany @@ -131,6 +137,7 @@ function(family_configure_example TARGET RTOS) # Flashing family_add_bin_hex(${TARGET}) family_flash_openocd_wch(${TARGET}) + family_flash_wlink_rs(${TARGET}) #family_add_uf2(${TARGET} ${UF2_FAMILY_ID}) #family_flash_uf2(${TARGET} ${UF2_FAMILY_ID}) diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 4485091dc..08761dc0d 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -60,4 +60,5 @@ INC += \ FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -flash: flash-openocd-wch +flash: flash-wlink-rs +#flash: flash-openocd-wch diff --git a/hw/bsp/ch32v20x/system_ch32v20x.c b/hw/bsp/ch32v20x/system_ch32v20x.c index 435feae1b..d32ee8d17 100644 --- a/hw/bsp/ch32v20x/system_ch32v20x.c +++ b/hw/bsp/ch32v20x/system_ch32v20x.c @@ -19,9 +19,9 @@ * If none of the define below is enabled, the HSI is used as System clock source. */ //#define SYSCLK_FREQ_HSE HSE_VALUE -//#define SYSCLK_FREQ_48MHz_HSE 48000000 +// #define SYSCLK_FREQ_48MHz_HSE 48000000 //#define SYSCLK_FREQ_56MHz_HSE 56000000 -//#define SYSCLK_FREQ_72MHz_HSE 72000000 +// #define SYSCLK_FREQ_72MHz_HSE 72000000 // #define SYSCLK_FREQ_96MHz_HSE 96000000 //#define SYSCLK_FREQ_120MHz_HSE 120000000 //#define SYSCLK_FREQ_144MHz_HSE 144000000 @@ -109,6 +109,16 @@ static void SetSysClockTo144_HSI( void ); */ void SystemInit (void) { + // Enable Flash enhance read mode for full 224KB +#if defined(CH32_FLASH_ENHANCE_READ_MODE) && CH32_FLASH_ENHANCE_READ_MODE == 1 + FLASH->KEYR = 0x45670123; // FLASH_Unlock_Fast(); + FLASH->KEYR = 0xCDEF89AB; + + FLASH->CTLR |= (1 << 24); // Enhanced Read Mode + + FLASH->CTLR |= (1 << 15); // FLASH_Lock_Fast(); +#endif + RCC->CTLR |= (uint32_t)0x00000001; RCC->CFGR0 &= (uint32_t)0xF8FF0000; RCC->CTLR &= (uint32_t)0xFEF6FFFF; diff --git a/hw/bsp/da14695_dk_usb/da14695_dk_usb.c b/hw/bsp/da14695_dk_usb/da14695_dk_usb.c deleted file mode 100644 index 667b83de3..000000000 --- a/hw/bsp/da14695_dk_usb/da14695_dk_usb.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * 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. - */ - -#include "bsp/board_api.h" -#include -#include - -//--------------------------------------------------------------------+ -// Forward USB interrupt events to TinyUSB IRQ Handler -//--------------------------------------------------------------------+ -void USB_IRQHandler(void) -{ - tud_int_handler(0); -} - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM -//--------------------------------------------------------------------+ - -#define LED_PIN 33 // P1.1 -#define LED_STATE_ON 1 -#define LED_STATE_OFF (1-LED_STATE_ON) - -#define BUTTON_PIN 6 - -void UnhandledIRQ(void) -{ - CRG_TOP->SYS_CTRL_REG = 0x80; - __BKPT(1); - while(1); -} - -// DA146xx driver function that must be called whenever VBUS changes. -extern void tusb_vbus_changed(bool present); - -void board_init(void) -{ - // LED - hal_gpio_init_out(LED_PIN, LED_STATE_ON); - - hal_gpio_init_out(1, 0); - hal_gpio_init_out(2, 0); - hal_gpio_init_out(3, 0); - hal_gpio_init_out(4, 0); - hal_gpio_init_out(5, 0); - - // Button - hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_DOWN); - - // 1ms tick timer - SysTick_Config(SystemCoreClock / 1000); - -#if CFG_TUD_ENABLED - // This board is USB powered there is no need to monitor - // VBUS line. Notify driver that VBUS is present. - tusb_vbus_changed(true); - - /* Setup USB IRQ */ - NVIC_SetPriority(USB_IRQn, 2); - NVIC_EnableIRQ(USB_IRQn); - - /* Use PLL96 / 2 clock not HCLK */ - CRG_TOP->CLK_CTRL_REG &= ~CRG_TOP_CLK_CTRL_REG_USB_CLK_SRC_Msk; - - mcu_gpio_set_pin_function(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); - mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); -#endif -} - -//--------------------------------------------------------------------+ -// Board porting API -//--------------------------------------------------------------------+ - -void board_led_write(bool state) -{ - hal_gpio_write(LED_PIN, state ? LED_STATE_ON : LED_STATE_OFF); -} - -uint32_t board_button_read(void) -{ - // button is active HIGH - return hal_gpio_read(BUTTON_PIN); -} - -int board_uart_read(uint8_t* buf, int len) -{ - (void)buf; - (void)len; - return 0; -} - -int board_uart_write(void const * buf, int len) -{ - (void)buf; - (void)len; - - return 0; -} - -#if CFG_TUSB_OS == OPT_OS_NONE -volatile uint32_t system_ticks = 0; -void SysTick_Handler(void) -{ - system_ticks++; -} - -uint32_t board_millis(void) -{ - return system_ticks; -} -#endif diff --git a/hw/bsp/da1469x/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/da1469x/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..4d4379a6f --- /dev/null +++ b/hw/bsp/da1469x/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,150 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "DA1469xAB.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) +#define configRUN_FREERTOS_SECURE_ONLY 1 + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS 4 + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1< #include +#define LED_STATE_OFF (1-LED_STATE_ON) + //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ -void USB_IRQHandler(void) -{ +void USB_IRQHandler(void) { tud_int_handler(0); } -#if CFG_TUD_ENABLED -// DA146xx driver function that must be called whenever VBUS changes +// DA146xx driver function that must be called whenever VBUS changes. extern void tusb_vbus_changed(bool present); +#if defined(NEED_VBUS_MONITOR) && CFG_TUD_ENABLED // VBUS change interrupt handler -void VBUS_IRQHandler(void) -{ +void VBUS_IRQHandler(void) { bool present = (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0; // Clear VBUS interrupt CRG_TOP->VBUS_IRQ_CLEAR_REG = 1; @@ -54,22 +55,13 @@ void VBUS_IRQHandler(void) //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ - -#define LED_PIN 33 -#define LED_STATE_ON 1 -#define LED_STATE_OFF 0 - -#define BUTTON_PIN 6 - -void UnhandledIRQ(void) -{ +void UnhandledIRQ(void) { CRG_TOP->SYS_CTRL_REG = 0x80; __BKPT(1); - while(1); + while (1); } -void board_init(void) -{ +void board_init(void) { // LED hal_gpio_init_out(LED_PIN, LED_STATE_ON); @@ -80,12 +72,13 @@ void board_init(void) hal_gpio_init_out(5, 0); // Button - hal_gpio_init_in(BUTTON_PIN, HAL_GPIO_PULL_UP); + hal_gpio_init_in(BUTTON_PIN, BUTTON_STATE_ACTIVE ? HAL_GPIO_PULL_DOWN : HAL_GPIO_PULL_UP); // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); #if CFG_TUD_ENABLED + #ifdef NEED_VBUS_MONITOR // Setup interrupt for both connect and disconnect CRG_TOP->VBUS_IRQ_MASK_REG = CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_FALL_Msk | CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_RISE_Msk; @@ -94,6 +87,10 @@ void board_init(void) // otherwise it could go unnoticed. NVIC_SetPendingIRQ(VBUS_IRQn); NVIC_EnableIRQ(VBUS_IRQn); + #else + // This board is USB powered there is no need to monitor VBUS line. Notify driver that VBUS is present. + tusb_vbus_changed(true); + #endif /* Setup USB IRQ */ NVIC_SetPriority(USB_IRQn, 2); @@ -111,41 +108,35 @@ void board_init(void) // Board porting API //--------------------------------------------------------------------+ -void board_led_write(bool state) -{ +void board_led_write(bool state) { hal_gpio_write(LED_PIN, state ? LED_STATE_ON : LED_STATE_OFF); } -uint32_t board_button_read(void) -{ - // button is active LOW - return hal_gpio_read(BUTTON_PIN) ^ 1; +uint32_t board_button_read(void) { + return BUTTON_STATE_ACTIVE == hal_gpio_read(BUTTON_PIN); } -int board_uart_read(uint8_t* buf, int len) -{ - (void)buf; - (void)len; +int board_uart_read(uint8_t* buf, int len) { + (void) buf; + (void) len; return 0; } -int board_uart_write(void const * buf, int len) -{ - (void)buf; - (void)len; +int board_uart_write(void const* buf, int len) { + (void) buf; + (void) len; return 0; } #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler(void) -{ + +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis(void) -{ +uint32_t board_millis(void) { return system_ticks; } #endif diff --git a/hw/bsp/da1469x/family.cmake b/hw/bsp/da1469x/family.cmake new file mode 100644 index 000000000..8c89141fe --- /dev/null +++ b/hw/bsp/da1469x/family.cmake @@ -0,0 +1,141 @@ +include_guard() + +set(MCU_DIR ${TOP}/hw/mcu/dialog/da1469x) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +set(CMAKE_SYSTEM_PROCESSOR cortex-m33-nodsp CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) +set(FAMILY_MCUS DA1469X CACHE INTERNAL "") + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif () + + if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/da1469x.ld) + endif () + + if (NOT DEFINED STARTUP_FILE_${CMAKE_C_COMPILER_ID}) + set(STARTUP_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gcc_startup_da1469x.S) + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + endif () + + add_library(${BOARD_TARGET} STATIC + ${MCU_DIR}/src/system_da1469x.c + ${MCU_DIR}/src/da1469x_clock.c + ${MCU_DIR}/src/hal_gpio.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_compile_options(${BOARD_TARGET} PUBLIC -mthumb-interwork) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CORE_M33 + CFG_TUD_ENDPOINT0_SIZE=8 + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ${MCU_DIR}/include + ${MCU_DIR}/SDK_10.0.8.105/sdk/bsp/include + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -L${NRFX_DIR}/mdk + --specs=nosys.specs --specs=nano.specs + -nostartfiles + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -L${NRFX_DIR}/mdk + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--config=${LD_FILE_IAR}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ + +function(family_flash_jlink_dialog TARGET) + set(JLINKEXE JLinkExe) + set(JLINK_IF swd) + + # mkimage from sdk + set(MKIMAGE $ENV{HOME}/code/tinyusb-mcu-driver/dialog/SDK_10.0.8.105/binaries/mkimage) + + file(GENERATE OUTPUT $/version.h + CONTENT "#define SW_VERSION \"v_1.0.0.1\" +#define SW_VERSION_DATE \"2024-07-17 17:55\"" + ) + + file(GENERATE OUTPUT $/${TARGET}.jlink + CONTENT "r +halt +loadfile $/${TARGET}-image.bin 0x16000000 +r +go +exit" + ) + + add_custom_target(${TARGET}-image + DEPENDS ${TARGET} + COMMAND ${MKIMAGE} da1469x $/${TARGET}.bin $/version.h $/${TARGET}.bin.img + COMMAND cp ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/product_header.dump $/${TARGET}-image.bin + COMMAND cat $/${TARGET}.bin.img >> $/${TARGET}-image.bin + ) + add_custom_target(${TARGET}-jlink + DEPENDS ${TARGET}-image + COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $/${TARGET}.jlink + ) +endfunction() + + +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_DA1469X ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/dialog/da146xx/dcd_da146xx.c + ) + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_jlink_dialog(${TARGET}) +endfunction() diff --git a/hw/bsp/da14695_dk_usb/board.mk b/hw/bsp/da1469x/family.mk similarity index 52% rename from hw/bsp/da14695_dk_usb/board.mk rename to hw/bsp/da1469x/family.mk index 980b1a361..f35fe2cb5 100644 --- a/hw/bsp/da14695_dk_usb/board.mk +++ b/hw/bsp/da1469x/family.mk @@ -1,4 +1,6 @@ -MCU_FAMILY_DIR = hw/mcu/dialog/da1469x +MCU_DIR = hw/mcu/dialog/da1469x + +include $(TOP)/$(BOARD_PATH)/board.mk CFLAGS += \ -flto \ @@ -8,48 +10,52 @@ CFLAGS += \ -mcpu=cortex-m33+nodsp \ -mfloat-abi=hard \ -mfpu=fpv5-sp-d16 \ - -nostdlib \ -DCORE_M33 \ -DCFG_TUSB_MCU=OPT_MCU_DA1469X \ -DCFG_TUD_ENDPOINT0_SIZE=8\ -LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs +LDFLAGS_GCC += \ + -nostdlib \ + --specs=nosys.specs --specs=nano.specs # All source paths should be relative to the top level. -LD_FILE = hw/bsp/$(BOARD)/da1469x.ld +LD_FILE = $(FAMILY_PATH)/linker/da1469x.ld # While this is for da1469x chip, there is chance that da1468x chip family will also work SRC_C += \ src/portable/dialog/da146xx/dcd_da146xx.c \ - $(MCU_FAMILY_DIR)/src/system_da1469x.c \ - $(MCU_FAMILY_DIR)/src/da1469x_clock.c \ - $(MCU_FAMILY_DIR)/src/hal_gpio.c \ + ${MCU_DIR}/src/system_da1469x.c \ + ${MCU_DIR}/src/da1469x_clock.c \ + ${MCU_DIR}/src/hal_gpio.c \ -SRC_S += hw/bsp/$(BOARD)/gcc_startup_da1469x.S +SRC_S += $(FAMILY_PATH)/gcc_startup_da1469x.S INC += \ - $(TOP)/hw/bsp/$(BOARD) \ - $(TOP)/$(MCU_FAMILY_DIR)/include \ - $(TOP)/$(MCU_FAMILY_DIR)/SDK_10.0.8.105/sdk/bsp/include + $(TOP)/$(BOARD_PATH) \ + $(TOP)/${MCU_DIR}/include \ + $(TOP)/${MCU_DIR}/SDK_10.0.8.105/sdk/bsp/include # For freeRTOS port source FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM33_NTZ/non_secure -# For flash-jlink target -JLINK_DEVICE = DA14695 - # flash using jlink but with some twists flash: flash-dialog -flash-dialog: $(BUILD)/$(PROJECT).bin +# SDK_BINARY_PATH is the path to the SDK binary files +SDK_BINARY_PATH = $(HOME)/code/tinyusb-mcu-driver/dialog/SDK_10.0.8.105/binaries +MKIMAGE = $(SDK_BINARY_PATH)/mkimage + +$(BUILD)/$(PROJECT)-image.bin: $(BUILD)/$(PROJECT).bin @echo '#define SW_VERSION "v_1.0.0.1"' >$(BUILD)/version.h - @echo '#define SW_VERSION_DATE "'`date +"%Y-%m-%d %H:%M"`'"' >>$(BUILD)/version.h - mkimage da1469x $(BUILD)/$(PROJECT).bin $(BUILD)/version.h $^.img - cp $(TOP)/hw/bsp/$(BOARD)/product_header.dump $(BUILD)/$(BOARD)-image.bin - cat $^.img >> $(BUILD)/$(BOARD)-image.bin + @echo '#define SW_VERSION_DATE "'`date +"%Y-%m-%d %H:%M"`'"' >> $(BUILD)/version.h + $(MKIMAGE) da1469x $^ $(BUILD)/version.h $^.img + cp $(TOP)/$(FAMILY_PATH)/product_header.dump $(BUILD)/$(PROJECT)-image.bin + cat $^.img >> $(BUILD)/$(PROJECT)-image.bin + +flash-dialog: $(BUILD)/$(PROJECT)-image.bin @echo r > $(BUILD)/$(BOARD).jlink @echo halt >> $(BUILD)/$(BOARD).jlink - @echo loadfile $(BUILD)/$(BOARD)-image.bin 0x16000000 >> $(BUILD)/$(BOARD).jlink + @echo loadfile $^ 0x16000000 >> $(BUILD)/$(BOARD).jlink @echo r >> $(BUILD)/$(BOARD).jlink @echo go >> $(BUILD)/$(BOARD).jlink @echo exit >> $(BUILD)/$(BOARD).jlink diff --git a/hw/bsp/da14695_dk_usb/gcc_startup_da1469x.S b/hw/bsp/da1469x/gcc_startup_da1469x.S similarity index 100% rename from hw/bsp/da14695_dk_usb/gcc_startup_da1469x.S rename to hw/bsp/da1469x/gcc_startup_da1469x.S diff --git a/hw/bsp/da14695_dk_usb/da1469x.ld b/hw/bsp/da1469x/linker/da1469x.ld similarity index 100% rename from hw/bsp/da14695_dk_usb/da1469x.ld rename to hw/bsp/da1469x/linker/da1469x.ld diff --git a/hw/bsp/da14695_dk_usb/product_header.dump b/hw/bsp/da1469x/product_header.dump similarity index 100% rename from hw/bsp/da14695_dk_usb/product_header.dump rename to hw/bsp/da1469x/product_header.dump diff --git a/hw/bsp/da1469x_dk_pro/board.mk b/hw/bsp/da1469x_dk_pro/board.mk deleted file mode 100644 index 5282f93a3..000000000 --- a/hw/bsp/da1469x_dk_pro/board.mk +++ /dev/null @@ -1,56 +0,0 @@ -MCU_FAMILY_DIR = hw/mcu/dialog/da1469x - -CFLAGS += \ - -flto \ - -mthumb \ - -mthumb-interwork \ - -mabi=aapcs \ - -mcpu=cortex-m33+nodsp \ - -mfloat-abi=hard \ - -mfpu=fpv5-sp-d16 \ - -nostdlib \ - -DCORE_M33 \ - -DCFG_TUSB_MCU=OPT_MCU_DA1469X \ - -DCFG_TUD_ENDPOINT0_SIZE=8\ - -LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs - -# All source paths should be relative to the top level. -LD_FILE = hw/bsp/$(BOARD)/da1469x.ld - -# While this is for da1469x chip, there is chance that da1468x chip family will also work -SRC_C += \ - src/portable/dialog/da146xx/dcd_da146xx.c \ - $(MCU_FAMILY_DIR)/src/system_da1469x.c \ - $(MCU_FAMILY_DIR)/src/da1469x_clock.c \ - $(MCU_FAMILY_DIR)/src/hal_gpio.c \ - -SRC_S += hw/bsp/$(BOARD)/gcc_startup_da1469x.S - -INC += \ - $(TOP)/hw/bsp/$(BOARD) \ - $(TOP)/$(MCU_FAMILY_DIR)/include \ - $(TOP)/$(MCU_FAMILY_DIR)/SDK_10.0.8.105/sdk/bsp/include - -# For freeRTOS port source -FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM33_NTZ/non_secure - -# For flash-jlink target -JLINK_DEVICE = DA14699 - -# flash using jlink but with some twists -flash: flash-dialog - -flash-dialog: $(BUILD)/$(PROJECT).bin - @echo '#define SW_VERSION "v_1.0.0.1"' >$(BUILD)/version.h - @echo '#define SW_VERSION_DATE "'`date +"%Y-%m-%d %H:%M"`'"' >>$(BUILD)/version.h - mkimage da1469x $(BUILD)/$(PROJECT).bin $(BUILD)/version.h $^.img - cp $(TOP)/hw/bsp/$(BOARD)/product_header.dump $(BUILD)/$(BOARD)-image.bin - cat $^.img >> $(BUILD)/$(BOARD)-image.bin - @echo r > $(BUILD)/$(BOARD).jlink - @echo halt >> $(BUILD)/$(BOARD).jlink - @echo loadfile $(BUILD)/$(BOARD)-image.bin 0x16000000 >> $(BUILD)/$(BOARD).jlink - @echo r >> $(BUILD)/$(BOARD).jlink - @echo go >> $(BUILD)/$(BOARD).jlink - @echo exit >> $(BUILD)/$(BOARD).jlink - $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -JTAGConf -1,-1 -speed auto -CommandFile $(BUILD)/$(BOARD).jlink diff --git a/hw/bsp/da1469x_dk_pro/da1469x.ld b/hw/bsp/da1469x_dk_pro/da1469x.ld deleted file mode 100644 index 8cc1d9d99..000000000 --- a/hw/bsp/da1469x_dk_pro/da1469x.ld +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -MEMORY -{ - /* - * Flash is remapped at 0x0 by 1st stage bootloader, but this is done with - * an offset derived from image header thus it is safer to use remapped - * address space at 0x0 instead of QSPI_M address space at 0x16000000. - * Bootloader partition is 32K, but 9K is currently reserved for product - * header (8K) and image header (1K). - * First 512 bytes of SYSRAM are remapped at 0x0 and used as ISR vector - * (there's no need to reallocate ISR vector) and thus cannot be used by - * application. - */ - - FLASH (r) : ORIGIN = (0x00000000), LENGTH = (1024 * 1024) - RAM (rw) : ORIGIN = (0x20000000), LENGTH = (512 * 1024) -} - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") - -/* Linker script to place sections and symbol values. Should be used together - * with other linker script that defines memory regions FLASH and RAM. - * It references following symbols, which must be defined in code: - * Reset_Handler : Entry of reset handler - * - * It defines following symbols, which code can use without definition: - * __exidx_start - * __exidx_end - * __etext - * __data_start__ - * __preinit_array_start - * __preinit_array_end - * __init_array_start - * __init_array_end - * __fini_array_start - * __fini_array_end - * __data_end__ - * __bss_start__ - * __bss_end__ - * __HeapBase - * __HeapLimit - * __StackLimit - * __StackTop - * __stack - * __bssnz_start__ - * __bssnz_end__ - */ -ENTRY(Reset_Handler) - -SECTIONS -{ - __text = .; - - .text : - { - __isr_vector_start = .; - KEEP(*(.isr_vector)) - /* ISR vector shall have exactly 512 bytes */ - . = __isr_vector_start + 0x200; - __isr_vector_end = .; - - *(.text) - *(.text.*) - - *(.libcmac.rom) - - KEEP(*(.init)) - KEEP(*(.fini)) - - /* .ctors */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - - /* .dtors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.rodata*) - - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - . = ALIGN(4); - } > FLASH - - __exidx_start = .; - .ARM : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - . = ALIGN(4); - } > FLASH - __exidx_end = .; - - .intvect : - { - . = ALIGN(4); - __intvect_start__ = .; - . = . + (__isr_vector_end - __isr_vector_start); - . = ALIGN(4); - } > RAM - - .sleep_state (NOLOAD) : - { - . = ALIGN(4); - *(sleep_state) - } > RAM - - /* This section will be zeroed by RTT package init */ - .rtt (NOLOAD): - { - . = ALIGN(4); - *(.rtt) - . = ALIGN(4); - } > RAM - - __text_ram_addr = LOADADDR(.text_ram); - - .text_ram : - { - . = ALIGN(4); - __text_ram_start__ = .; - *(.text_ram*) - . = ALIGN(4); - __text_ram_end__ = .; - } > RAM AT > FLASH - - __etext = LOADADDR(.data); - - .data : - { - __data_start__ = .; - *(vtable) - *(.data*) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - *(.preinit_array) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - *(SORT(.init_array.*)) - *(.init_array) - PROVIDE_HIDDEN (__init_array_end = .); - - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - /* All data end */ - __data_end__ = .; - } > RAM AT > FLASH - - .bssnz : - { - . = ALIGN(4); - __bssnz_start__ = .; - *(.bss.core.nz*) - . = ALIGN(4); - __bssnz_end__ = .; - } > RAM - - .bss : - { - . = ALIGN(4); - __bss_start__ = .; - *(.bss*) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .cmac (NOLOAD) : - { - . = ALIGN(0x400); - *(.libcmac.ram) - } > RAM - - /* Heap starts after BSS */ - . = ALIGN(8); - __HeapBase = .; - - /* .stack_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later */ - .stack_dummy (COPY): - { - *(.stack*) - } > RAM - - _ram_start = ORIGIN(RAM); - - /* Set stack top to end of RAM, and stack limit move down by - * size of stack_dummy section */ - __StackTop = ORIGIN(RAM) + LENGTH(RAM); - __StackLimit = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* Top of head is the bottom of the stack */ - __HeapLimit = __StackLimit; - end = __HeapLimit; - - /* Check if data + heap + stack exceeds RAM limit */ - ASSERT(__HeapBase <= __HeapLimit, "region RAM overflowed with stack") - - /* Check that intvect is at the beginning of RAM */ - ASSERT(__intvect_start__ == ORIGIN(RAM), "intvect is not at beginning of RAM") -} diff --git a/hw/bsp/da1469x_dk_pro/gcc_startup_da1469x.S b/hw/bsp/da1469x_dk_pro/gcc_startup_da1469x.S deleted file mode 100644 index d47fbcd97..000000000 --- a/hw/bsp/da1469x_dk_pro/gcc_startup_da1469x.S +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - #include "syscfg/syscfg.h" - - .syntax unified - .arch armv7-m - - .section .stack - .align 3 -#ifdef __STACK_SIZE - .equ Stack_Size, __STACK_SIZE -#else - .equ Stack_Size, 0xC00 -#endif - .equ SYS_CTRL_REG, 0x50000024 - .equ CACHE_FLASH_REG, 0x100C0040 - .equ RESET_STAT_REG, 0x500000BC - - .globl __StackTop - .globl __StackLimit -__StackLimit: - .space Stack_Size - .size __StackLimit, . - __StackLimit -__StackTop: - .size __StackTop, . - __StackTop - - .section .heap - .align 3 -#ifdef __HEAP_SIZE - .equ Heap_Size, __HEAP_SIZE -#else - .equ Heap_Size, 0 -#endif - .globl __HeapBase - .globl __HeapLimit -__HeapBase: - .if Heap_Size - .space Heap_Size - .endif - .size __HeapBase, . - __HeapBase -__HeapLimit: - .size __HeapLimit, . - __HeapLimit - - .section .isr_vector - .align 2 - .globl __isr_vector -__isr_vector: - .long __StackTop - .long Reset_Handler - /* Cortex-M33 interrupts */ - .long NMI_Handler - .long HardFault_Handler - .long MemoryManagement_Handler - .long BusFault_Handler - .long UsageFault_Handler - .long SecureFault_Handler - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long SVC_Handler - .long DebugMonitor_Handler - .long 0 /* Reserved */ - .long PendSV_Handler - .long SysTick_Handler - /* DA1469x interrupts */ - .long SENSOR_NODE_IRQHandler - .long DMA_IRQHandler - .long CHARGER_STATE_IRQHandler - .long CHARGER_ERROR_IRQHandler - .long CMAC2SYS_IRQHandler - .long UART_IRQHandler - .long UART2_IRQHandler - .long UART3_IRQHandler - .long I2C_IRQHandler - .long I2C2_IRQHandler - .long SPI_IRQHandler - .long SPI2_IRQHandler - .long PCM_IRQHandler - .long SRC_IN_IRQHandler - .long SRC_OUT_IRQHandler - .long USB_IRQHandler - .long TIMER_IRQHandler - .long TIMER2_IRQHandler - .long RTC_IRQHandler - .long KEY_WKUP_GPIO_IRQHandler - .long PDC_IRQHandler - .long VBUS_IRQHandler - .long MRM_IRQHandler - .long MOTOR_CONTROLLER_IRQHandler - .long TRNG_IRQHandler - .long DCDC_IRQHandler - .long XTAL32M_RDY_IRQHandler - .long ADC_IRQHandler - .long ADC2_IRQHandler - .long CRYPTO_IRQHandler - .long CAPTIMER1_IRQHandler - .long RFDIAG_IRQHandler - .long LCD_CONTROLLER_IRQHandler - .long PLL_LOCK_IRQHandler - .long TIMER3_IRQHandler - .long TIMER4_IRQHandler - .long LRA_IRQHandler - .long RTC_EVENT_IRQHandler - .long GPIO_P0_IRQHandler - .long GPIO_P1_IRQHandler - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .long 0 /* Reserved */ - .size __isr_vector, . - __isr_vector - - .text - .thumb - .thumb_func - .align 2 - .globl Reset_Handler - .type Reset_Handler, %function -Reset_Handler: - /* Make sure interrupt vector is remapped at 0x0 */ - ldr r1, =SYS_CTRL_REG - ldrh r2, [r1, #0] - orrs r2, r2, #8 - strh r2, [r1, #0] - -#if !MYNEWT_VAL(RAM_RESIDENT) -/* - * Flash is remapped at 0x0 with an offset, i.e. 0x0 does not correspond to - * 0x16000000 but to start of an image on flash. This is calculated from product - * header by 1st state bootloader and configured in CACHE_FLASH_REG. We need to - * retrieve proper offset value for calculations later. - */ - ldr r1, =CACHE_FLASH_REG - ldr r4, [r1, #0] - mov r2, r4 - mov r3, #0xFFFF - bic r4, r4, r3 /* CACHE_FLASH_REG[FLASH_REGION_BASE] */ - mov r3, #0xFFF0 - and r2, r2, r3 /* CACHE_FLASH_REG[FLASH_REGION_OFFSET] */ - lsr r2, r2, #2 - orr r4, r4, r2 - -/* Copy ISR vector from flash to RAM */ - ldr r1, =__isr_vector_start /* src ptr */ - ldr r2, =__isr_vector_end /* src end */ - ldr r3, =__intvect_start__ /* dst ptr */ -/* Make sure we copy from QSPIC address range, not from remapped range */ - cmp r1, r4 - itt lt - addlt r1, r1, r4 - addlt r2, r2, r4 -.loop_isr_copy: - cmp r1, r2 - ittt lt - ldrlt r0, [r1], #4 - strlt r0, [r3], #4 - blt .loop_isr_copy - -/* Copy QSPI code from flash to RAM */ - ldr r1, =__text_ram_addr /* src ptr */ - ldr r2, =__text_ram_start__ /* ptr */ - ldr r3, =__text_ram_end__ /* dst end */ -.loop_code_text_ram_copy: - cmp r2, r3 - ittt lt - ldrlt r0, [r1], #4 - strlt r0, [r2], #4 - blt .loop_code_text_ram_copy - -/* Copy data from flash to RAM */ - ldr r1, =__etext /* src ptr */ - ldr r2, =__data_start__ /* dst ptr */ - ldr r3, =__data_end__ /* dst end */ -.loop_data_copy: - cmp r2, r3 - ittt lt - ldrlt r0, [r1], #4 - strlt r0, [r2], #4 - blt .loop_data_copy -#endif - -/* Clear BSS */ - movs r0, 0 - ldr r1, =__bss_start__ - ldr r2, =__bss_end__ -.loop_bss_clear: - cmp r1, r2 - itt lt - strlt r0, [r1], #4 - blt .loop_bss_clear - - ldr r0, =__HeapBase - ldr r1, =__HeapLimit -/* Call static constructors */ - bl __libc_init_array - - bl SystemInit - bl main - - .pool - .size Reset_Handler, . - Reset_Handler - -/* Default interrupt handler */ - .type Default_Handler, %function -Default_Handler: - ldr r1, =SYS_CTRL_REG - ldrh r2, [r1, #0] - orrs r2, r2, #0x80 /* DEBUGGER_ENABLE */ - strh r2, [r1, #0] - b . - - .size Default_Handler, . - Default_Handler - -/* Default handlers for all interrupts */ - .macro IRQ handler - .weak \handler - .set \handler, Default_Handler - .endm - - /* Cortex-M33 interrupts */ - IRQ NMI_Handler - IRQ HardFault_Handler - IRQ MemoryManagement_Handler - IRQ BusFault_Handler - IRQ UsageFault_Handler - IRQ SecureFault_Handler - IRQ SVC_Handler - IRQ DebugMonitor_Handler - IRQ PendSV_Handler - IRQ SysTick_Handler - /* DA1469x interrupts */ - IRQ SENSOR_NODE_IRQHandler - IRQ DMA_IRQHandler - IRQ CHARGER_STATE_IRQHandler - IRQ CHARGER_ERROR_IRQHandler - IRQ CMAC2SYS_IRQHandler - IRQ UART_IRQHandler - IRQ UART2_IRQHandler - IRQ UART3_IRQHandler - IRQ I2C_IRQHandler - IRQ I2C2_IRQHandler - IRQ SPI_IRQHandler - IRQ SPI2_IRQHandler - IRQ PCM_IRQHandler - IRQ SRC_IN_IRQHandler - IRQ SRC_OUT_IRQHandler - IRQ USB_IRQHandler - IRQ TIMER_IRQHandler - IRQ TIMER2_IRQHandler - IRQ RTC_IRQHandler - IRQ KEY_WKUP_GPIO_IRQHandler - IRQ PDC_IRQHandler - IRQ VBUS_IRQHandler - IRQ MRM_IRQHandler - IRQ MOTOR_CONTROLLER_IRQHandler - IRQ TRNG_IRQHandler - IRQ DCDC_IRQHandler - IRQ XTAL32M_RDY_IRQHandler - IRQ ADC_IRQHandler - IRQ ADC2_IRQHandler - IRQ CRYPTO_IRQHandler - IRQ CAPTIMER1_IRQHandler - IRQ RFDIAG_IRQHandler - IRQ LCD_CONTROLLER_IRQHandler - IRQ PLL_LOCK_IRQHandler - IRQ TIMER3_IRQHandler - IRQ TIMER4_IRQHandler - IRQ LRA_IRQHandler - IRQ RTC_EVENT_IRQHandler - IRQ GPIO_P0_IRQHandler - IRQ GPIO_P1_IRQHandler - IRQ RESERVED40_IRQHandler - IRQ RESERVED41_IRQHandler - IRQ RESERVED42_IRQHandler - IRQ RESERVED43_IRQHandler - IRQ RESERVED44_IRQHandler - IRQ RESERVED45_IRQHandler - IRQ RESERVED46_IRQHandler - IRQ RESERVED47_IRQHandler - -.end diff --git a/hw/bsp/da1469x_dk_pro/product_header.dump b/hw/bsp/da1469x_dk_pro/product_header.dump deleted file mode 100644 index ea4842242..000000000 Binary files a/hw/bsp/da1469x_dk_pro/product_header.dump and /dev/null differ diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 9f2e34691..aa5e037d1 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -69,6 +69,10 @@ if (NOT FAMILY STREQUAL rp2040) endif() endif() +if (NOT NO_WARN_RWX_SEGMENTS_SUPPORTED) + set(NO_WARN_RWX_SEGMENTS_SUPPORTED 1) +endif() + set(WARNING_FLAGS_GNU -Wall -Wextra @@ -210,7 +214,7 @@ function(family_configure_common TARGET RTOS) # Generate linker map file if (CMAKE_C_COMPILER_ID STREQUAL "GNU") target_link_options(${TARGET} PUBLIC "LINKER:-Map=$.map") - if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0) + if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0 AND NO_WARN_RWX_SEGMENTS_SUPPORTED) target_link_options(${TARGET} PUBLIC "LINKER:--no-warn-rwx-segments") endif () elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") @@ -360,7 +364,7 @@ function(family_add_default_example_warnings TARGET) ) if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0) + if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0 AND NO_WARN_RWX_SEGMENTS_SUPPORTED) target_link_options(${TARGET} PUBLIC "LINKER:--no-warn-rwx-segments") endif() @@ -395,6 +399,11 @@ function(family_flash_jlink TARGET) set(JLINK_IF swd) endif () + if (NOT DEFINED JLINK_OPTION) + set(JLINK_OPTION "") + endif () + separate_arguments(OPTION_LIST UNIX_COMMAND ${JLINK_OPTION}) + file(GENERATE OUTPUT $/${TARGET}.jlink CONTENT "halt @@ -406,8 +415,15 @@ exit" add_custom_target(${TARGET}-jlink DEPENDS ${TARGET} - COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $/${TARGET}.jlink + COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} ${OPTION_LIST} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $/${TARGET}.jlink + VERBATIM ) + + # optional flash post build +# add_custom_command(TARGET ${TARGET} POST_BUILD +# COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} ${OPTION_LIST} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $/${TARGET}.jlink +# VERBATIM +# ) endfunction() @@ -424,6 +440,19 @@ function(family_flash_stlink TARGET) endfunction() +# Add flash st-flash target +function(family_flash_stflash TARGET) + if (NOT DEFINED ST_FLASH) + set(ST_FLASH st-flash) + endif () + + add_custom_target(${TARGET}-stflash + DEPENDS ${TARGET} + COMMAND ${ST_FLASH} write $/${TARGET}.bin 0x8000000 + ) +endfunction() + + # Add flash openocd target function(family_flash_openocd TARGET) if (NOT DEFINED OPENOCD) @@ -440,11 +469,12 @@ function(family_flash_openocd TARGET) # note skip verify since it has issue with rp2040 add_custom_target(${TARGET}-openocd DEPENDS ${TARGET} - COMMAND ${OPENOCD} ${OPTION_LIST} -c init -c halt -c "program $ reset" ${OPTION_LIST2} -c exit + COMMAND ${OPENOCD} -c "tcl_port disabled" -c "gdb_port disabled" ${OPTION_LIST} -c init -c halt -c "program $" -c reset ${OPTION_LIST2} -c exit VERBATIM ) endfunction() + # Add flash openocd-wch target # compiled from https://github.com/hathach/riscv-openocd-wch or https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz function(family_flash_openocd_wch TARGET) @@ -455,6 +485,39 @@ function(family_flash_openocd_wch TARGET) family_flash_openocd(${TARGET}) endfunction() + +# Add flash openocd adi (Analog Devices) target +# included with msdk or compiled from release branch of https://github.com/analogdevicesinc/openocd +function(family_flash_openocd_adi TARGET) + if (DEFINED $ENV{MAXIM_PATH}) + # use openocd from msdk + set(OPENOCD ENV{MAXIM_PATH}/Tools/OpenOCD/openocd) + set(OPENOCD_OPTION2 "-s ENV{MAXIM_PATH}/Tools/OpenOCD/scripts") + else() + # compiled from source + if (NOT DEFINED OPENOCD_ADI_PATH) + set(OPENOCD_ADI_PATH $ENV{HOME}/app/openocd_adi) + endif () + set(OPENOCD ${OPENOCD_ADI_PATH}/src/openocd) + set(OPENOCD_OPTION2 "-s ${OPENOCD_ADI_PATH}/tcl") + endif () + + family_flash_openocd(${TARGET}) +endfunction() + +# Add flash with https://github.com/ch32-rs/wlink +function(family_flash_wlink_rs TARGET) + if (NOT DEFINED WLINK_RS) + set(WLINK_RS wlink) + endif () + + add_custom_target(${TARGET}-wlink-rs + DEPENDS ${TARGET} + COMMAND ${WLINK_RS} flash $ + ) +endfunction() + + # Add flash pycod target function(family_flash_pyocd TARGET) if (NOT DEFINED PYOC) @@ -467,6 +530,7 @@ function(family_flash_pyocd TARGET) ) endfunction() + # Flash with UF2 function(family_flash_uf2 TARGET FAMILY_ID) add_custom_target(${TARGET}-uf2 @@ -475,6 +539,7 @@ function(family_flash_uf2 TARGET FAMILY_ID) ) endfunction() + # Add flash teensy_cli target function(family_flash_teensy TARGET) if (NOT DEFINED TEENSY_CLI) @@ -487,6 +552,7 @@ function(family_flash_teensy TARGET) ) endfunction() + # Add flash using NXP's LinkServer (redserver) # https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/linkserver-for-microcontrollers:LINKERSERVER function(family_flash_nxplink TARGET) @@ -532,6 +598,21 @@ function(family_flash_msp430flasher TARGET) ) endfunction() + +function(family_flash_uniflash TARGET) + if (NOT DEFINED DSLITE) + set(DSLITE dslite.sh) + endif () + + separate_arguments(OPTION_LIST UNIX_COMMAND ${UNIFLASH_OPTION}) + + add_custom_target(${TARGET}-uniflash + DEPENDS ${TARGET} + COMMAND ${DSLITE} ${UNIFLASH_OPTION} -f $/${TARGET}.hex + VERBATIM + ) +endfunction() + #---------------------------------- # Family specific #---------------------------------- diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c index c9c4918ef..2f305aa4d 100644 --- a/hw/bsp/imxrt/family.c +++ b/hw/bsp/imxrt/family.c @@ -40,6 +40,7 @@ #include "fsl_iomuxc.h" #include "fsl_clock.h" #include "fsl_lpuart.h" +#include "fsl_ocotp.h" #ifdef __GNUC__ #pragma GCC diagnostic pop @@ -186,6 +187,29 @@ uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == GPIO_PinRead(BUTTON_PORT, BUTTON_PIN); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + + #if FSL_FEATURE_OCOTP_HAS_TIMING_CTRL + OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk)); + #else + OCOTP_Init(OCOTP, 0u); + #endif + + // Reads shadow registers 0x01 - 0x04 (Configuration and Manufacturing Info) + // into 8 bit wide destination, avoiding punning. + for (int i = 0; i < 4; ++i) { + uint32_t wr = OCOTP_ReadFuseShadowRegister(OCOTP, i + 1); + for (int j = 0; j < 4; j++) { + id[i*4+j] = wr & 0xff; + wr >>= 8; + } + } + OCOTP_Deinit(OCOTP); + + return 16; +} + int board_uart_read(uint8_t* buf, int len) { int count = 0; diff --git a/hw/bsp/imxrt/family.cmake b/hw/bsp/imxrt/family.cmake index f4d7378a5..d917e9777 100644 --- a/hw/bsp/imxrt/family.cmake +++ b/hw/bsp/imxrt/family.cmake @@ -44,6 +44,7 @@ function(add_board_target BOARD_TARGET) ${SDK_DIR}/drivers/igpio/fsl_gpio.c ${SDK_DIR}/drivers/lpspi/fsl_lpspi.c ${SDK_DIR}/drivers/lpuart/fsl_lpuart.c + ${SDK_DIR}/drivers/ocotp/fsl_ocotp.c ${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_VARIANT_WITH_CORE}.c ${SDK_DIR}/devices/${MCU_VARIANT}/xip/fsl_flexspi_nor_boot.c ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c @@ -75,6 +76,7 @@ function(add_board_target BOARD_TARGET) ${SDK_DIR}/drivers/igpio ${SDK_DIR}/drivers/lpspi ${SDK_DIR}/drivers/lpuart + ${SDK_DIR}/drivers/ocotp ) update_board(${BOARD_TARGET}) diff --git a/hw/bsp/imxrt/family.mk b/hw/bsp/imxrt/family.mk index bde4c4ba6..f00afb6a4 100644 --- a/hw/bsp/imxrt/family.mk +++ b/hw/bsp/imxrt/family.mk @@ -50,7 +50,8 @@ SRC_C += \ $(SDK_DIR)/drivers/common/fsl_common.c \ $(SDK_DIR)/drivers/common/fsl_common_arm.c \ $(SDK_DIR)/drivers/igpio/fsl_gpio.c \ - $(SDK_DIR)/drivers/lpuart/fsl_lpuart.c + $(SDK_DIR)/drivers/lpuart/fsl_lpuart.c \ + $(SDK_DIR)/drivers/ocotp/fsl_ocotp.c \ # Optional drivers: only available for some mcus: rt1160, rt1170 ifneq (,$(wildcard ${TOP}/${MCU_DIR}/drivers/fsl_dcdc.c)) @@ -68,7 +69,8 @@ INC += \ $(TOP)/$(MCU_DIR)/drivers \ $(TOP)/$(SDK_DIR)/drivers/common \ $(TOP)/$(SDK_DIR)/drivers/igpio \ - $(TOP)/$(SDK_DIR)/drivers/lpuart + $(TOP)/$(SDK_DIR)/drivers/lpuart \ + $(TOP)/$(SDK_DIR)/drivers/ocotp \ SRC_S += $(MCU_DIR)/gcc/startup_$(MCU_VARIANT_WITH_CORE).S diff --git a/hw/bsp/lpc11/family.c b/hw/bsp/lpc11/family.c index bff7110b8..e75bc4919 100644 --- a/hw/bsp/lpc11/family.c +++ b/hw/bsp/lpc11/family.c @@ -90,6 +90,13 @@ void board_led_write(bool state) { Chip_GPIO_SetPinState(LPC_GPIO, LED_PORT, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + if ( max_len < 16 ) return 0; + uint32_t* id32 = (uint32_t*) (uintptr_t) id; + id32[0] = Chip_IAP_ReadUID(); + return 4; +} + uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == Chip_GPIO_GetPinState(LPC_GPIO, BUTTON_PORT, BUTTON_PIN); } diff --git a/hw/bsp/lpc11/family.cmake b/hw/bsp/lpc11/family.cmake index f17a48dd7..818600656 100644 --- a/hw/bsp/lpc11/family.cmake +++ b/hw/bsp/lpc11/family.cmake @@ -30,6 +30,7 @@ function(add_board_target BOARD_TARGET) ${SDK_DIR}/../gcc/cr_startup_lpc${LPC_FAMILY}.c ${SDK_DIR}/src/chip_${LPC_FAMILY}.c ${SDK_DIR}/src/clock_${LPC_FAMILY}.c + ${SDK_DIR}/src/iap.c ${SDK_DIR}/src/iocon_${LPC_FAMILY}.c ${SDK_DIR}/src/sysinit_${LPC_FAMILY}.c ) diff --git a/hw/bsp/lpc11/family.mk b/hw/bsp/lpc11/family.mk index 09713fd55..a3ec33768 100644 --- a/hw/bsp/lpc11/family.mk +++ b/hw/bsp/lpc11/family.mk @@ -9,13 +9,18 @@ CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_LPC11UXX \ -DCFG_TUSB_MEM_ALIGN='__attribute__((aligned(64)))' -LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs +# mcu driver cause following warnings +CFLAGS += \ + -Wno-error=incompatible-pointer-types \ + +LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs SRC_C += \ src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c \ $(MCU_DIR)/../gcc/cr_startup_lpc$(MCU_DRV).c \ $(MCU_DIR)/src/chip_$(MCU_DRV).c \ $(MCU_DIR)/src/clock_$(MCU_DRV).c \ + $(MCU_DIR)/src/iap.c \ $(MCU_DIR)/src/iocon_$(MCU_DRV).c \ $(MCU_DIR)/src/sysinit_$(MCU_DRV).c diff --git a/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h index 6f10a7ab0..d3f357576 100644 --- a/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h +++ b/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h @@ -52,6 +52,7 @@ #define configENABLE_FPU 1 #define configENABLE_TRUSTZONE 0 #define configMINIMAL_SECURE_STACK_SIZE (1024) +#define configRUN_FREERTOS_SECURE_ONLY 1 #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c index cfd5b7032..075832ea7 100644 --- a/hw/bsp/lpc55/family.c +++ b/hw/bsp/lpc55/family.c @@ -81,51 +81,85 @@ void USB1_IRQHandler(void) { } /**************************************************************** -name: BOARD_BootClockFROHF96M +name: BOARD_BootClockPLL100M outputs: -- {id: SYSTICK_clock.outFreq, value: 96 MHz} -- {id: System_clock.outFreq, value: 96 MHz} +- {id: System_clock.outFreq, value: 100 MHz} settings: -- {id: SYSCON.MAINCLKSELA.sel, value: SYSCON.fro_hf} +- {id: PLL0_Mode, value: Normal} +- {id: ANALOG_CONTROL_FRO192M_CTRL_ENDI_FRO_96M_CFG, value: Enable} +- {id: ENABLE_CLKIN_ENA, value: Enabled} +- {id: ENABLE_SYSTEM_CLK_OUT, value: Enabled} +- {id: SYSCON.MAINCLKSELB.sel, value: SYSCON.PLL0_BYPASS} +- {id: SYSCON.PLL0CLKSEL.sel, value: SYSCON.CLK_IN_EN} +- {id: SYSCON.PLL0M_MULT.scale, value: '100', locked: true} +- {id: SYSCON.PLL0N_DIV.scale, value: '4', locked: true} +- {id: SYSCON.PLL0_PDEC.scale, value: '4', locked: true} sources: -- {id: SYSCON.fro_hf.outFreq, value: 96 MHz} +- {id: ANACTRL.fro_hf.outFreq, value: 96 MHz} +- {id: SYSCON.XTAL32M.outFreq, value: 16 MHz, enabled: true} ******************************************************************/ -void BootClockFROHF96M(void) { - /*!< Set up the clock sources */ - /*!< Set up FRO */ - POWER_DisablePD(kPDRUNCFG_PD_FRO192M); /*!< Ensure FRO is on */ - CLOCK_SetupFROClocking(12000000U); /*!< Set up FRO to the 12 MHz, just for sure */ - CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12MHz first to ensure we can change voltage without - accidentally being below the voltage for current speed */ +void BOARD_BootClockPLL100M(void) +{ + /*!< Set up the clock sources */ + /*!< Configure FRO192M */ + POWER_DisablePD(kPDRUNCFG_PD_FRO192M); /*!< Ensure FRO is on */ + CLOCK_SetupFROClocking(12000000U); /*!< Set up FRO to the 12 MHz, just for sure */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12MHz first to ensure we can change the clock setting */ - CLOCK_SetupFROClocking(96000000U); /*!< Set up high frequency FRO output to selected frequency */ + CLOCK_SetupFROClocking(96000000U); /* Enable FRO HF(96MHz) output */ - POWER_SetVoltageForFreq(96000000U); /*!< Set voltage for the one of the fastest clock outputs: System clock output */ - CLOCK_SetFLASHAccessCyclesForFreq(96000000U); /*!< Set FLASH wait states for core */ + /*!< Configure XTAL32M */ + POWER_DisablePD(kPDRUNCFG_PD_XTAL32M); /* Ensure XTAL32M is powered */ + POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M); /* Ensure XTAL32M is powered */ + CLOCK_SetupExtClocking(16000000U); /* Enable clk_in clock */ + SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /* Enable clk_in from XTAL32M clock */ + ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK; /* Enable clk_in to system */ - /*!< Set up dividers */ - CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); /*!< Set AHBCLKDIV divider to value 1 */ + POWER_SetVoltageForFreq(100000000U); /*!< Set voltage for the one of the fastest clock outputs: System clock output */ + CLOCK_SetFLASHAccessCyclesForFreq(100000000U); /*!< Set FLASH wait states for core */ - /*!< Set up clock selectors - Attach clocks to the peripheries */ - CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /*!< Switch MAIN_CLK to FRO_HF */ + /*!< Set up PLL */ + CLOCK_AttachClk(kEXT_CLK_to_PLL0); /*!< Switch PLL0CLKSEL to EXT_CLK */ + POWER_DisablePD(kPDRUNCFG_PD_PLL0); /* Ensure PLL is on */ + POWER_DisablePD(kPDRUNCFG_PD_PLL0_SSCG); + const pll_setup_t pll0Setup = { + .pllctrl = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_SELI(53U) | SYSCON_PLL0CTRL_SELP(26U), + .pllndec = SYSCON_PLL0NDEC_NDIV(4U), + .pllpdec = SYSCON_PLL0PDEC_PDIV(2U), + .pllsscg = {0x0U,(SYSCON_PLL0SSCG1_MDIV_EXT(100U) | SYSCON_PLL0SSCG1_SEL_EXT_MASK)}, + .pllRate = 100000000U, + .flags = PLL_SETUPFLAG_WAITLOCK + }; + CLOCK_SetPLL0Freq(&pll0Setup); /*!< Configure PLL0 to the desired values */ - /*!< Set SystemCoreClock variable. */ - SystemCoreClock = 96000000U; + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); /*!< Set AHBCLKDIV divider to value 1 */ + + /*!< Set up clock selectors - Attach clocks to the peripheries */ + CLOCK_AttachClk(kPLL0_to_MAIN_CLK); /*!< Switch MAIN_CLK to PLL0 */ + + /*< Set SystemCoreClock variable. */ + SystemCoreClock = 100000000U; } void board_init(void) { // Enable IOCON clock CLOCK_EnableClock(kCLOCK_Iocon); - // Init 96 MHz clock - BootClockFROHF96M(); + // Init 100 MHz clock + BOARD_BootClockPLL100M(); +#if CFG_TUSB_OS == OPT_OS_NONE // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); -#if CFG_TUSB_OS == OPT_OS_FREERTOS +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + // Explicitly disable systick to prevent its ISR runs before scheduler start + SysTick->CTRL &= ~1U; + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) NVIC_SetPriority(USB0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ); + NVIC_SetPriority(USB1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ); #endif // Init all GPIO ports @@ -239,6 +273,10 @@ void board_init(void) { // phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK); // phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06); // USBPHY->TX = phytx; + + ARM_MPU_SetMemAttr(0, 0x44); // Normal memory, non-cacheable (inner and outer) + ARM_MPU_SetRegion(0, ARM_MPU_RBAR(0x40100000, ARM_MPU_SH_NON, 0, 1, 1), ARM_MPU_RLAR(0x40104000, 0)); + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk); #endif } diff --git a/hw/bsp/max32650/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/max32650/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..e5a76af85 --- /dev/null +++ b/hw/bsp/max32650/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,149 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "mxc_device.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS __NVIC_PRIO_BITS + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<-jlink` target for CMake. + +Both the Evaluation Kit and Feather boards are shipped with a CMSIS-DAP +compatible debug probe. However, at the time of writing, the necessary flashing +algorithms for OpenOCD have not yet been incorporated into the OpenOCD master +branch. To utilize the provided debug probes, please install the bundled MSDK +package which includes the appropriate OpenOCD modifications. To leverage this +OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake +target. + +### MAX32651 + +The MAX32651 features an integrated secure bootloader which requires the +application image be signed prior to flashing. Both the Makefile and CMake +scripts account for this signing automatically when building for the +MAX32651EVKIT. + +To flash the signed image, the MSDK's OpenOCD variant must be used. To flash +the MAX32651EVKIT please install the bundled MSDK, and utilize the `flash-msdk` +and `-msdk` rule and target. diff --git a/hw/bsp/max32650/boards/max32650evkit/board.cmake b/hw/bsp/max32650/boards/max32650evkit/board.cmake new file mode 100644 index 000000000..fffdcc9fb --- /dev/null +++ b/hw/bsp/max32650/boards/max32650evkit/board.cmake @@ -0,0 +1,10 @@ +# Use the standard, non-secure linker file +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32650.ld) + +function(update_board_extras TARGET) + #No extra arguments +endfunction() + +function(prepare_image TARGET_IN) + #No signing required +endfunction() diff --git a/hw/bsp/max32650/boards/max32650evkit/board.h b/hw/bsp/max32650/boards/max32650evkit/board.h new file mode 100644 index 000000000..196abdaca --- /dev/null +++ b/hw/bsp/max32650/boards/max32650evkit/board.h @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// LED +#define LED_PORT MXC_GPIO2 +#define LED_PIN MXC_GPIO_PIN_25 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 0 + +// Button +#define BUTTON_PORT MXC_GPIO2 +#define BUTTON_PIN MXC_GPIO_PIN_28 +#define BUTTON_PULL MXC_GPIO_PAD_WEAK_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for EvKit's Integrated FTDI Adapter. Pin Mux handled by the HAL +#define UART_NUM 0 + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max32650/boards/max32650evkit/board.mk b/hw/bsp/max32650/boards/max32650evkit/board.mk new file mode 100644 index 000000000..0bc210e11 --- /dev/null +++ b/hw/bsp/max32650/boards/max32650evkit/board.mk @@ -0,0 +1,2 @@ +# Use the standard, non-secure linker file +LD_FILE = $(BOARD_PATH)/max32650.ld diff --git a/hw/bsp/max32650/boards/max32650evkit/max32650.ld b/hw/bsp/max32650/boards/max32650evkit/max32650.ld new file mode 100644 index 000000000..0e56a91ec --- /dev/null +++ b/hw/bsp/max32650/boards/max32650evkit/max32650.ld @@ -0,0 +1,119 @@ +MEMORY { + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64kB ROM */ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00300000 /* 3MB flash */ + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000 /* 1MB SRAM */ +} + +SECTIONS { + .text : + { + _text = .; + KEEP(*(.isr_vector)) + *(.text*) /* program code */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + *(vtable) + *(.data*) /*read-write initialized data: initialized global variable*/ + *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */ + *(.flashprog*) /* Flash program */ + + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + _edata = ALIGN(., 4); + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > SRAM + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") +} diff --git a/hw/bsp/max32650/boards/max32650fthr/board.cmake b/hw/bsp/max32650/boards/max32650fthr/board.cmake new file mode 100644 index 000000000..fffdcc9fb --- /dev/null +++ b/hw/bsp/max32650/boards/max32650fthr/board.cmake @@ -0,0 +1,10 @@ +# Use the standard, non-secure linker file +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32650.ld) + +function(update_board_extras TARGET) + #No extra arguments +endfunction() + +function(prepare_image TARGET_IN) + #No signing required +endfunction() diff --git a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.h b/hw/bsp/max32650/boards/max32650fthr/board.h similarity index 71% rename from hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.h rename to hw/bsp/max32650/boards/max32650fthr/board.h index bc203f073..d80a8fcae 100644 --- a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.h +++ b/hw/bsp/max32650/boards/max32650fthr/board.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020, Ha Thach (tinyusb.org) + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,26 +27,31 @@ #ifndef BOARD_H_ #define BOARD_H_ +#include "gpio.h" +#include "mxc_sys.h" + #ifdef __cplusplus - extern "C" { +extern "C" { #endif -#define _PINNUM(port, pin) ((port)*32 + (pin)) - // LED -#define LED_PIN _PINNUM(1, 13) -#define LED_STATE_ON 0 +#define LED_PORT MXC_GPIO1 +#define LED_PIN MXC_GPIO_PIN_14 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIO +#define LED_STATE_ON 0 // Button -#define BUTTON_PIN _PINNUM(0, 15) -#define BUTTON_STATE_ACTIVE 0 +#define BUTTON_PORT MXC_GPIO1 +#define BUTTON_PIN MXC_GPIO_PIN_19 +#define BUTTON_PULL MXC_GPIO_PAD_WEAK_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for SWD UART Pins. Pin Mux handled by the HAL +#define UART_NUM 0 -// UART -#define UART_RX_PIN 25 -#define UART_TX_PIN 24 #ifdef __cplusplus - } +} #endif #endif /* BOARD_H_ */ diff --git a/hw/bsp/max32650/boards/max32650fthr/board.mk b/hw/bsp/max32650/boards/max32650fthr/board.mk new file mode 100644 index 000000000..0bc210e11 --- /dev/null +++ b/hw/bsp/max32650/boards/max32650fthr/board.mk @@ -0,0 +1,2 @@ +# Use the standard, non-secure linker file +LD_FILE = $(BOARD_PATH)/max32650.ld diff --git a/hw/bsp/max32650/boards/max32650fthr/max32650.ld b/hw/bsp/max32650/boards/max32650fthr/max32650.ld new file mode 100644 index 000000000..0e56a91ec --- /dev/null +++ b/hw/bsp/max32650/boards/max32650fthr/max32650.ld @@ -0,0 +1,119 @@ +MEMORY { + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64kB ROM */ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00300000 /* 3MB flash */ + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000 /* 1MB SRAM */ +} + +SECTIONS { + .text : + { + _text = .; + KEEP(*(.isr_vector)) + *(.text*) /* program code */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + *(vtable) + *(.data*) /*read-write initialized data: initialized global variable*/ + *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */ + *(.flashprog*) /* Flash program */ + + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + _edata = ALIGN(., 4); + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > SRAM + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") +} diff --git a/hw/bsp/max32650/boards/max32651evkit/board.cmake b/hw/bsp/max32650/boards/max32651evkit/board.cmake new file mode 100644 index 000000000..bd8077a42 --- /dev/null +++ b/hw/bsp/max32650/boards/max32651evkit/board.cmake @@ -0,0 +1,30 @@ +# Use the secure linker file +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32651.ld) + +function(update_board_extras TARGET) + # for the signed target, need to add the __SLA_FWK__ define + target_compile_definitions(${TARGET} PUBLIC + __SLA_FWK__ + ) +endfunction() + +function(prepare_image TARGET_IN) + #For the signed target, set up a POST_BUILD command to sign the elf file once + #created + if((WIN32) OR (MINGW) OR (MSYS)) + set(SIGN_EXE "sign_app.exe") + else() + set(SIGN_EXE "sign_app") + endif() + set(MCU_PATH "${TOP}/hw/mcu/analog/max32/") + + # Custom POST_BUILD command + add_custom_command( + TARGET ${TARGET_IN} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} $ -R .sig -O binary $/${TARGET_IN}.bin + COMMAND ${MCU_PATH}/Tools/SBT/bin/${SIGN_EXE} -c MAX32651 key_file=${MCU_PATH}/Tools/SBT/devices/MAX32651/keys/maximtestcrk.key + ca=$/${TARGET_IN}.bin sca=$/${TARGET_IN}.sbin + COMMAND ${CMAKE_OBJCOPY} $ --update-section .sig=$/${TARGET_IN}.sig + VERBATIM + ) +endfunction() diff --git a/hw/bsp/max32650/boards/max32651evkit/board.h b/hw/bsp/max32650/boards/max32651evkit/board.h new file mode 100644 index 000000000..196abdaca --- /dev/null +++ b/hw/bsp/max32650/boards/max32651evkit/board.h @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// LED +#define LED_PORT MXC_GPIO2 +#define LED_PIN MXC_GPIO_PIN_25 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 0 + +// Button +#define BUTTON_PORT MXC_GPIO2 +#define BUTTON_PIN MXC_GPIO_PIN_28 +#define BUTTON_PULL MXC_GPIO_PAD_WEAK_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for EvKit's Integrated FTDI Adapter. Pin Mux handled by the HAL +#define UART_NUM 0 + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max32650/boards/max32651evkit/board.mk b/hw/bsp/max32650/boards/max32651evkit/board.mk new file mode 100644 index 000000000..b609598c1 --- /dev/null +++ b/hw/bsp/max32650/boards/max32651evkit/board.mk @@ -0,0 +1,5 @@ +# Use the secure linker file +LD_FILE = $(BOARD_PATH)/max32651.ld + +# Let the family script know the build needs to be signed +SIGNED_BUILD := 1 diff --git a/hw/bsp/max32650/boards/max32651evkit/max32651.ld b/hw/bsp/max32650/boards/max32651evkit/max32651.ld new file mode 100644 index 000000000..3921d10f2 --- /dev/null +++ b/hw/bsp/max32650/boards/max32651evkit/max32651.ld @@ -0,0 +1,132 @@ +MEMORY { + HEADER (rx): ORIGIN = 0x10000000, LENGTH = 0x200 + FLASH (rx) : ORIGIN = 0x10000200, LENGTH = 0x002FFE00 /* 3MB flash */ + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000 /* 1MB SRAM */ +} + +/* Added Oct 9, 2018 to go to correct reset vector. */ +ENTRY(Reset_Handler) +PROVIDE( _start_SWAP = (((Reset_Handler) >> 24) | (((Reset_Handler) & 0x00FF0000) >> 8) | (((Reset_Handler) & 0x0000FF00) << 8) | ((Reset_Handler) << 24))); +PROVIDE_HIDDEN( _SLA_Size = _endimage - __end_header ); +PROVIDE( _SLA_Size_SWAP = (((_SLA_Size) >> 24) | (((_SLA_Size) & 0x00FF0000) >> 8) | (((_SLA_Size) & 0x0000FF00) << 8) | ((_SLA_Size) << 24))); + +/* Sections Definitions */ +SECTIONS { + .sb_sla_header : ALIGN(4) + { + FILL(0xFF) + KEEP(*(.sb_sla_header)) /* Header for ROM code */ + __end_header = . ; + . = ALIGN(512); + } > HEADER + + .text : + { + _text = .; + KEEP(*(.isr_vector)) + *(.text*) /* program code */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + *(.data*) /*read-write initialized data: initialized global variable*/ + *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */ + *(.flashprog*) /* Flash program */ + + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + _edata = ALIGN(., 4); + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + _enddata = LOADADDR(.data)+SIZEOF(.data); + + .sb_sla_trailer : AT(_enddata) + { + KEEP(*(.sb_sla_trailer)) + /* Align image with 16 byte boundary to conform to flash encryption block size. */ + FILL(0xDEADC0DE); + /* NOTE: The FILL and ALIGN will not work unless something is written to the section. So, we use LONG. */ + LONG(0xDEADC0DE); + . = ALIGN(16); + } > FLASH + _endimage = LOADADDR(.sb_sla_trailer)+SIZEOF(.sb_sla_trailer); + .sig : + { + KEEP(*(.sig)) + LONG(0xDEADBEEF); + + } > FLASH + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > SRAM + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") +} diff --git a/hw/bsp/max32650/family.c b/hw/bsp/max32650/family.c new file mode 100644 index 000000000..bb382cdd4 --- /dev/null +++ b/hw/bsp/max32650/family.c @@ -0,0 +1,173 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state() +#endif + +#include "gpio.h" +#include "mxc_sys.h" +#include "mxc_device.h" +#include "uart.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include "board.h" +#include "bsp/board_api.h" + + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void USB_IRQHandler(void) { + tud_int_handler(0); +} + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ +mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM); + +void board_init(void) { +#if CFG_TUSB_OS == OPT_OS_NONE + // 1ms tick timer + SysTick_Config(SystemCoreClock / 1000); +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); +#endif + mxc_gpio_cfg_t gpioConfig; + + // LED + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_OUT; + gpioConfig.mask = LED_PIN; + gpioConfig.pad = MXC_GPIO_PAD_NONE; + gpioConfig.port = LED_PORT; + gpioConfig.vssel = LED_VDDIO; + MXC_GPIO_Config(&gpioConfig); + board_led_write(false); + + // Button + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_IN; + gpioConfig.mask = BUTTON_PIN; + gpioConfig.pad = BUTTON_PULL; + gpioConfig.port = BUTTON_PORT; + gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO; + MXC_GPIO_Config(&gpioConfig); + + // UART + MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE); + + //USB + // Startup the HIRC96M clock if it's not on already + if (!(MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_HIRC96_EN)) { + MXC_GCR->clk_ctrl |= MXC_F_GCR_CLK_CTRL_HIRC96_EN; + MXC_SYS_Clock_Timeout(MXC_F_GCR_CLK_CTRL_HIRC96_RDY); + } + + MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB); + MXC_SYS_Reset_Periph(MXC_SYS_RESET_USB); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#if LED_STATE_ON + state = !state; +#endif + if (state) { + MXC_GPIO_OutClr(LED_PORT, LED_PIN); + } else { + MXC_GPIO_OutSet(LED_PORT, LED_PIN); + } +} + +uint32_t board_button_read(void) { + uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0; + return BUTTON_STATE_ACTIVE == state; +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + uint8_t hw_id[13];//USN Buffer + MXC_SYS_GetUSN(hw_id, 13); + + size_t act_len = TU_MIN(max_len, 13); + memcpy(id, hw_id, act_len); + return act_len; +} + +int board_uart_read(uint8_t *buf, int len) { + int uart_val; + int act_len = 0; + + while (act_len < len) { + if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) { + break; + } else { + *buf++ = (uint8_t) uart_val; + act_len++; + } + } + return act_len; +} + +int board_uart_write(void const *buf, int len) { + int act_len = 0; + const uint8_t *ch_ptr = (const uint8_t *) buf; + while (act_len < len) { + MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++); + act_len++; + } + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +void SysTick_Handler(void) { + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} +#endif + +void HardFault_Handler(void) { + __asm("BKPT #0\n"); +} + +// Required by __libc_init_array in startup code if we are compiling using +// -nostdlib/-nostartfiles. +void _init(void) { +} diff --git a/hw/bsp/max32650/family.cmake b/hw/bsp/max32650/family.cmake new file mode 100644 index 000000000..48853b92c --- /dev/null +++ b/hw/bsp/max32650/family.cmake @@ -0,0 +1,169 @@ +include_guard() + +set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers) +set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS) +set(CMSIS_5 ${TOP}/lib/CMSIS_5) + +# include board specific information and functions +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# Get the linker file +set(LD_FILE_Clang ${LD_FILE_GNU}) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR cortex-m4 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) +set(JLINK_DEVICE max32650) +set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32650.cfg") + +set(FAMILY_MCUS MAX32650 CACHE INTERNAL "") + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + TARGET=MAX32650 + TARGET_REV=0x4131 + MXC_ASSERT_ENABLE + MAX32650 + IAR_PRAGMAS=0 + CFG_TUSB_MCU=OPT_MCU_MAX32650 + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) + + # Run any board specific updates + update_board_extras(${TARGET}) +endfunction() + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif () + + # Startup & Linker script + set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/GCC/startup_max32650.S) + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + + set(PERIPH_SRC ${MAX32_PERIPH}/Source) + add_library(${BOARD_TARGET} STATIC + ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/heap.c + ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/header_MAX32650.c + ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/system_max32650.c + ${PERIPH_SRC}/SYS/mxc_assert.c + ${PERIPH_SRC}/SYS/mxc_delay.c + ${PERIPH_SRC}/SYS/mxc_lock.c + ${PERIPH_SRC}/SYS/nvic_table.c + ${PERIPH_SRC}/SYS/pins_me10.c + ${PERIPH_SRC}/SYS/sys_me10.c + ${PERIPH_SRC}/TPU/tpu_me10.c + ${PERIPH_SRC}/TPU/tpu_reva.c + ${PERIPH_SRC}/FLC/flc_common.c + ${PERIPH_SRC}/FLC/flc_me10.c + ${PERIPH_SRC}/FLC/flc_reva.c + ${PERIPH_SRC}/GPIO/gpio_common.c + ${PERIPH_SRC}/GPIO/gpio_me10.c + ${PERIPH_SRC}/GPIO/gpio_reva.c + ${PERIPH_SRC}/ICC/icc_me10.c + ${PERIPH_SRC}/ICC/icc_reva.c + ${PERIPH_SRC}/ICC/icc_common.c + ${PERIPH_SRC}/UART/uart_common.c + ${PERIPH_SRC}/UART/uart_me10.c + ${PERIPH_SRC}/UART/uart_reva.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${MAX32_CMSIS}/Include + ${MAX32_CMSIS}/Device/Maxim/MAX32650/Include + ${MAX32_PERIPH}/Include/MAX32650 + ${PERIPH_SRC}/SYS + ${PERIPH_SRC}/GPIO + ${PERIPH_SRC}/TPU + ${PERIPH_SRC}/ICC + ${PERIPH_SRC}/FLC + ${PERIPH_SRC}/UART + ) + + target_compile_options(${BOARD_TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + -u sb_header #Needed when linking libraries to not lose the Signing header + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_Clang}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_MAX32650 ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/mentor/musb/dcd_musb.c + ) + target_compile_options(${TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + target_compile_options(${TARGET}-tinyusb PRIVATE + -Wno-error=strict-prototypes + ) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_flash_jlink(${TARGET}) + family_flash_openocd_adi(${TARGET}) + + # Add the optional MSDK OpenOCD flashing + family_flash_msdk(${TARGET}) +endfunction() + +function(family_flash_msdk TARGET) + # Prepare the image (signed) if the board requires it + prepare_image(${TARGET}) + + set(MAXIM_PATH "$ENV{MAXIM_PATH}") + add_custom_target(${TARGET}-msdk + DEPENDS ${TARGET} + COMMAND ${MAXIM_PATH}/Tools/OpenOCD/openocd -s ${MAXIM_PATH}/Tools/OpenOCD/scripts + -f interface/cmsis-dap.cfg -f target/max32650.cfg + -c "program $ verify; init; reset; exit" + VERBATIM + ) +endfunction() diff --git a/hw/bsp/max32650/family.mk b/hw/bsp/max32650/family.mk new file mode 100644 index 000000000..d2fc293e4 --- /dev/null +++ b/hw/bsp/max32650/family.mk @@ -0,0 +1,140 @@ +DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32 + +# Important locations in the hw support for MCU +MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS +MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers + +# Add any board specific make rules +include $(TOP)/$(BOARD_PATH)/board.mk + +CPU_CORE ?= cortex-m4 +PORT ?= 0 + +# GCC +SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/GCC/startup_max32650.S + +# -------------- +# Compiler Flags +# -------------- +# Flags for the MAX32650/1/2 SDK +CFLAGS += -DTARGET=MAX32650 \ + -DTARGET_REV=0x4131 \ + -DMXC_ASSERT_ENABLE \ + -DMAX32650 \ + -DIAR_PRAGMAS=0 + +# Flags for TUSB features +CFLAGS += \ + -DCFG_TUSB_MCU=OPT_MCU_MAX32650 \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + +# mcu driver cause following warnings +CFLAGS += -Wno-error=strict-prototypes \ + -Wno-error=unused-parameter \ + -Wno-error=cast-align \ + -Wno-error=cast-qual \ + -Wno-error=sign-compare + +LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs + +# Configure the flash rule. By default, use JLink. +SIGNED_BUILD ?= 0 +DEFAULT_FLASH = flash-jlink + +# If the applications needs to be signed (for the MAX32651), sign it first and +# then need to use MSDK's OpenOCD to flash it +# Also need to include the __SLA_FWK__ define to enable the signed header into +# memory +ifeq ($(SIGNED_BUILD), 1) +# Extra definitions to build for the secure part +CFLAGS += -D__SLA_FWK__ +DEFAULT_FLASH := sign-build flash-msdk +endif + +# For flash-jlink target +JLINK_DEVICE = max32650 + +# Configure the flash rule +flash: $(DEFAULT_FLASH) + +# ----------------- +# Sources & Include +# ----------------- +PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source +SRC_C += \ + src/portable/mentor/musb/dcd_musb.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/heap.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/system_max32650.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/header_MAX32650.c \ + $(PERIPH_SRC)/SYS/mxc_assert.c \ + $(PERIPH_SRC)/SYS/mxc_delay.c \ + $(PERIPH_SRC)/SYS/mxc_lock.c \ + $(PERIPH_SRC)/SYS/nvic_table.c \ + $(PERIPH_SRC)/SYS/pins_me10.c \ + $(PERIPH_SRC)/SYS/sys_me10.c \ + $(PERIPH_SRC)/FLC/flc_common.c \ + $(PERIPH_SRC)/FLC/flc_me10.c \ + $(PERIPH_SRC)/FLC/flc_reva.c \ + $(PERIPH_SRC)/GPIO/gpio_common.c \ + $(PERIPH_SRC)/GPIO/gpio_me10.c \ + $(PERIPH_SRC)/GPIO/gpio_reva.c \ + $(PERIPH_SRC)/ICC/icc_me10.c \ + $(PERIPH_SRC)/ICC/icc_reva.c \ + $(PERIPH_SRC)/ICC/icc_common.c \ + $(PERIPH_SRC)/TPU/tpu_me10.c \ + $(PERIPH_SRC)/TPU/tpu_reva.c \ + $(PERIPH_SRC)/UART/uart_common.c \ + $(PERIPH_SRC)/UART/uart_me10.c \ + $(PERIPH_SRC)/UART/uart_reva.c \ + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MAX32_CMSIS)/Include \ + $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32650/Include \ + $(TOP)/$(MAX32_PERIPH)/Include/MAX32650 \ + $(PERIPH_SRC)/SYS \ + $(PERIPH_SRC)/GPIO \ + $(PERIPH_SRC)/ICC \ + $(PERIPH_SRC)/FLC \ + $(PERIPH_SRC)/TPU \ + $(PERIPH_SRC)/UART + + +# The MAX32651EVKIT is pin for pin identical to the MAX32650EVKIT, however the +# MAX32651 has a secure bootloader which requires the image to be signed before +# loading into flash. All MAX32651EVKIT's have the same key for evaluation +# purposes, so create a special flash rule to sign the binary and flash using +# the MSDK. +MCU_PATH = $(TOP)/hw/mcu/analog/max32/ +# Assume no extension for sign utility +SIGN_EXE = sign_app +ifeq ($(OS), Windows_NT) +# Must use .exe extension on Windows, since the binaries +# for Linux may live in the same place. +SIGN_EXE := sign_app.exe +else +UNAME = $(shell uname -s) +ifneq ($(findstring MSYS_NT,$(UNAME)),) +# Must also use .exe extension for MSYS2 +SIGN_EXE := sign_app.exe +endif +endif + +# Rule to sign the build. This will in-place modify the existing .elf file +# an populate the .sig section with the signature value +sign-build: $(BUILD)/$(PROJECT).elf + $(OBJCOPY) $(BUILD)/$(PROJECT).elf -R .sig -O binary $(BUILD)/$(PROJECT).bin + $(MCU_PATH)/Tools/SBT/bin/$(SIGN_EXE) -c MAX32651 \ + key_file="$(MCU_PATH)/Tools/SBT/devices/MAX32651/keys/maximtestcrk.key" \ + ca=$(BUILD)/$(PROJECT).bin sca=$(BUILD)/$(PROJECT).sbin + $(OBJCOPY) $(BUILD)/$(PROJECT).elf --update-section .sig=$(BUILD)/$(PROJECT).sig + +# Optional flash option when running within an installed MSDK to use OpenOCD +# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated. +# If the MSDK is installed, flash-msdk can be run to utilize the the modified +# openocd with the algorithms +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +flash-msdk: $(BUILD)/$(PROJECT).elf + $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \ + -f interface/cmsis-dap.cfg -f target/max32650.cfg \ + -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit" diff --git a/hw/bsp/max32666/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/max32666/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..e5a76af85 --- /dev/null +++ b/hw/bsp/max32666/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,149 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "mxc_device.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS __NVIC_PRIO_BITS + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<-jlink` target for CMake. + +Both the Evaluation Kit and Feather boards are shipped with a CMSIS-DAP +compatible debug probe. However, at the time of writing, the necessary flashing +algorithms for OpenOCD have not yet been incorporated into the OpenOCD master +branch. To utilize the provided debug probes, please install the bundled MSDK +package which includes the appropriate OpenOCD modifications. To leverage this +OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake +target. diff --git a/hw/bsp/max32666/boards/max32666evkit/board.cmake b/hw/bsp/max32666/boards/max32666evkit/board.cmake new file mode 100644 index 000000000..9dc6962eb --- /dev/null +++ b/hw/bsp/max32666/boards/max32666evkit/board.cmake @@ -0,0 +1 @@ +# Nothing to be done at the board level diff --git a/hw/bsp/max32666/boards/max32666evkit/board.h b/hw/bsp/max32666/boards/max32666evkit/board.h new file mode 100644 index 000000000..0ab1483b8 --- /dev/null +++ b/hw/bsp/max32666/boards/max32666evkit/board.h @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// LED +#define LED_PORT MXC_GPIO1 +#define LED_PIN MXC_GPIO_PIN_14 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 0 + +// Button +#define BUTTON_PORT MXC_GPIO1 +#define BUTTON_PIN MXC_GPIO_PIN_6 +#define BUTTON_PULL MXC_GPIO_PAD_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for EvKit's Integrated FTDI Adapter. Pin Mux handled by the HAL +#define UART_NUM 1 +#define UART_MAP MAP_A + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max32666/boards/max32666evkit/board.mk b/hw/bsp/max32666/boards/max32666evkit/board.mk new file mode 100644 index 000000000..a813a5327 --- /dev/null +++ b/hw/bsp/max32666/boards/max32666evkit/board.mk @@ -0,0 +1 @@ +# No specific build requirements for the board. diff --git a/hw/bsp/max32666/boards/max32666fthr/board.cmake b/hw/bsp/max32666/boards/max32666fthr/board.cmake new file mode 100644 index 000000000..9dc6962eb --- /dev/null +++ b/hw/bsp/max32666/boards/max32666fthr/board.cmake @@ -0,0 +1 @@ +# Nothing to be done at the board level diff --git a/hw/bsp/max32666/boards/max32666fthr/board.h b/hw/bsp/max32666/boards/max32666fthr/board.h new file mode 100644 index 000000000..c719b748a --- /dev/null +++ b/hw/bsp/max32666/boards/max32666fthr/board.h @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// LED +#define LED_PORT MXC_GPIO0 +#define LED_PIN MXC_GPIO_PIN_29 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 0 + +// Button +#define BUTTON_PORT MXC_GPIO1 +#define BUTTON_PIN MXC_GPIO_PIN_10 +#define BUTTON_PULL MXC_GPIO_PAD_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for UART on SWD. Pin Mux handled by the HAL +#define UART_NUM 1 +#define UART_MAP MAP_B + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max32666/boards/max32666fthr/board.mk b/hw/bsp/max32666/boards/max32666fthr/board.mk new file mode 100644 index 000000000..a813a5327 --- /dev/null +++ b/hw/bsp/max32666/boards/max32666fthr/board.mk @@ -0,0 +1 @@ +# No specific build requirements for the board. diff --git a/hw/bsp/max32666/family.c b/hw/bsp/max32666/family.c new file mode 100644 index 000000000..f96393fe1 --- /dev/null +++ b/hw/bsp/max32666/family.c @@ -0,0 +1,173 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state() +#endif + +#include "gpio.h" +#include "mxc_sys.h" +#include "mcr_regs.h" +#include "mxc_device.h" +#include "uart.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include "board.h" +#include "bsp/board_api.h" + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void USB_IRQHandler(void) { + tud_int_handler(0); +} + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ +mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM); + +void board_init(void) { +#if CFG_TUSB_OS == OPT_OS_NONE + // 1ms tick timer + SysTick_Config(SystemCoreClock / 1000); +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); +#endif + mxc_gpio_cfg_t gpioConfig; + + // LED + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_OUT; + gpioConfig.mask = LED_PIN; + gpioConfig.pad = MXC_GPIO_PAD_NONE; + gpioConfig.port = LED_PORT; + gpioConfig.vssel = LED_VDDIO; + MXC_GPIO_Config(&gpioConfig); + board_led_write(false); + + // Button + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_IN; + gpioConfig.mask = BUTTON_PIN; + gpioConfig.pad = BUTTON_PULL; + gpioConfig.port = BUTTON_PORT; + gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO; + MXC_GPIO_Config(&gpioConfig); + + // UART + MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, UART_MAP); + + //USB + // Startup the HIRC96M clock if it's not on already + if (!(MXC_GCR->clkcn & MXC_F_GCR_CLKCN_HIRC96M_EN)) { + MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC96M_EN; + } + + MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB); + MXC_SYS_Reset_Periph(MXC_SYS_RESET_USB); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#if LED_STATE_ON + state = !state; +#endif + if (state) { + MXC_GPIO_OutClr(LED_PORT, LED_PIN); + } else { + MXC_GPIO_OutSet(LED_PORT, LED_PIN); + } +} + +uint32_t board_button_read(void) { + uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0; + return BUTTON_STATE_ACTIVE == state; +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer + /* All other 2nd parameter is optional checksum buffer */ + MXC_SYS_GetUSN(hw_id, NULL); + + size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN); + memcpy(id, hw_id, act_len); + return act_len; +} + +int board_uart_read(uint8_t *buf, int len) { + int uart_val; + int act_len = 0; + + while (act_len < len) { + if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) { + break; + } else { + *buf++ = (uint8_t) uart_val; + act_len++; + } + } + return act_len; +} + +int board_uart_write(void const *buf, int len) { + int act_len = 0; + const uint8_t *ch_ptr = (const uint8_t *) buf; + while (act_len < len) { + MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++); + act_len++; + } + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +void SysTick_Handler(void) { + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} +#endif + +void HardFault_Handler(void) { + __asm("BKPT #0\n"); +} + +// Required by __libc_init_array in startup code if we are compiling using +// -nostdlib/-nostartfiles. +void _init(void) { +} diff --git a/hw/bsp/max32666/family.cmake b/hw/bsp/max32666/family.cmake new file mode 100644 index 000000000..fb8c32295 --- /dev/null +++ b/hw/bsp/max32666/family.cmake @@ -0,0 +1,147 @@ +include_guard() + +set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers) +set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS) +set(CMSIS_5 ${TOP}/lib/CMSIS_5) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# Get the linker file from current location (family) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32666.ld) +set(LD_FILE_Clang ${LD_FILE_GNU}) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR cortex-m4 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) +set(JLINK_DEVICE max32666) +set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32665.cfg") + +set(FAMILY_MCUS MAX32666 CACHE INTERNAL "") + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + TARGET=MAX32665 + TARGET_REV=0x4131 + MXC_ASSERT_ENABLE + MAX32665 + IAR_PRAGMAS=0 + CFG_TUSB_MCU=OPT_MCU_MAX32666 + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) +endfunction() + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif () + + # Startup & Linker script + set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/GCC/startup_max32665.S) + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + + set(PERIPH_SRC ${MAX32_PERIPH}/Source) + add_library(${BOARD_TARGET} STATIC + ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/heap.c + ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/system_max32665.c + ${PERIPH_SRC}/SYS/mxc_assert.c + ${PERIPH_SRC}/SYS/mxc_delay.c + ${PERIPH_SRC}/SYS/mxc_lock.c + ${PERIPH_SRC}/SYS/nvic_table.c + ${PERIPH_SRC}/SYS/pins_me14.c + ${PERIPH_SRC}/SYS/sys_me14.c + ${PERIPH_SRC}/TPU/tpu_me14.c + ${PERIPH_SRC}/TPU/tpu_reva.c + ${PERIPH_SRC}/FLC/flc_common.c + ${PERIPH_SRC}/FLC/flc_me14.c + ${PERIPH_SRC}/FLC/flc_reva.c + ${PERIPH_SRC}/GPIO/gpio_common.c + ${PERIPH_SRC}/GPIO/gpio_me14.c + ${PERIPH_SRC}/GPIO/gpio_reva.c + ${PERIPH_SRC}/ICC/icc_me14.c + ${PERIPH_SRC}/ICC/icc_reva.c + ${PERIPH_SRC}/UART/uart_common.c + ${PERIPH_SRC}/UART/uart_me14.c + ${PERIPH_SRC}/UART/uart_reva.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${MAX32_CMSIS}/Include + ${MAX32_CMSIS}/Device/Maxim/MAX32665/Include + ${MAX32_PERIPH}/Include/MAX32665 + ${PERIPH_SRC}/SYS + ${PERIPH_SRC}/GPIO + ${PERIPH_SRC}/TPU + ${PERIPH_SRC}/ICC + ${PERIPH_SRC}/FLC + ${PERIPH_SRC}/UART + ) + + target_compile_options(${BOARD_TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_Clang}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_MAX32666 ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/mentor/musb/dcd_musb.c + ) + target_compile_options(${TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + target_compile_options(${TARGET}-tinyusb PRIVATE + -Wno-error=strict-prototypes + ) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_flash_jlink(${TARGET}) + family_flash_openocd_adi(${TARGET}) +endfunction() diff --git a/hw/bsp/max32666/family.mk b/hw/bsp/max32666/family.mk new file mode 100644 index 000000000..b4f7d1e57 --- /dev/null +++ b/hw/bsp/max32666/family.mk @@ -0,0 +1,93 @@ +DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32 + +# Important locations in the hw support for MCU +MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS +MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers + +# Add any board specific make rules +include $(TOP)/$(BOARD_PATH)/board.mk + +CPU_CORE ?= cortex-m4 +PORT ?= 0 + +# GCC +SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/GCC/startup_max32665.S +LD_FILE = $(FAMILY_PATH)/max32666.ld + +# -------------- +# Compiler Flags +# -------------- +# Flags for the MAX32665/6 SDK +CFLAGS += -DTARGET=MAX32665 \ + -DTARGET_REV=0x4131 \ + -DMXC_ASSERT_ENABLE \ + -DMAX32665 \ + -DIAR_PRAGMAS=0 + +# Flags for TUSB features +CFLAGS += \ + -DCFG_TUSB_MCU=OPT_MCU_MAX32666 \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + +# mcu driver cause following warnings +CFLAGS += -Wno-error=strict-prototypes \ + -Wno-error=unused-parameter \ + -Wno-error=cast-align \ + -Wno-error=cast-qual +LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs + +# For flash-jlink target +JLINK_DEVICE = max32666 + +# flash target using Jlink by default +flash: flash-jlink + +# Optional flash option when running within an installed MSDK to use OpenOCD +# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated. +# If the MSDK is installed, flash-msdk can be run to utilize the the modified +# openocd with the algorithms +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +flash-msdk: $(BUILD)/$(PROJECT).elf + $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \ + -f interface/cmsis-dap.cfg -f target/max32665.cfg \ + -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit" + +# ----------------- +# Sources & Include +# ----------------- +PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source +SRC_C += \ + src/portable/mentor/musb/dcd_musb.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/heap.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/system_max32665.c \ + $(PERIPH_SRC)/SYS/mxc_assert.c \ + $(PERIPH_SRC)/SYS/mxc_delay.c \ + $(PERIPH_SRC)/SYS/mxc_lock.c \ + $(PERIPH_SRC)/SYS/nvic_table.c \ + $(PERIPH_SRC)/SYS/pins_me14.c \ + $(PERIPH_SRC)/SYS/sys_me14.c \ + $(PERIPH_SRC)/FLC/flc_common.c \ + $(PERIPH_SRC)/FLC/flc_me14.c \ + $(PERIPH_SRC)/FLC/flc_reva.c \ + $(PERIPH_SRC)/GPIO/gpio_common.c \ + $(PERIPH_SRC)/GPIO/gpio_me14.c \ + $(PERIPH_SRC)/GPIO/gpio_reva.c \ + $(PERIPH_SRC)/ICC/icc_me14.c \ + $(PERIPH_SRC)/ICC/icc_reva.c \ + $(PERIPH_SRC)/TPU/tpu_me14.c \ + $(PERIPH_SRC)/TPU/tpu_reva.c \ + $(PERIPH_SRC)/UART/uart_common.c \ + $(PERIPH_SRC)/UART/uart_me14.c \ + $(PERIPH_SRC)/UART/uart_reva.c \ + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MAX32_CMSIS)/Include \ + $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32665/Include \ + $(TOP)/$(MAX32_PERIPH)/Include/MAX32665 \ + $(PERIPH_SRC)/SYS \ + $(PERIPH_SRC)/GPIO \ + $(PERIPH_SRC)/ICC \ + $(PERIPH_SRC)/FLC \ + $(PERIPH_SRC)/TPU \ + $(PERIPH_SRC)/UART diff --git a/hw/bsp/max32666/max32666.ld b/hw/bsp/max32666/max32666.ld new file mode 100644 index 000000000..06c124247 --- /dev/null +++ b/hw/bsp/max32666/max32666.ld @@ -0,0 +1,135 @@ +/* SPID and SPIX Sections here are maximum possible sizes */ +/* If used, they should be adjusted for the external Flash/RAM size */ +MEMORY { + + SPIX (rx) : ORIGIN = 0x08000000, LENGTH = 0x08000000 + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00100000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0008C000 + SPID (rw) : ORIGIN = 0x80000000, LENGTH = 512M +} + +/* Sections Definitions */ +SECTIONS { + .text : + { + _text = .; + KEEP(*(.isr_vector)) + *(.text*) /* program code */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + /* This section will keep the SPIX data until loaded into the external device */ + /* Upon initialization of SPIX (user code needs to do this) */ + .xip_section : + { + KEEP(*(.xip_section*)) + } > SPIX AT>FLASH + + __load_start_xip = LOADADDR(.xip_section); + __load_length_xip = SIZEOF(.xip_section); + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + *(vtable) + *(.data*) /*read-write initialized data: initialized global variable*/ + *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */ + *(.flashprog*) /* Flash program */ + + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + _edata = ALIGN(., 4); + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + /* Setup the stack for Core 1, it will only be used if the user code + * includes a definition of Stack_Size_Core1, which defines the space + * reserved above the main core's stack for core 1's stack */ + + __StackTop_Core1 = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit_Core1 = DEFINED(Stack_Size_Core1) ? __StackTop_Core1 - Stack_Size_Core1 : __StackTop_Core1; + + /* Set stack top to end of RAM, and stack limit move down by Stack_Size. + * If core 1 is used, set the stack to the bottom of Core 1's stack region */ + + __StackTop = DEFINED(Stack_Size_Core1) ? __StackLimit_Core1 : ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - Stack_Size; + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack(s) exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") +} diff --git a/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..e5a76af85 --- /dev/null +++ b/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,149 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "mxc_device.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS __NVIC_PRIO_BITS + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<-jlink` target for CMake. + +Both the Evaluation Kit and APARD boards are shipped with a CMSIS-DAP +compatible debug probe. However, at the time of writing, the necessary flashing +algorithms for OpenOCD have not yet been incorporated into the OpenOCD master +branch. To utilize the provided debug probes, please install the bundled MSDK +package which includes the appropriate OpenOCD modifications. To leverage this +OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake +target. diff --git a/hw/bsp/max32690/boards/apard32690/board.cmake b/hw/bsp/max32690/boards/apard32690/board.cmake new file mode 100644 index 000000000..9dc6962eb --- /dev/null +++ b/hw/bsp/max32690/boards/apard32690/board.cmake @@ -0,0 +1 @@ +# Nothing to be done at the board level diff --git a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.h b/hw/bsp/max32690/boards/apard32690/board.h similarity index 72% rename from hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.h rename to hw/bsp/max32690/boards/apard32690/board.h index 072cb2714..f94097ca9 100644 --- a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.h +++ b/hw/bsp/max32690/boards/apard32690/board.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020, Ha Thach (tinyusb.org) + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,26 +27,30 @@ #ifndef BOARD_H_ #define BOARD_H_ +#include "gpio.h" +#include "mxc_sys.h" + #ifdef __cplusplus - extern "C" { +extern "C" { #endif -#define _PINNUM(port, pin) ((port)*32 + (pin)) - // LED -#define LED_PIN _PINNUM(0, 23) -#define LED_STATE_ON 0 +#define LED_PORT MXC_GPIO2 +#define LED_PIN MXC_GPIO_PIN_1 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 1 // Button -#define BUTTON_PIN _PINNUM(0, 18) -#define BUTTON_STATE_ACTIVE 0 +#define BUTTON_PORT MXC_GPIO1 +#define BUTTON_PIN MXC_GPIO_PIN_27 +#define BUTTON_PULL MXC_GPIO_PAD_NONE +#define BUTTON_STATE_ACTIVE 1 -// UART -#define UART_RX_PIN 2 -#define UART_TX_PIN 3 +// UART Enable for UART on ARM SWD Connector +#define UART_NUM 0 #ifdef __cplusplus - } +} #endif #endif /* BOARD_H_ */ diff --git a/hw/bsp/max32690/boards/apard32690/board.mk b/hw/bsp/max32690/boards/apard32690/board.mk new file mode 100644 index 000000000..a813a5327 --- /dev/null +++ b/hw/bsp/max32690/boards/apard32690/board.mk @@ -0,0 +1 @@ +# No specific build requirements for the board. diff --git a/hw/bsp/max32690/boards/max32690evkit/board.cmake b/hw/bsp/max32690/boards/max32690evkit/board.cmake new file mode 100644 index 000000000..9dc6962eb --- /dev/null +++ b/hw/bsp/max32690/boards/max32690evkit/board.cmake @@ -0,0 +1 @@ +# Nothing to be done at the board level diff --git a/src/portable/mentor/musb/musb_tm4c.h b/hw/bsp/max32690/boards/max32690evkit/board.h similarity index 67% rename from src/portable/mentor/musb/musb_tm4c.h rename to hw/bsp/max32690/boards/max32690evkit/board.h index 65a1751b0..05d60f220 100644 --- a/src/portable/mentor/musb/musb_tm4c.h +++ b/hw/bsp/max32690/boards/max32690evkit/board.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2021, Ha Thach (tinyusb.org) + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,22 +24,33 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MUSB_TM4C_H_ -#define _TUSB_MUSB_TM4C_H_ +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif -#if CFG_TUSB_MCU == OPT_MCU_TM4C123 - #include "TM4C123.h" -//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129 -#else - #error "Unsupported MCUs" -#endif +// LED +#define LED_PORT MXC_GPIO0 +#define LED_PIN MXC_GPIO_PIN_14 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 0 + +// Button +#define BUTTON_PORT MXC_GPIO4 +#define BUTTON_PIN MXC_GPIO_PIN_0 +#define BUTTON_PULL MXC_GPIO_PAD_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for EvKit's Integrated FTDI Adapter. Pin Mux handled by the HAL +#define UART_NUM 2 #ifdef __cplusplus - } +} #endif -#endif +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max32690/boards/max32690evkit/board.mk b/hw/bsp/max32690/boards/max32690evkit/board.mk new file mode 100644 index 000000000..a813a5327 --- /dev/null +++ b/hw/bsp/max32690/boards/max32690evkit/board.mk @@ -0,0 +1 @@ +# No specific build requirements for the board. diff --git a/hw/bsp/max32690/family.c b/hw/bsp/max32690/family.c new file mode 100644 index 000000000..2418168d4 --- /dev/null +++ b/hw/bsp/max32690/family.c @@ -0,0 +1,171 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state() +#endif + +#include "gpio.h" +#include "mxc_sys.h" +#include "mcr_regs.h" +#include "mxc_device.h" +#include "uart.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include "board.h" +#include "bsp/board_api.h" + + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void USB_IRQHandler(void) { + tud_int_handler(0); +} + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ +mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM); + +void board_init(void) { +#if CFG_TUSB_OS == OPT_OS_NONE + // 1ms tick timer + SysTick_Config(SystemCoreClock / 1000); +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); +#endif + mxc_gpio_cfg_t gpioConfig; + + // LED + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_OUT; + gpioConfig.mask = LED_PIN; + gpioConfig.pad = MXC_GPIO_PAD_NONE; + gpioConfig.port = LED_PORT; + gpioConfig.vssel = LED_VDDIO; + MXC_GPIO_Config(&gpioConfig); + board_led_write(false); + + // Button + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_IN; + gpioConfig.mask = BUTTON_PIN; + gpioConfig.pad = BUTTON_PULL; + gpioConfig.port = BUTTON_PORT; + gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO; + MXC_GPIO_Config(&gpioConfig); + + // UART + MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, MXC_UART_IBRO_CLK); + + //USB + MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_IPO); + MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN; + MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB); + MXC_SYS_Reset_Periph(MXC_SYS_RESET0_USB); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#if LED_STATE_ON + state = !state; +#endif + if (state) { + MXC_GPIO_OutClr(LED_PORT, LED_PIN); + } else { + MXC_GPIO_OutSet(LED_PORT, LED_PIN); + } +} + +uint32_t board_button_read(void) { + uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0; + return BUTTON_STATE_ACTIVE == state; +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer + /* All other 2nd parameter is optional checksum buffer */ + MXC_SYS_GetUSN(hw_id, NULL); + + size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN); + memcpy(id, hw_id, act_len); + return act_len; +} + +int board_uart_read(uint8_t *buf, int len) { + int uart_val; + int act_len = 0; + + while (act_len < len) { + if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) { + break; + } else { + *buf++ = (uint8_t) uart_val; + act_len++; + } + } + return act_len; +} + +int board_uart_write(void const *buf, int len) { + int act_len = 0; + const uint8_t *ch_ptr = (const uint8_t *) buf; + while (act_len < len) { + MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++); + act_len++; + } + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +void SysTick_Handler(void) { + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} +#endif + +void HardFault_Handler(void) { + __asm("BKPT #0\n"); +} + +// Required by __libc_init_array in startup code if we are compiling using +// -nostdlib/-nostartfiles. +void _init(void) { +} diff --git a/hw/bsp/max32690/family.cmake b/hw/bsp/max32690/family.cmake new file mode 100644 index 000000000..96dcfedff --- /dev/null +++ b/hw/bsp/max32690/family.cmake @@ -0,0 +1,152 @@ +include_guard() + +set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers) +set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS) +set(CMSIS_5 ${TOP}/lib/CMSIS_5) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# Get the linker file from current location (family) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32690.ld) +set(LD_FILE_Clang ${LD_FILE_GNU}) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR cortex-m4 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) +set(JLINK_DEVICE max32690) +set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32690.cfg") + +set(FAMILY_MCUS MAX32690 CACHE INTERNAL "") + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + TARGET=MAX32690 + TARGET_REV=0x4131 + MXC_ASSERT_ENABLE + MAX32690 + FLASH_ORIGIN=0x10000000 + FLASH_SIZE=0x340000 + SRAM_ORIGIN=0x20000000 + SRAM_SIZE=0x100000 + IAR_PRAGMAS=0 + CFG_TUSB_MCU=OPT_MCU_MAX32690 + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) +endfunction() + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif () + + # Startup & Linker script + set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/GCC/startup_max32690.S) + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + + set(PERIPH_SRC ${MAX32_PERIPH}/Source) + add_library(${BOARD_TARGET} STATIC + ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/heap.c + ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/system_max32690.c + ${PERIPH_SRC}/SYS/mxc_assert.c + ${PERIPH_SRC}/SYS/mxc_delay.c + ${PERIPH_SRC}/SYS/mxc_lock.c + ${PERIPH_SRC}/SYS/nvic_table.c + ${PERIPH_SRC}/SYS/pins_me18.c + ${PERIPH_SRC}/SYS/sys_me18.c + ${PERIPH_SRC}/CTB/ctb_me18.c + ${PERIPH_SRC}/CTB/ctb_reva.c + ${PERIPH_SRC}/CTB/ctb_common.c + ${PERIPH_SRC}/FLC/flc_common.c + ${PERIPH_SRC}/FLC/flc_me18.c + ${PERIPH_SRC}/FLC/flc_reva.c + ${PERIPH_SRC}/GPIO/gpio_common.c + ${PERIPH_SRC}/GPIO/gpio_me18.c + ${PERIPH_SRC}/GPIO/gpio_reva.c + ${PERIPH_SRC}/ICC/icc_me18.c + ${PERIPH_SRC}/ICC/icc_reva.c + ${PERIPH_SRC}/UART/uart_common.c + ${PERIPH_SRC}/UART/uart_me18.c + ${PERIPH_SRC}/UART/uart_revb.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${MAX32_CMSIS}/Include + ${MAX32_CMSIS}/Device/Maxim/MAX32690/Include + ${MAX32_PERIPH}/Include/MAX32690 + ${PERIPH_SRC}/SYS + ${PERIPH_SRC}/GPIO + ${PERIPH_SRC}/CTB + ${PERIPH_SRC}/ICC + ${PERIPH_SRC}/FLC + ${PERIPH_SRC}/UART + ) + + target_compile_options(${BOARD_TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_Clang}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_MAX32690 ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/mentor/musb/dcd_musb.c + ) + target_compile_options(${TARGET} PRIVATE + -Wno-error=strict-prototypes + ) + + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + target_compile_options(${TARGET}-tinyusb PRIVATE + -Wno-error=strict-prototypes + ) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_flash_jlink(${TARGET}) + family_flash_openocd_adi(${TARGET}) +endfunction() diff --git a/hw/bsp/max32690/family.mk b/hw/bsp/max32690/family.mk new file mode 100644 index 000000000..d4df8ef2f --- /dev/null +++ b/hw/bsp/max32690/family.mk @@ -0,0 +1,101 @@ +DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32 + +# Important locations in the hw support for MCU +MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS +MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers + +# Add any board specific make rules +include $(TOP)/$(BOARD_PATH)/board.mk + +CPU_CORE ?= cortex-m4 +PORT ?= 0 + +# GCC +SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/GCC/startup_max32690.S +LD_FILE = $(FAMILY_PATH)/max32690.ld + +# -------------- +# Compiler Flags +# -------------- +# Flags for the MAX32690 SDK +CFLAGS += -DTARGET=MAX32690 \ + -DTARGET_REV=0x4131 \ + -DMXC_ASSERT_ENABLE \ + -DMAX32690 \ + -DFLASH_ORIGIN=0x10000000 \ + -DFLASH_SIZE=0x340000 \ + -DSRAM_ORIGIN=0x20000000 \ + -DSRAM_SIZE=0x100000 \ + -DIAR_PRAGMAS=0 + +# Flags for TUSB features +CFLAGS += \ + -DCFG_TUSB_MCU=OPT_MCU_MAX32690 \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + +# mcu driver cause following warnings +CFLAGS += -Wno-error=unused-parameter \ + -Wno-error=strict-prototypes \ + -Wno-error=old-style-declaration \ + -Wno-error=sign-compare \ + -Wno-error=cast-qual \ + -Wno-lto-type-mismatch + +LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs + +# For flash-jlink target +JLINK_DEVICE = max32690 + +# flash target using Jlink by default +flash: flash-jlink + +# Optional flash option when running within an installed MSDK to use OpenOCD +# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated. +# If the MSDK is installed, flash-msdk can be run to utilize the the modified +# openocd with the algorithms +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +flash-msdk: $(BUILD)/$(PROJECT).elf + $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \ + -f interface/cmsis-dap.cfg -f target/max32690.cfg \ + -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit" + +# ----------------- +# Sources & Include +# ----------------- +PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source +SRC_C += \ + src/portable/mentor/musb/dcd_musb.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/heap.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/system_max32690.c \ + $(PERIPH_SRC)/SYS/mxc_assert.c \ + $(PERIPH_SRC)/SYS/mxc_delay.c \ + $(PERIPH_SRC)/SYS/mxc_lock.c \ + $(PERIPH_SRC)/SYS/nvic_table.c \ + $(PERIPH_SRC)/SYS/pins_me18.c \ + $(PERIPH_SRC)/SYS/sys_me18.c \ + $(PERIPH_SRC)/CTB/ctb_me18.c \ + $(PERIPH_SRC)/CTB/ctb_reva.c \ + $(PERIPH_SRC)/CTB/ctb_common.c \ + $(PERIPH_SRC)/FLC/flc_common.c \ + $(PERIPH_SRC)/FLC/flc_me18.c \ + $(PERIPH_SRC)/FLC/flc_reva.c \ + $(PERIPH_SRC)/GPIO/gpio_common.c \ + $(PERIPH_SRC)/GPIO/gpio_me18.c \ + $(PERIPH_SRC)/GPIO/gpio_reva.c \ + $(PERIPH_SRC)/ICC/icc_me18.c \ + $(PERIPH_SRC)/ICC/icc_reva.c \ + $(PERIPH_SRC)/UART/uart_common.c \ + $(PERIPH_SRC)/UART/uart_me18.c \ + $(PERIPH_SRC)/UART/uart_revb.c \ + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MAX32_CMSIS)/Include \ + $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32690/Include \ + $(TOP)/$(MAX32_PERIPH)/Include/MAX32690 \ + $(PERIPH_SRC)/SYS \ + $(PERIPH_SRC)/GPIO \ + $(PERIPH_SRC)/CTB \ + $(PERIPH_SRC)/ICC \ + $(PERIPH_SRC)/FLC \ + $(PERIPH_SRC)/UART diff --git a/hw/bsp/max32690/max32690.ld b/hw/bsp/max32690/max32690.ld new file mode 100644 index 000000000..64b906a54 --- /dev/null +++ b/hw/bsp/max32690/max32690.ld @@ -0,0 +1,164 @@ +MEMORY { + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000 /* 128kB ROM */ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00340000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000 + + /* + * Note that CS0/CS1 address mappings may be reversed using MXC_HPC->mbr0 and ->mbr1 + * The following mappings are selected for simplicity + */ + HPB_CS0 (rwx) : ORIGIN = 0x60000000, LENGTH = 0x10000000 /* External Hyperbus/Xccelabus chip select 0 */ + HPB_CS1 (rwx) : ORIGIN = 0x70000000, LENGTH = 0x10000000 /* External Hyperbus/Xccelabus chip select 1 */ +} + +SECTIONS { + .rom : + { + KEEP(*(.rom_vector)) + *(.rom_handlers*) + } > ROM + + .text : + { + _text = .; + KEEP(*(.isr_vector)) + EXCLUDE_FILE (*riscv.o) *(.text*) /* program code, exclude RISCV code */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + /* These sections allow code to be compiled/linked for HPB addresses, but reside in + * flash until copied by code to the external HPB flash device + */ + .hpb_cs0_section : + { + __hpb_cs0_start = ABSOLUTE(.); + KEEP(*(.hpb_cs0_section*)) + } > HPB_CS0 AT>FLASH + + __load_start_hpb_cs0 = LOADADDR(.hpb_cs0_section); + __load_length_hpb_cs0 = SIZEOF(.hpb_cs0_section); + + .hpb_cs1_section : + { + __hpb_cs1_start = ABSOLUTE(.); + KEEP(*(.hpb_cs1_section*)) + } > HPB_CS1 AT>FLASH + + __load_start_hpb_cs1 = LOADADDR(.hpb_cs1_section); + __load_length_hpb_cs1 = SIZEOF(.hpb_cs1_section); + + /* Binary import */ + .bin_storage : + { + FILL(0xFF) + _bin_start_ = .; + KEEP(*(.bin_storage_img)) + _bin_end_ = .; + . = ALIGN(4); + } > FLASH + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + *(vtable) + *(.data*) /*read-write initialized data: initialized global variable*/ + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + /* Run the flash programming functions from SRAM */ + *(.flashprog) + + _edata = ALIGN(., 4); + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > SRAM + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") +} diff --git a/hw/bsp/max78002/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/max78002/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..e5a76af85 --- /dev/null +++ b/hw/bsp/max78002/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,149 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "mxc_device.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS __NVIC_PRIO_BITS + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<-jlink` target for CMake. + +The Evaluation Kit is shipped with a CMSIS-DAP compatible debug probe. However, +at the time of writing, the necessary flashing algorithms for OpenOCD have not +yet been incorporated into the OpenOCD master branch. To utilize the provided +debug probes, please install the bundled MSDK package which includes the +appropriate OpenOCD modifications. To leverage this OpenOCD instance, run the +`flash-msdk` Makefile rule, or `-msdk` CMake target. diff --git a/hw/bsp/max78002/boards/max78002evkit/board.cmake b/hw/bsp/max78002/boards/max78002evkit/board.cmake new file mode 100644 index 000000000..9dc6962eb --- /dev/null +++ b/hw/bsp/max78002/boards/max78002evkit/board.cmake @@ -0,0 +1 @@ +# Nothing to be done at the board level diff --git a/hw/bsp/max78002/boards/max78002evkit/board.h b/hw/bsp/max78002/boards/max78002evkit/board.h new file mode 100644 index 000000000..f8102c394 --- /dev/null +++ b/hw/bsp/max78002/boards/max78002evkit/board.h @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#include "gpio.h" +#include "mxc_sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// LED +#define LED_PORT MXC_GPIO2 +#define LED_PIN MXC_GPIO_PIN_4 +#define LED_VDDIO MXC_GPIO_VSSEL_VDDIOH +#define LED_STATE_ON 1 + +// Button +#define BUTTON_PORT MXC_GPIO2 +#define BUTTON_PIN MXC_GPIO_PIN_6 +#define BUTTON_PULL MXC_GPIO_PAD_PULL_UP +#define BUTTON_STATE_ACTIVE 0 + +// UART Enable for EvKit's Integrated FTDI Adapter. Pin Mux handled by the HAL +#define UART_NUM 0 +#define UART_PORT MXC_GPIO0 +#define UART_VDDIO_BITS 0xF + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/max78002/boards/max78002evkit/board.mk b/hw/bsp/max78002/boards/max78002evkit/board.mk new file mode 100644 index 000000000..a813a5327 --- /dev/null +++ b/hw/bsp/max78002/boards/max78002evkit/board.mk @@ -0,0 +1 @@ +# No specific build requirements for the board. diff --git a/hw/bsp/max78002/family.c b/hw/bsp/max78002/family.c new file mode 100644 index 000000000..8d51f141c --- /dev/null +++ b/hw/bsp/max78002/family.c @@ -0,0 +1,169 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state() +#endif + +#include "gpio.h" +#include "mxc_sys.h" +#include "mcr_regs.h" +#include "mxc_device.h" +#include "uart.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include "board.h" +#include "bsp/board_api.h" + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void USB_IRQHandler(void) { + tud_int_handler(0); +} + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ +mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM); + +void board_init(void) { +#if CFG_TUSB_OS == OPT_OS_NONE + // 1ms tick timer + SysTick_Config(SystemCoreClock / 1000); +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); +#endif + mxc_gpio_cfg_t gpioConfig; + + // LED + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_OUT; + gpioConfig.mask = LED_PIN; + gpioConfig.pad = MXC_GPIO_PAD_NONE; + gpioConfig.port = LED_PORT; + gpioConfig.vssel = LED_VDDIO; + MXC_GPIO_Config(&gpioConfig); + board_led_write(false); + + // Button + gpioConfig.drvstr = MXC_GPIO_DRVSTR_0; + gpioConfig.func = MXC_GPIO_FUNC_IN; + gpioConfig.mask = BUTTON_PIN; + gpioConfig.pad = BUTTON_PULL; + gpioConfig.port = BUTTON_PORT; + gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO; + MXC_GPIO_Config(&gpioConfig); + + // UART + MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, MXC_UART_IBRO_CLK); + UART_PORT->vssel |= UART_VDDIO_BITS; //Set necessary bits to 3.3V + + //USB + MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN; + MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#if LED_STATE_ON + state = !state; +#endif + if (state) { + MXC_GPIO_OutClr(LED_PORT, LED_PIN); + } else { + MXC_GPIO_OutSet(LED_PORT, LED_PIN); + } +} + +uint32_t board_button_read(void) { + uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0; + return BUTTON_STATE_ACTIVE == state; +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer + /* All other 2nd parameter is optional checksum buffer */ + MXC_SYS_GetUSN(hw_id, NULL); + + size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN); + memcpy(id, hw_id, act_len); + return act_len; +} + +int board_uart_read(uint8_t *buf, int len) { + int uart_val; + int act_len = 0; + + while (act_len < len) { + if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) { + break; + } else { + *buf++ = (uint8_t) uart_val; + act_len++; + } + } + return act_len; +} + +int board_uart_write(void const *buf, int len) { + int act_len = 0; + const uint8_t *ch_ptr = (const uint8_t *) buf; + while (act_len < len) { + MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++); + act_len++; + } + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +void SysTick_Handler(void) { + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} +#endif + +void HardFault_Handler(void) { + __asm("BKPT #0\n"); +} + +// Required by __libc_init_array in startup code if we are compiling using +// -nostdlib/-nostartfiles. +void _init(void) { +} diff --git a/hw/bsp/max78002/family.cmake b/hw/bsp/max78002/family.cmake new file mode 100644 index 000000000..446930bd8 --- /dev/null +++ b/hw/bsp/max78002/family.cmake @@ -0,0 +1,166 @@ +include_guard() + +set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers) +set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS) +set(CMSIS_5 ${TOP}/lib/CMSIS_5) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# Get the linker file from current location (family) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max78002.ld) +set(LD_FILE_Clang ${LD_FILE_GNU}) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR cortex-m4 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) +set(JLINK_DEVICE max78000) + +set(FAMILY_MCUS MAX78002 CACHE INTERNAL "") + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + TARGET=MAX78002 + TARGET_REV=0x4131 + MXC_ASSERT_ENABLE + MAX78002 + IAR_PRAGMAS=0 + CFG_TUSB_MCU=OPT_MCU_MAX78002 + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) +endfunction() + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif () + + # Startup & Linker script + set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/GCC/startup_max78002.S) + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + + set(PERIPH_SRC ${MAX32_PERIPH}/Source) + add_library(${BOARD_TARGET} STATIC + ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/heap.c + ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/system_max78002.c + ${PERIPH_SRC}/SYS/mxc_assert.c + ${PERIPH_SRC}/SYS/mxc_delay.c + ${PERIPH_SRC}/SYS/mxc_lock.c + ${PERIPH_SRC}/SYS/nvic_table.c + ${PERIPH_SRC}/SYS/pins_ai87.c + ${PERIPH_SRC}/SYS/sys_ai87.c + ${PERIPH_SRC}/AES/aes_ai87.c + ${PERIPH_SRC}/AES/aes_revb.c + ${PERIPH_SRC}/FLC/flc_common.c + ${PERIPH_SRC}/FLC/flc_ai87.c + ${PERIPH_SRC}/FLC/flc_reva.c + ${PERIPH_SRC}/GPIO/gpio_common.c + ${PERIPH_SRC}/GPIO/gpio_ai87.c + ${PERIPH_SRC}/GPIO/gpio_reva.c + ${PERIPH_SRC}/ICC/icc_ai87.c + ${PERIPH_SRC}/ICC/icc_reva.c + ${PERIPH_SRC}/TRNG/trng_ai87.c + ${PERIPH_SRC}/TRNG/trng_revb.c + ${PERIPH_SRC}/UART/uart_common.c + ${PERIPH_SRC}/UART/uart_ai87.c + ${PERIPH_SRC}/UART/uart_revb.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${MAX32_CMSIS}/Include + ${MAX32_CMSIS}/Device/Maxim/MAX78002/Include + ${MAX32_PERIPH}/Include/MAX78002 + ${PERIPH_SRC}/SYS + ${PERIPH_SRC}/GPIO + ${PERIPH_SRC}/AES + ${PERIPH_SRC}/TRNG + ${PERIPH_SRC}/ICC + ${PERIPH_SRC}/FLC + ${PERIPH_SRC}/UART + ) + + target_compile_options(${BOARD_TARGET} PRIVATE + -Wno-error=strict-prototypes + -Wno-error=redundant-decls + ) + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_Clang}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + target_compile_options(${TARGET} PRIVATE + -Wno-error=strict-prototypes + -Wno-error=redundant-decls + ) + + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_MAX78002 ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/mentor/musb/dcd_musb.c + ) + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + target_compile_options(${TARGET}-tinyusb PRIVATE + -Wno-error=strict-prototypes + -Wno-error=redundant-decls + ) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_flash_jlink(${TARGET}) + family_flash_msdk(${TARGET}) +endfunction() + +# Add flash msdk target +function(family_flash_msdk TARGET) + set(MAXIM_PATH "$ENV{MAXIM_PATH}") + + add_custom_target(${TARGET}-msdk + DEPENDS ${TARGET} + COMMAND ${MAXIM_PATH}/Tools/OpenOCD/openocd -s ${MAXIM_PATH}/Tools/OpenOCD/scripts + -f interface/cmsis-dap.cfg -f target/max78002.cfg + -c "program $ verify; init; reset; exit" + VERBATIM + ) +endfunction() diff --git a/hw/bsp/max78002/family.mk b/hw/bsp/max78002/family.mk new file mode 100644 index 000000000..997816261 --- /dev/null +++ b/hw/bsp/max78002/family.mk @@ -0,0 +1,99 @@ +DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32 + +# Important locations in the hw support for MCU +MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS +MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers + +# Add any board specific make rules +include $(TOP)/$(BOARD_PATH)/board.mk + +CPU_CORE ?= cortex-m4 +PORT ?= 0 + +# GCC +SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/GCC/startup_max78002.S +LD_FILE = $(FAMILY_PATH)/max78002.ld + +# -------------- +# Compiler Flags +# -------------- +# Flags for the MAX78002 SDK +CFLAGS += -DTARGET=MAX78002 \ + -DTARGET_REV=0x4131 \ + -DMXC_ASSERT_ENABLE \ + -DMAX78002 \ + -DIAR_PRAGMAS=0 + +# Flags for TUSB features +CFLAGS += \ + -DCFG_TUSB_MCU=OPT_MCU_MAX78002 \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + +# mcu driver cause following warnings +CFLAGS += -Wno-error=redundant-decls \ + -Wno-error=strict-prototypes \ + -Wno-error=unused-parameter \ + -Wno-error=enum-conversion \ + -Wno-error=sign-compare \ + -Wno-error=cast-qual + +LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs + +# For flash-jlink target +JLINK_DEVICE = max78000 + +# flash target using Jlink by default +flash: flash-jlink + +# Optional flash option when running within an installed MSDK to use OpenOCD +# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated. +# If the MSDK is installed, flash-msdk can be run to utilize the the modified +# openocd with the algorithms +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +flash-msdk: $(BUILD)/$(PROJECT).elf + $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \ + -f interface/cmsis-dap.cfg -f target/max78002.cfg \ + -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit" + +# ----------------- +# Sources & Include +# ----------------- +PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source +SRC_C += \ + src/portable/mentor/musb/dcd_musb.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/heap.c \ + $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/system_max78002.c \ + $(PERIPH_SRC)/SYS/mxc_assert.c \ + $(PERIPH_SRC)/SYS/mxc_delay.c \ + $(PERIPH_SRC)/SYS/mxc_lock.c \ + $(PERIPH_SRC)/SYS/nvic_table.c \ + $(PERIPH_SRC)/SYS/pins_ai87.c \ + $(PERIPH_SRC)/SYS/sys_ai87.c \ + $(PERIPH_SRC)/AES/aes_ai87.c \ + $(PERIPH_SRC)/AES/aes_revb.c \ + $(PERIPH_SRC)/FLC/flc_common.c \ + $(PERIPH_SRC)/FLC/flc_ai87.c \ + $(PERIPH_SRC)/FLC/flc_reva.c \ + $(PERIPH_SRC)/GPIO/gpio_common.c \ + $(PERIPH_SRC)/GPIO/gpio_ai87.c \ + $(PERIPH_SRC)/GPIO/gpio_reva.c \ + $(PERIPH_SRC)/ICC/icc_ai87.c \ + $(PERIPH_SRC)/ICC/icc_reva.c \ + $(PERIPH_SRC)/TRNG/trng_ai87.c \ + $(PERIPH_SRC)/TRNG/trng_revb.c \ + $(PERIPH_SRC)/UART/uart_common.c \ + $(PERIPH_SRC)/UART/uart_ai87.c \ + $(PERIPH_SRC)/UART/uart_revb.c \ + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MAX32_CMSIS)/Include \ + $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX78002/Include \ + $(TOP)/$(MAX32_PERIPH)/Include/MAX78002 \ + $(PERIPH_SRC)/SYS \ + $(PERIPH_SRC)/GPIO \ + $(PERIPH_SRC)/AES \ + $(PERIPH_SRC)/ICC \ + $(PERIPH_SRC)/FLC \ + $(PERIPH_SRC)/TRNG \ + $(PERIPH_SRC)/UART diff --git a/hw/bsp/max78002/max78002.ld b/hw/bsp/max78002/max78002.ld new file mode 100644 index 000000000..e5c4866ee --- /dev/null +++ b/hw/bsp/max78002/max78002.ld @@ -0,0 +1,182 @@ +MEMORY { + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64 kB ROM */ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00280000 /* 2.5 MB Flash */ + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00060000 /* 384 kB SRAM */ + /*CSI2 (rwx) : ORIGIN = 0x2001F000, LENGTH = 0x00001000 4096 B CSI2 Buffer */ +} + +SECTIONS { + .rom : + { + KEEP(*(.rom_vector)) + *(.rom_handlers*) + } > ROM + + .text : + { + _text = .; + KEEP(*(.isr_vector)) + EXCLUDE_FILE (*riscv.o) *(.text*) /* Program code (exclude RISCV code) */ + *(.rodata*) /* read-only data: "const" */ + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + /* C++ Exception handling */ + KEEP(*(.eh_frame*)) + _etext = .; + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + /* Binary import */ + .bin_storage : + { + FILL(0xFF) + _bin_start_ = .; + KEEP(*(.bin_storage_img)) + _bin_end_ = .; + . = ALIGN(4); + } > FLASH + + .rom_code : + { + . = ALIGN(16); + _sran_code = .; + *(.rom_code_section) + _esran_code = .; + } > ROM + + .flash_code : + { + . = ALIGN(16); + _sran_code = .; + *(.flash_code_section) + _esran_code = .; + } > FLASH + + .sram_code : + { + . = ALIGN(16); + _sran_code = .; + *(.sram_code_section) + _esran_code = .; + } > SRAM + + /* it's used for C++ exception handling */ + /* we need to keep this to avoid overlapping */ + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + .data : + { + _data = ALIGN(., 4); + _csi = . + 0x20000; + *(vtable) + *(.data*) /*read-write initialized data: initialized global variable*/ + + + /* These array sections are used by __libc_init_array to call static C++ constructors */ + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + _edata = ALIGN(., 4); + + } > SRAM AT>FLASH + __load_data = LOADADDR(.data); + + .bss : + { + . = ALIGN(4); + _bss = .; + *(.bss*) /*read-write zero initialized data: uninitialized global variable*/ + *(COMMON) + _ebss = ALIGN(., 4); + } > SRAM + + .shared : + { + . = ALIGN(4); + _shared = .; + *(.mailbox*) + . = ALIGN(4); + *(.shared*) /*read-write zero initialized data: uninitialized global variable*/ + _eshared = ALIGN(., 4); + } > SRAM + __shared_data = LOADADDR(.shared); + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > SRAM + + .heap (COPY): + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + *(.heap*) + __HeapLimit = ABSOLUTE(__StackLimit); + } > SRAM + + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") + + /* Section used by RISCV loader projects. See RISCV_LOAD documentation in the build system. */ + .riscv_flash : + { + /* Align address to mod 256 with a small offset. This is required to match the flash page size.*/ + . = ALIGN(256); /* ALIGN operatator is used here. Note that (. & 0x1FFFFF00) was used in the past, but a strange bug was seen on Windows where the & did not behave as expected.*/ + . += 0x100; + _riscv_boot = .; + KEEP(*riscv.o (.text*)) + } > FLASH +} diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake index 6ff1a7b59..a0282aa23 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake @@ -2,7 +2,7 @@ set(MCU_VARIANT nrf52840) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) # enable max3421 host driver for this board -set(MAX3421_HOST 1) +# set(MAX3421_HOST 1) function(update_board TARGET) endfunction() diff --git a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake b/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake deleted file mode 100644 index ffa5932c1..000000000 --- a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(MCU_VARIANT nrf52840) -set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/nrf52840_mdk_dongle.ld) - -function(update_board TARGET) -endfunction() diff --git a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.mk b/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.mk deleted file mode 100644 index f25ec8f34..000000000 --- a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.mk +++ /dev/null @@ -1,15 +0,0 @@ -MCU_VARIANT = nrf52840 -CFLAGS += -DNRF52840_XXAA - -LD_FILE = $(BOARD_PATH)/$(BOARD).ld - -# flash using Nordic nrfutil (pip3 install nrfutil) -# make BOARD=nrf52840_mdk_dongle SERIAL=/dev/ttyACM0 all flash -NRFUTIL = nrfutil - -$(BUILD)/$(PROJECT).zip: $(BUILD)/$(PROJECT).hex - $(NRFUTIL) pkg generate --hw-version 52 --sd-req 0x0000 --debug-mode --application $^ $@ - -flash: $(BUILD)/$(PROJECT).zip - @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0) - $(NRFUTIL) dfu usb-serial --package $^ -p $(SERIAL) -b 115200 diff --git a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/nrf52840_mdk_dongle.ld b/hw/bsp/nrf/boards/nrf52840_mdk_dongle/nrf52840_mdk_dongle.ld deleted file mode 100644 index a6bc6dcfe..000000000 --- a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/nrf52840_mdk_dongle.ld +++ /dev/null @@ -1,13 +0,0 @@ -/* Linker script to configure memory regions. */ - -SEARCH_DIR(.) -/*GROUP(-lgcc -lc -lnosys) not compatible with clang*/ - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0xE0000-0x1000 - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 0x3fff8 -} - - -INCLUDE "nrf_common.ld" diff --git a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.mk b/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.mk deleted file mode 100644 index be2ed3314..000000000 --- a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.mk +++ /dev/null @@ -1,7 +0,0 @@ -MCU_VARIANT = nrf52840 -CFLAGS += -DNRF52840_XXAA - -LD_FILE = hw/mcu/nordic/nrfx/mdk/nrf52840_xxaa.ld - -# flash using jlink -flash: flash-jlink diff --git a/hw/bsp/ra/family.c b/hw/bsp/ra/family.c index db8988a36..a8b4ebcc7 100644 --- a/hw/bsp/ra/family.c +++ b/hw/bsp/ra/family.c @@ -147,6 +147,13 @@ uint32_t board_button_read(void) { return lvl == BUTTON_STATE_ACTIVE; } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + max_len = tu_min32(max_len, sizeof(bsp_unique_id_t)); + bsp_unique_id_t const *uid = R_BSP_UniqueIdGet(); + memcpy(id, uid->unique_id_bytes, max_len); + return max_len; +} + int board_uart_read(uint8_t *buf, int len) { (void) buf; (void) len; @@ -169,7 +176,6 @@ void SysTick_Handler(void) { uint32_t board_millis(void) { return system_ticks; } - #endif //--------------------------------------------------------------------+ diff --git a/hw/bsp/rp2040/board.h b/hw/bsp/rp2040/board.h index 3849894ce..733e93797 100644 --- a/hw/bsp/rp2040/board.h +++ b/hw/bsp/rp2040/board.h @@ -78,7 +78,12 @@ // USB Host MAX3421E //-------------------------------------------------------------------- -#define MAX3421_SPI PICO_DEFAULT_SPI_INSTANCE +#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 diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index cffb632f3..64a3a0af6 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -31,6 +31,7 @@ #include "hardware/gpio.h" #include "hardware/sync.h" #include "hardware/resets.h" +#include "hardware/clocks.h" #include "hardware/structs/ioqspi.h" #include "hardware/structs/sio.h" @@ -41,7 +42,7 @@ static uart_inst_t *uart_inst; #endif -#if CFG_TUH_RPI_PIO_USB || CFG_TUD_RPI_PIO_USB +#if (CFG_TUH_ENABLED && CFG_TUH_RPI_PIO_USB) || (CFG_TUD_ENABLED && CFG_TUD_RPI_PIO_USB) #include "pio_usb.h" #endif @@ -125,7 +126,7 @@ void stdio_rtt_init(void) { void board_init(void) { -#if CFG_TUH_RPI_PIO_USB || CFG_TUD_RPI_PIO_USB +#if (CFG_TUH_ENABLED && CFG_TUH_RPI_PIO_USB) || (CFG_TUD_ENABLED && CFG_TUD_RPI_PIO_USB) // Set the system clock to a multiple of 120mhz for bitbanging USB with pico-usb set_sys_clock_khz(120000, true); @@ -274,7 +275,15 @@ static void max3421_init(void) { gpio_set_function(MAX3421_SCK_PIN, GPIO_FUNC_SPI); gpio_set_function(MAX3421_MOSI_PIN, GPIO_FUNC_SPI); gpio_set_function(MAX3421_MISO_PIN, GPIO_FUNC_SPI); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnull-dereference" +#endif spi_set_format(MAX3421_SPI, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } //// API to enable/disable MAX3421 INTR pin interrupt diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index c81390b28..d91821ffa 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -133,7 +133,10 @@ target_sources(tinyusb_bsp INTERFACE target_include_directories(tinyusb_bsp INTERFACE ${TOP}/hw ) -target_link_libraries(tinyusb_bsp INTERFACE pico_unique_id) +target_link_libraries(tinyusb_bsp INTERFACE + pico_unique_id + hardware_clocks + ) # tinyusb_additions will hold our extra settings for examples add_library(tinyusb_additions INTERFACE) diff --git a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake index 86d12ca24..ebc32b1f7 100644 --- a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake +++ b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake @@ -3,6 +3,9 @@ set(SAM_FAMILY samd51) set(JLINK_DEVICE ATSAMD51J19) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/${BOARD}.ld) +# force max3421e for testing with hardware-in-the-loop +set(MAX3421_HOST 1) + function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC __SAMD51J19A__ diff --git a/hw/bsp/stm32f0/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32f0/FreeRTOSConfig/FreeRTOSConfig.h index 37e7e0943..999dbfe9e 100644 --- a/hw/bsp/stm32f0/FreeRTOSConfig/FreeRTOSConfig.h +++ b/hw/bsp/stm32f0/FreeRTOSConfig/FreeRTOSConfig.h @@ -58,7 +58,7 @@ #define configCPU_CLOCK_HZ SystemCoreClock #define configTICK_RATE_HZ ( 1000 ) #define configMAX_PRIORITIES ( 5 ) -#define configMINIMAL_STACK_SIZE ( 128 ) +#define configMINIMAL_STACK_SIZE ( 200 ) #define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 diff --git a/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.cmake b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.cmake new file mode 100644 index 000000000..7672ff338 --- /dev/null +++ b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.cmake @@ -0,0 +1,15 @@ +set(MCU_VARIANT stm32f103xe) +set(JLINK_DEVICE stm32f103ze) +#set(JLINK_OPTION "-USB 320000338") + +string(TOUPPER ${MCU_VARIANT} MCU_VARIANT_UPPER) + +set(LD_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT_UPPER}_FLASH.ld) +set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + STM32F103xE + HSE_VALUE=8000000U + ) +endfunction() diff --git a/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.h b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.h new file mode 100644 index 000000000..d31102d32 --- /dev/null +++ b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.h @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// LED +#define LED_PORT GPIOF +#define LED_PIN GPIO_PIN_6 +#define LED_STATE_ON 1 + +// Button +#define BUTTON_PORT GPIOG +#define BUTTON_PIN GPIO_PIN_8 +#define BUTTON_STATE_ACTIVE 0 + +// USB Connect +#define USB_CONNECT_PORT GPIOG +#define USB_CONNECT_PIN GPIO_PIN_11 +#define USB_CONNECT_STATE 0 + +// UART +//#define UART_DEV USART1 +//#define UART_CLK_EN __HAL_RCC_USART1_CLK_ENABLE +//#define UART_GPIO_PORT GPIOA +//#define UART_GPIO_AF GPIO_AF1_USART1 +//#define UART_TX_PIN GPIO_PIN_9 +//#define UART_RX_PIN GPIO_PIN_10 + +//--------------------------------------------------------------------+ +// RCC Clock +//--------------------------------------------------------------------+ +static inline void board_stm32f1_clock_init(void) +{ + RCC_ClkInitTypeDef clkinitstruct = {0}; + RCC_OscInitTypeDef oscinitstruct = {0}; + RCC_PeriphCLKInitTypeDef rccperiphclkinit = {0}; + + /* Enable HSE Oscillator and activate PLL with HSE as source */ + oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + oscinitstruct.HSEState = RCC_HSE_ON; + oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; + oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9; + oscinitstruct.PLL.PLLState = RCC_PLL_ON; + oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + HAL_RCC_OscConfig(&oscinitstruct); + + /* USB clock selection */ + rccperiphclkinit.PeriphClockSelection = RCC_PERIPHCLK_USB; + rccperiphclkinit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5; + HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit); + + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ + clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2; + clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1; + HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); +} + +static inline void board_vbus_sense_init(void) +{ +} + +#ifdef __cplusplus + } +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.mk b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.mk new file mode 100644 index 000000000..5b17d8036 --- /dev/null +++ b/hw/bsp/stm32f1/boards/stm32f103ze_iar/board.mk @@ -0,0 +1,13 @@ +MCU_VARIANT = stm32f103xe + +CFLAGS += -DSTM32F103xE -DHSE_VALUE=8000000U + +# Linker +LD_FILE_GCC = ${ST_CMSIS}/Source/Templates/gcc/linker/STM32F103XE_FLASH.ld +LD_FILE_IAR = ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf + +# For flash-jlink target +JLINK_DEVICE = stm32f103ze + +# flash target ROM bootloader +flash: flash-jlink diff --git a/hw/bsp/stm32f1/family.c b/hw/bsp/stm32f1/family.c index 70f81e7fc..600fc28c0 100644 --- a/hw/bsp/stm32f1/family.c +++ b/hw/bsp/stm32f1/family.c @@ -57,6 +57,19 @@ void board_init(void) { __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); +#ifdef __HAL_RCC_GPIOE_CLK_ENABLE + __HAL_RCC_GPIOE_CLK_ENABLE(); +#endif + +#ifdef __HAL_RCC_GPIOF_CLK_ENABLE + __HAL_RCC_GPIOF_CLK_ENABLE(); +#endif + +#ifdef __HAL_RCC_GPIOG_CLK_ENABLE + __HAL_RCC_GPIOG_CLK_ENABLE(); +#endif + + #if CFG_TUSB_OS == OPT_OS_NONE // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); @@ -107,10 +120,18 @@ void board_init(void) { HAL_UART_Init(&UartHandle); #endif +#ifdef USB_CONNECT_PIN + GPIO_InitStruct.Pin = USB_CONNECT_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(USB_CONNECT_PORT, &GPIO_InitStruct); +#endif + // USB Pins // Configure USB DM and DP pins. GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -119,6 +140,18 @@ void board_init(void) { __HAL_RCC_USB_CLK_ENABLE(); } +#ifdef USB_CONNECT_PIN +void dcd_disconnect(uint8_t rhport) { + (void)rhport; + HAL_GPIO_WritePin(USB_CONNECT_PORT, USB_CONNECT_PIN, 1-USB_CONNECT_STATE); +} + +void dcd_connect(uint8_t rhport) { + (void)rhport; + HAL_GPIO_WritePin(USB_CONNECT_PORT, USB_CONNECT_PIN, USB_CONNECT_STATE); +} +#endif + //--------------------------------------------------------------------+ // Board porting API //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32f1/family.mk b/hw/bsp/stm32f1/family.mk index 03fbf4010..364616304 100644 --- a/hw/bsp/stm32f1/family.mk +++ b/hw/bsp/stm32f1/family.mk @@ -1,10 +1,10 @@ ST_FAMILY = f1 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver +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 +ST_CMSIS = hw/mcu/st/cmsis_device_${ST_FAMILY} +ST_HAL_DRIVER = hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver -include $(TOP)/$(BOARD_PATH)/board.mk +include ${TOP}/${BOARD_PATH}/board.mk CPU_CORE ?= cortex-m3 # -------------- @@ -29,23 +29,23 @@ LDFLAGS_GCC += \ # ------------------------ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ - $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc_ex.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_gpio.c \ - $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_uart.c + ${ST_CMSIS}/Source/Templates/system_stm32${ST_FAMILY}xx.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_cortex.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_rcc.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_rcc_ex.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_gpio.c \ + ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_uart.c INC += \ - $(TOP)/$(BOARD_PATH) \ - $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \ - $(TOP)/$(ST_CMSIS)/Include \ - $(TOP)/$(ST_HAL_DRIVER)/Inc + ${TOP}/${BOARD_PATH} \ + ${TOP}/lib/CMSIS_5/CMSIS/Core/Include \ + ${TOP}/${ST_CMSIS}/Include \ + ${TOP}/${ST_HAL_DRIVER}/Inc # Startup -SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s -SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s +SRC_S_GCC += ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s +SRC_S_IAR += ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s # flash target ROM bootloader: flash-dfu-util DFU_UTIL_OPTION = -a 0 --dfuse-address 0x08000000 diff --git a/hw/bsp/stm32f3/family.c b/hw/bsp/stm32f3/family.c index e7488ba84..f94dd95cf 100644 --- a/hw/bsp/stm32f3/family.c +++ b/hw/bsp/stm32f3/family.c @@ -116,6 +116,19 @@ uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + volatile uint32_t * stm32_uuid = (volatile uint32_t *) UID_BASE; + uint32_t* id32 = (uint32_t*) (uintptr_t) id; + uint8_t const len = 12; + + id32[0] = stm32_uuid[0]; + id32[1] = stm32_uuid[1]; + id32[2] = stm32_uuid[2]; + + return len; +} + int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; diff --git a/hw/bsp/stm32f7/family.mk b/hw/bsp/stm32f7/family.mk index e261b0467..bae7d6d5b 100644 --- a/hw/bsp/stm32f7/family.mk +++ b/hw/bsp/stm32f7/family.mk @@ -24,6 +24,7 @@ ifeq ($(PORT), 1) $(info "Using OTG_HS in FullSpeed mode") endif else + CFLAGS += -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED $(info "Using OTG_FS") endif diff --git a/hw/bsp/stm32g0/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32g0/FreeRTOSConfig/FreeRTOSConfig.h index 82cb0cdb3..76133ea2d 100644 --- a/hw/bsp/stm32g0/FreeRTOSConfig/FreeRTOSConfig.h +++ b/hw/bsp/stm32g0/FreeRTOSConfig/FreeRTOSConfig.h @@ -58,7 +58,7 @@ #define configCPU_CLOCK_HZ SystemCoreClock #define configTICK_RATE_HZ ( 1000 ) #define configMAX_PRIORITIES ( 5 ) -#define configMINIMAL_STACK_SIZE ( 128 ) +#define configMINIMAL_STACK_SIZE ( 200 ) #define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 diff --git a/hw/bsp/stm32g0/family.cmake b/hw/bsp/stm32g0/family.cmake index b6838c619..0dafa9c0a 100644 --- a/hw/bsp/stm32g0/family.cmake +++ b/hw/bsp/stm32g0/family.cmake @@ -15,7 +15,7 @@ set(CMAKE_SYSTEM_PROCESSOR cortex-m0plus CACHE INTERNAL "System Processor") set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) set(FAMILY_MCUS STM32G0 CACHE INTERNAL "") - +set(OPENOCD_OPTION "-f interface/stlink.cfg -f target/stm32g0x.cfg") #------------------------------------ # BOARD_TARGET @@ -112,6 +112,7 @@ function(family_configure_example TARGET RTOS) target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) # Flashing - family_flash_stlink(${TARGET}) family_flash_jlink(${TARGET}) + family_flash_stlink(${TARGET}) + #family_flash_openocd(${TARGET}) endfunction() diff --git a/hw/bsp/stm32g4/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32g4/FreeRTOSConfig/FreeRTOSConfig.h index fa3f0ac33..891ea4b79 100644 --- a/hw/bsp/stm32g4/FreeRTOSConfig/FreeRTOSConfig.h +++ b/hw/bsp/stm32g4/FreeRTOSConfig/FreeRTOSConfig.h @@ -58,7 +58,7 @@ #define configCPU_CLOCK_HZ SystemCoreClock #define configTICK_RATE_HZ ( 1000 ) #define configMAX_PRIORITIES ( 5 ) -#define configMINIMAL_STACK_SIZE ( 128 ) +#define configMINIMAL_STACK_SIZE ( 200 ) #define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 diff --git a/hw/bsp/stm32h5/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32h5/FreeRTOSConfig/FreeRTOSConfig.h index cf6e23c1b..6a9c90a4a 100644 --- a/hw/bsp/stm32h5/FreeRTOSConfig/FreeRTOSConfig.h +++ b/hw/bsp/stm32h5/FreeRTOSConfig/FreeRTOSConfig.h @@ -58,7 +58,7 @@ #define configCPU_CLOCK_HZ SystemCoreClock #define configTICK_RATE_HZ ( 1000 ) #define configMAX_PRIORITIES ( 5 ) -#define configMINIMAL_STACK_SIZE ( 128 ) +#define configMINIMAL_STACK_SIZE ( 200 ) #define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 diff --git a/hw/bsp/stm32l0/boards/stm32l052dap52/board.h b/hw/bsp/stm32l0/boards/stm32l052dap52/board.h index c8963199b..ee83bbcbc 100644 --- a/hw/bsp/stm32l0/boards/stm32l052dap52/board.h +++ b/hw/bsp/stm32l0/boards/stm32l052dap52/board.h @@ -54,16 +54,17 @@ //--------------------------------------------------------------------+ static inline void board_stm32l0_clock_init(void) { - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_OscInitTypeDef RCC_OscInitStruct; - RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; - static RCC_CRSInitTypeDef RCC_CRSInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + RCC_CRSInitTypeDef RCC_CRSInitStruct = {0}; /* Enable HSI Oscillator to be used as System clock source Enable HSI48 Oscillator to be used as USB clock source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSI48; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; HAL_RCC_OscConfig(&RCC_OscInitStruct); /* Select HSI48 as USB clock source */ diff --git a/hw/bsp/stm32l0/boards/stm32l0538disco/board.cmake b/hw/bsp/stm32l0/boards/stm32l0538disco/board.cmake index 8d7b537d5..895bbb3ab 100644 --- a/hw/bsp/stm32l0/boards/stm32l0538disco/board.cmake +++ b/hw/bsp/stm32l0/boards/stm32l0538disco/board.cmake @@ -1,5 +1,6 @@ set(MCU_VARIANT stm32l053xx) set(JLINK_DEVICE stm32l053r8) +#set(JLINK_OPTION "-USB 778921770") set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32L053C8Tx_FLASH.ld) diff --git a/hw/bsp/stm32l0/boards/stm32l0538disco/board.h b/hw/bsp/stm32l0/boards/stm32l0538disco/board.h index 0722e3102..5cda1c15a 100644 --- a/hw/bsp/stm32l0/boards/stm32l0538disco/board.h +++ b/hw/bsp/stm32l0/boards/stm32l0538disco/board.h @@ -54,16 +54,17 @@ //--------------------------------------------------------------------+ static inline void board_stm32l0_clock_init(void) { - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_OscInitTypeDef RCC_OscInitStruct; - RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; - static RCC_CRSInitTypeDef RCC_CRSInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + RCC_CRSInitTypeDef RCC_CRSInitStruct = {0}; /* Enable HSI Oscillator to be used as System clock source Enable HSI48 Oscillator to be used as USB clock source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSI48; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; HAL_RCC_OscConfig(&RCC_OscInitStruct); /* Select HSI48 as USB clock source */ diff --git a/hw/bsp/stm32l0/family.c b/hw/bsp/stm32l0/family.c index ea7f0b73d..c8c88d687 100644 --- a/hw/bsp/stm32l0/family.c +++ b/hw/bsp/stm32l0/family.c @@ -126,6 +126,19 @@ uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + volatile uint32_t * stm32_uuid = (volatile uint32_t *) UID_BASE; + uint32_t* id32 = (uint32_t*) (uintptr_t) id; + uint8_t const len = 12; + + id32[0] = stm32_uuid[0]; + id32[1] = stm32_uuid[1]; + id32[2] = stm32_uuid[2]; + + return len; +} + int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; diff --git a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.cmake b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.cmake index a86b5c0e5..b8df9f189 100644 --- a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.cmake +++ b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.cmake @@ -4,6 +4,7 @@ set(JLINK_DEVICE TM4C123GH6PM) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/tm4c123.ld) set(OPENOCD_OPTION "-f board/ti_ek-tm4c123gxl.cfg") +set(UNIFLASH_OPTION "-c ${CMAKE_CURRENT_LIST_DIR}/${BOARD}.ccxml -r 1") function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC diff --git a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.mk b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.mk index a3e8df62c..b3ded8007 100644 --- a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.mk +++ b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.mk @@ -10,4 +10,6 @@ JLINK_DEVICE = TM4C123GH6PM # flash using openocd OPENOCD_OPTION = -f board/ti_ek-tm4c123gxl.cfg +UNIFLASH_OPTION = -c ${TOP}/${BOARD_PATH}/${BOARD}.ccxml -r 1 + flash: flash-openocd diff --git a/hw/bsp/tm4c/boards/ek_tm4c123gxl/ek_tm4c123gxl.ccxml b/hw/bsp/tm4c/boards/ek_tm4c123gxl/ek_tm4c123gxl.ccxml new file mode 100644 index 000000000..426a6f368 --- /dev/null +++ b/hw/bsp/tm4c/boards/ek_tm4c123gxl/ek_tm4c123gxl.ccxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/hw/bsp/tm4c/family.c b/hw/bsp/tm4c/family.c index 738bc3fa0..5e1f6d3ff 100644 --- a/hw/bsp/tm4c/family.c +++ b/hw/bsp/tm4c/family.c @@ -5,8 +5,7 @@ //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ -void USB0_Handler(void) -{ +void USB0_Handler(void) { #if CFG_TUH_ENABLED tuh_int_handler(0, true); #endif @@ -20,8 +19,7 @@ void USB0_Handler(void) // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ -static void board_uart_init (void) -{ +static void board_uart_init(void) { SYSCTL->RCGCUART |= (1 << 0); // Enable the clock to UART0 SYSCTL->RCGCGPIO |= (1 << 0); // Enable the clock to GPIOA @@ -42,13 +40,12 @@ static void board_uart_init (void) UART0->CTL = (1 << 0) | (1 << 8) | (1 << 9); // UART0 Enable, Transmit Enable, Receive Enable } -static void initialize_board_led (GPIOA_Type *port, uint8_t PinMsk, uint8_t dirmsk) -{ +static void initialize_board_led(GPIOA_Type* port, uint8_t PinMsk, uint8_t dirmsk) { /* Enable PortF Clock */ SYSCTL->RCGCGPIO |= (1 << 5); /* Let the clock stabilize */ - while ( !((SYSCTL->PRGPIO) & (1 << 5)) ) {} + while (!((SYSCTL->PRGPIO) & (1 << 5))) {} /* Port Digital Enable */ port->DEN |= PinMsk; @@ -57,46 +54,33 @@ static void initialize_board_led (GPIOA_Type *port, uint8_t PinMsk, uint8_t dirm port->DIR = dirmsk; } -static void board_switch_init (void) -{ - GPIOF->DIR &= ~(1 << BOARD_BTN); - GPIOF->PUR |= (1 << BOARD_BTN); - GPIOF->DEN |= (1 << BOARD_BTN); -} - -static void WriteGPIOPin (GPIOA_Type *port, uint8_t PinMsk, bool state) -{ - if ( state ) - { +static void WriteGPIOPin(GPIOA_Type* port, uint8_t PinMsk, bool state) { + if (state) { port->DATA |= PinMsk; - } - else - { + } else { port->DATA &= ~(PinMsk); } } -static uint32_t ReadGPIOPin (GPIOA_Type *port, uint8_t pinMsk) -{ +static uint32_t ReadGPIOPin(GPIOA_Type* port, uint8_t pinMsk) { return (port->DATA & pinMsk); } -void board_init (void) -{ +void board_init(void) { SystemCoreClockUpdate(); #if CFG_TUSB_OS == OPT_OS_NONE // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); #elif CFG_TUSB_OS == OPT_OS_FREERTOS - // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) - NVIC_SetPriority(USB0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ); + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(USB0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ); #endif /* Reset USB */ SYSCTL->SRCR2 |= (1u << 16); - for ( volatile uint8_t i = 0; i < 20; i++ ) {} + for (volatile uint8_t i = 0; i < 20; i++) {} SYSCTL->SRCR2 &= ~(1u << 16); @@ -110,7 +94,7 @@ void board_init (void) SYSCTL->RCGCGPIO |= (1u << 3); /* Let the clock stabilize */ - while ( !(SYSCTL->PRGPIO & (1u << 3)) ) {} + while (!(SYSCTL->PRGPIO & (1u << 3))) {} /* USB IOs to Analog Mode */ GPIOD->AFSEL &= ~((1u << 4) | (1u << 5)); @@ -124,7 +108,9 @@ void board_init (void) initialize_board_led(LED_PORT, leds, dirmsk); /* Configure GPIO for board switch */ - board_switch_init(); + GPIOF->DIR &= ~(1 << BOARD_BTN); + GPIOF->PUR |= (1 << BOARD_BTN); + GPIOF->DEN |= (1 << BOARD_BTN); /* Initialize board UART */ board_uart_init(); @@ -132,32 +118,35 @@ void board_init (void) TU_LOG1_INT(SystemCoreClock); } -void board_led_write (bool state) -{ +void board_led_write(bool state) { WriteGPIOPin(LED_PORT, (1 << LED_PIN_BLUE), state); } -uint32_t board_button_read (void) -{ +uint32_t board_button_read(void) { uint32_t gpio_value = ReadGPIOPin(BOARD_BTN_PORT, BOARD_BTN_Msk); return BUTTON_STATE_ACTIVE ? gpio_value : !gpio_value; } -int board_uart_write (void const *buf, int len) -{ - uint8_t const * data = buf; +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + uint8_t const len = 8; + // Note: DID0, DID1 are variant ID, they aer used since TM4C123 does not have unique ID + memcpy(id, (void*)(uintptr_t) &SYSCTL->DID0, len); + return len; +} - for ( int i = 0; i < len; i++ ) - { - while ( (UART0->FR & (1 << 5)) != 0 ) {} // Poll until previous data was shofted out - UART0->DR = data[i]; // Write UART0 DATA REGISTER +int board_uart_write(void const* buf, int len) { + uint8_t const* data = buf; + + for (int i = 0; i < len; i++) { + while ((UART0->FR & (1 << 5)) != 0) {} // Poll until previous data was shofted out + UART0->DR = data[i]; // Write UART0 DATA REGISTER } return len; } -int board_uart_read (uint8_t *buf, int len) -{ +int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; return 0; @@ -165,13 +154,13 @@ int board_uart_read (uint8_t *buf, int len) #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ + +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis (void) -{ +uint32_t board_millis(void) { return system_ticks; } + #endif diff --git a/hw/bsp/tm4c/family.cmake b/hw/bsp/tm4c/family.cmake index 86db985d6..9c083759b 100644 --- a/hw/bsp/tm4c/family.cmake +++ b/hw/bsp/tm4c/family.cmake @@ -92,4 +92,5 @@ function(family_configure_example TARGET RTOS) # Flashing family_add_bin_hex(${TARGET}) family_flash_openocd(${TARGET}) + family_flash_uniflash(${TARGET}) endfunction() diff --git a/lib/networking/dhserver.h b/lib/networking/dhserver.h index b0d57ac4e..6a443b220 100644 --- a/lib/networking/dhserver.h +++ b/lib/networking/dhserver.h @@ -59,7 +59,7 @@ typedef struct dhcp_config #ifdef __cplusplus extern "C" { #endif -err_t dhserv_init(const dhcp_config_t *config); +err_t dhserv_init(const dhcp_config_t *c); void dhserv_free(void); #ifdef __cplusplus } diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index d6f3e22e2..2f97c0f23 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -489,7 +489,7 @@ typedef enum AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), - AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000, + AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000u, } audio_data_format_type_I_t; /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification @@ -640,7 +640,7 @@ typedef enum AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, - AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000, + AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000u, } audio_channel_config_t; /// AUDIO Channel Cluster Descriptor (4.1) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 4a383c3c7..8c86de433 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg + * Copyright (c) 2023 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -120,23 +121,23 @@ // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING @@ -146,38 +147,38 @@ // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING @@ -187,89 +188,89 @@ // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; #if CFG_TUD_AUDIO > 1 -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; #endif #if CFG_TUD_AUDIO > 2 -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces -uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; +tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 -uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; +tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 -uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; +tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif // Software encoding/decoding support FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #endif @@ -302,32 +303,18 @@ typedef struct bool mounted; // Device opened - /*------------- From this point, data is not cleared by bus reset -------------*/ - uint16_t desc_length; // Length of audio function descriptor - // Buffer for control requests - uint8_t * ctrl_buf; - uint8_t ctrl_buf_sz; - - // Current active alternate settings - uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - - // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t ep_out_ff; -#endif - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + CFG_TUSB_MEM_ALIGN uint32_t send_buf; + uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) uint8_t compute_method; - + bool format_correction; union { uint8_t power_of_2; // pre-computed power of 2 shift float float_const; // pre-computed float constant @@ -337,28 +324,17 @@ typedef struct uint32_t mclk_freq; }fixed; -#if 0 // implement later struct { - uint32_t nominal_value; - uint32_t threshold_bytes; + uint32_t nom_value; // In 16.16 format + uint32_t fifo_lvl_avg; // In 16.16 format + uint16_t fifo_lvl_thr; // fifo level threshold + uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate }fifo_count; -#endif }compute; } feedback; #endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t ep_in_ff; -#endif - - // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; -#endif - // Decoding parameters - parameters are set when alternate AS interface is set by host // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING @@ -367,8 +343,7 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING audio_data_format_type_I_t format_type_I_rx; - uint8_t n_bytes_per_sampe_rx; - uint8_t n_channels_per_ff_rx; + uint8_t n_bytes_per_sample_rx; uint8_t n_ff_used_rx; #endif #endif @@ -384,26 +359,54 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL) audio_format_type_t format_type_tx; uint8_t n_channels_tx; - uint8_t n_bytes_per_sampe_tx; + uint8_t n_bytes_per_sample_tx; #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING audio_data_format_type_I_t format_type_I_tx; - uint8_t n_channels_per_ff_tx; uint8_t n_ff_used_tx; #endif #endif + /*------------- From this point, data is not cleared by bus reset -------------*/ + + // Buffer for control requests + uint8_t * ctrl_buf; + uint8_t ctrl_buf_sz; + + // Current active alternate settings + uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! + + // EP Transfer buffers and FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t ep_out_ff; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t ep_in_ff; +#endif + + // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; +#endif + // Support FIFOs for software encoding and decoding #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t * rx_supp_ff; uint8_t n_rx_supp_ff; uint16_t rx_supp_ff_sz_max; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + uint8_t n_channels_per_ff_rx; +#endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_t * tx_supp_ff; uint8_t n_tx_supp_ff; uint16_t tx_supp_ff_sz_max; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + uint8_t n_channels_per_ff_tx; +#endif #endif // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used @@ -429,10 +432,147 @@ typedef struct #define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) +//--------------------------------------------------------------------+ +// WEAK FUNCTION STUBS +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) { + (void) rhport; + (void) func_id; + (void) ep_in; + (void) cur_alt_setting; + return true; +} + +TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_copied; + (void) func_id; + (void) ep_in; + (void) cur_alt_setting; + return true; +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_received; + (void) func_id; + (void) ep_out; + (void) cur_alt_setting; + return true; +} + +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_received; + (void) func_id; + (void) ep_out; + (void) cur_alt_setting; + return true; +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) { + (void) func_id; +} + +TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) { + (void) func_id; + (void) alt_itf; + feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED; +} + +TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) { + (void) func_id; + return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION; +} +#endif + +TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) { + (void) func_id; + (void) frame_number; + (void) interval_shift; +} + +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) { + (void) rhport; +} +#endif + +// Invoked when audio set interface request received +TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + return true; +} + +// Invoked when audio set interface request received which closes an EP +TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + return true; +} + +// Invoked when audio class specific set request received for an EP +TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No EP set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific set request received for an interface +TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No interface set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific set request received for an entity +TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No entity set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific get request received for an EP +TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No EP get request callback available!\r\n"); + return false; // Stall +} + +// Invoked when audio class specific get request received for an interface +TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No interface get request callback available!\r\n"); + return false; // Stall +} + +// Invoked when audio class specific get request received for an entity +TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No entity get request callback available!\r\n"); + return false; // Stall +} + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; +tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; #if CFG_TUD_AUDIO_ENABLE_EP_OUT static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); @@ -475,7 +615,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new); #endif bool tud_audio_n_mounted(uint8_t func_id) @@ -556,19 +697,13 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t uint8_t const *dummy2; uint8_t idx_audio_fct = 0; - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); - } + idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) - { - TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } + TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_ENABLE_DECODING switch (audio->format_type_rx) { @@ -617,13 +752,17 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); #endif +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) + { + audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff)); + } +#endif + #endif // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) - { - TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } + TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); return true; } @@ -709,16 +848,16 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u if (info.len_lin != 0) { info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; + src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx]; dst_end = info.ptr_lin + info.len_lin; - src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); + src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used); // Handle wrapped part of FIFO info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); if (info.len_wrap != 0) { dst_end = info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); + audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used); } tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); } @@ -727,6 +866,13 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it // TU_VERIFY(cnt != n_bytes); +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) + { + audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0])); + } +#endif + return true; } #endif //CFG_TUD_AUDIO_ENABLE_DECODING @@ -850,7 +996,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); // Send everything in ISO EP FIFO uint16_t n_bytes_tx; @@ -913,7 +1059,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); return true; } @@ -1026,7 +1172,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used); // Round to full number of samples (flooring) - uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx; nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; #endif @@ -1038,7 +1184,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; + dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sample_tx]; tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); @@ -1046,7 +1192,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi { info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length src_end = (uint8_t *)info.ptr_lin + info.len_lin; - dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); + dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used); // Limit up to desired length info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); @@ -1055,7 +1201,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi if (info.len_wrap != 0) { src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); + audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used); } tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); @@ -1069,9 +1215,38 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) +static inline bool audiod_fb_send(audiod_function_t *audio) { - return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); + bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction; + // Format the feedback value + if (apply_correction) + { + uint8_t * fb = (uint8_t *) &audio->feedback.send_buf; + + // For FS format is 10.14 + *(fb++) = (audio->feedback.value >> 2) & 0xFF; + *(fb++) = (audio->feedback.value >> 10) & 0xFF; + *(fb++) = (audio->feedback.value >> 18) & 0xFF; + *fb = 0; + } else + { + audio->feedback.send_buf = audio->feedback.value; + } + + // About feedback format on FS + // + // 3 variables: Format | packetSize | sendSize | Working OS: + // 16.16 4 4 Linux, Windows + // 16.16 4 3 Linux + // 16.16 3 4 Linux + // 16.16 3 3 Linux + // 10.14 4 4 Linux + // 10.14 4 3 Linux + // 10.14 3 4 Linux, OSX + // 10.14 3 3 Linux, OSX + // + // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly + return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4); } #endif @@ -1492,7 +1667,8 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #endif uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { @@ -1688,7 +1864,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); audio->ep_in = 0; // Necessary? @@ -1719,7 +1895,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); audio->ep_out = 0; // Necessary? @@ -1742,7 +1918,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) @@ -1752,7 +1929,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (foundEPs < nEps && (p_desc_end - p_desc > 0)) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { @@ -1781,8 +1959,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)) - * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)); + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)) + * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)); for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); @@ -1812,7 +1990,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; + const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx; for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); @@ -1835,9 +2013,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * { audio->ep_fb = ep_addr; audio->feedback.frame_shift = desc_ep->bInterval -1; - - // Enable SOF interrupt if callback is implemented - if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true); } #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT @@ -1850,20 +2025,23 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * TU_VERIFY(foundEPs == nEps); // Invoke one callback for a final set interface - if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Prepare feedback computation if callback is available - if (tud_audio_feedback_params_cb) + // Prepare feedback computation if endpoint is available + if(audio->ep_fb != 0) { audio_feedback_params_t fb_param; tud_audio_feedback_params_cb(func_id, alt, &fb_param); audio->feedback.compute_method = fb_param.method; + if(TUSB_SPEED_FULL == tud_speed_get()) + audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id); + // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; + audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16; audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; switch(fb_param.method) @@ -1871,20 +2049,32 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); + audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); break; - #if 0 // implement later case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { - uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; - audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); - audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; - - tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); + // Initialize the threshold level to half filled + uint16_t fifo_lvl_thr; +#if CFG_TUD_AUDIO_ENABLE_DECODING + fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2; +#else + fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; +#endif + audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; + audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16; + // Avoid 64bit division + uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100); + audio->feedback.compute.fifo_count.nom_value = nominal; + audio->feedback.compute.fifo_count.rate_const[0] = (audio->feedback.max_value - nominal) / fifo_lvl_thr; + audio->feedback.compute.fifo_count.rate_const[1] = (nominal - audio->feedback.min_value) / fifo_lvl_thr; + // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability + if(tud_speed_get() == TUSB_SPEED_HIGH) { + audio->feedback.compute.fifo_count.rate_const[0] /= 8; + audio->feedback.compute.fifo_count.rate_const[1] /= 8; + } } break; - #endif // nothing to do default: break; @@ -1902,16 +2092,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Disable SOF interrupt if no driver has any enabled feedback EP - bool disable = true; + bool enable_sof = false; for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) { - if (_audiod_fct[i].ep_fb != 0) + if (_audiod_fct[i].ep_fb != 0 && + (_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2 )) { - disable = false; + enable_sof = true; break; } } - if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false); + usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof); #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL @@ -1941,35 +2134,19 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const if (entityID != 0) { - if (tud_audio_set_req_entity_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - // Invoke callback - return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No entity set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } else { - if (tud_audio_set_req_itf_cb) - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - // Invoke callback - return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No interface set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } } break; @@ -1978,19 +2155,11 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const { uint8_t ep = TU_U16_LOW(p_request->wIndex); - if (tud_audio_set_req_ep_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - // Invoke callback - return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No EP set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } break; // Unknown/Unsupported recipient @@ -2047,15 +2216,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_entity_cb) - { - return tud_audio_get_req_entity_cb(rhport, p_request); - } - else - { - TU_LOG2(" No entity get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_entity_cb(rhport, p_request); } } else @@ -2066,15 +2227,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_itf_cb) - { - return tud_audio_get_req_itf_cb(rhport, p_request); - } - else - { - TU_LOG2(" No interface get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_itf_cb(rhport, p_request); } } } @@ -2090,15 +2243,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_ep_cb) - { - return tud_audio_get_req_ep_cb(rhport, p_request); - } - else - { - TU_LOG2(" No EP get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_ep_cb(rhport, p_request); } } break; @@ -2153,7 +2298,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // I assume here, that things above are handled by PHY // All transmission is done - what remains to do is to inform job was completed - if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport); + tud_audio_int_done_cb(rhport); return true; } @@ -2194,13 +2339,13 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // Transmission of feedback EP finished if (audio->ep_fb == ep_addr) { - if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); + tud_audio_fb_done_cb(func_id); // Schedule a transmit with the new value if EP is not busy - if (!usbd_edpt_busy(rhport, audio->ep_fb)) + if (usbd_edpt_claim(rhport, audio->ep_fb)) { // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent - return audiod_fb_send(rhport, audio); + return audiod_fb_send(audio); } } #endif @@ -2212,7 +2357,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) +static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) { // Check if frame interval is within sane limits // The interval value n_frames was taken from the descriptors within audiod_set_interface() @@ -2231,11 +2376,11 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) { audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; - audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); + audio->feedback.compute.power_of_2 = 16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq); } else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) { - audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); + audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); } else { @@ -2246,6 +2391,38 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u return true; } +static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new) +{ + /* Low-pass (averaging) filter */ + uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg; + lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6); + audio->feedback.compute.fifo_count.fifo_lvl_avg = lvl; + + uint32_t const ff_lvl = lvl >> 16; + uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr; + uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const; + + uint32_t feedback; + + if(ff_lvl < ff_thr) + { + feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0]; + } else + { + feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1]; + } + + if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; + if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + audio->feedback.value = feedback; + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (usbd_edpt_claim(audio->rhport, audio->ep_fb)) + { + audiod_fb_send(audio); + } +} + uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { audiod_function_t* audio = &_audiod_fct[func_id]; @@ -2263,7 +2440,7 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: { - uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); + uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1)); feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); } break; @@ -2282,6 +2459,21 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) return feedback; } + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + _audiod_fct[func_id].feedback.value = feedback; + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) + { + return audiod_fb_send(&_audiod_fct[func_id]); + } + + return true; +} #endif TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) @@ -2308,7 +2500,7 @@ TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); if ( 0 == (frame_count & (interval-1)) ) { - if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); + tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); } } } @@ -2396,7 +2588,8 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; uint8_t tmp = 0; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) @@ -2449,7 +2642,8 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (p_desc[3] == entityID) // Entity IDs are always at offset 3 { @@ -2473,8 +2667,8 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) // Get pointer at beginning and end uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) { @@ -2502,7 +2696,8 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) { @@ -2533,8 +2728,8 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #endif p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor - - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; @@ -2583,14 +2778,14 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #if CFG_TUD_AUDIO_ENABLE_EP_IN if (as_itf == audio->ep_in_as_intf_num) { - audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING if (as_itf == audio->ep_out_as_intf_num) { - audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + audio->n_bytes_per_sample_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } #endif } @@ -2609,7 +2804,7 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) { TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); TU_VERIFY(audio->n_channels_tx); - TU_VERIFY(audio->n_bytes_per_sampe_tx); + TU_VERIFY(audio->n_bytes_per_sample_tx); TU_VERIFY(audio->interval_tx); TU_VERIFY(audio->sample_rate_tx); @@ -2618,9 +2813,9 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); - const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); - const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); - const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); + const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); // Endpoint size must larger than packet size TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); @@ -2693,44 +2888,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da #endif -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // Format the feedback value -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION - if ( TUSB_SPEED_FULL == tud_speed_get() ) - { - uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; - - // For FS format is 10.14 - *(fb++) = (feedback >> 2) & 0xFF; - *(fb++) = (feedback >> 10) & 0xFF; - *(fb++) = (feedback >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - *fb = 0; - }else -#else - { - // Send value as-is, caller will choose the appropriate format - _audiod_fct[func_id].feedback.value = feedback; - } -#endif - - // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) - { - return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); - } - - return true; -} -#endif - // No security checks here - internal function only which should always succeed -uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) +static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) { for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) { diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index b16514fd4..ae253f49d 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -3,6 +3,7 @@ * * Copyright (c) 2020 Ha Thach (tinyusb.org) * Copyright (c) 2020 Reinhard Panhuber + * Copyright (c) 2023 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -192,6 +193,7 @@ #endif // Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). +// Can be override by tud_audio_feedback_format_correction_cb() #ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 #endif @@ -242,7 +244,8 @@ // Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size // The actual coding parameters of active AS alternate interface is parsed from the descriptors -// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! +// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple +// of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sample_sz) * sample_sz)! // This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! // For PCM encoding/decoding @@ -446,63 +449,80 @@ static inline bool tud_audio_int_write (const audio_interru bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); //--------------------------------------------------------------------+ -// Application Callback API (weak is optional) +// Application Callback API //--------------------------------------------------------------------+ #if CFG_TUD_AUDIO_ENABLE_EP_IN -TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT -TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); +void tud_audio_fb_done_cb(uint8_t func_id); -// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. +// Note about feedback calculation +// +// Option 1 - AUDIO_FEEDBACK_METHOD_FIFO_COUNT +// Feedback value is calculated within the audio driver by regulating the FIFO level to half fill. +// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, well tested +// (Windows, Linux, OSX) with a reliable result so far. +// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is introduced. +// +// Option 2 - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED / AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT +// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from +// which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter). +// See tud_audio_set_fb_params() and tud_audio_feedback_update() +// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a smaller delay is possible. +// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point is the reading of the cycle counter value of f_m. +// It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). +// Long-term drift could occur since error is accumulated. +// +// Option 3 - manual +// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. +// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load. +// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay is introduced. -// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). - -// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). // This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. // // The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, -// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb -// expects 16.16 format and handles the conversion to 10.14 on FS. +// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set or tud_audio_feedback_format_correction_cb() +// return true, then tinyusb expects 16.16 format and handles the conversion to 10.14 on FS. +// +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and it seems the +// driver can work with either format. // -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the -// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. - // Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. - +// // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec // Boiled down, the feedback value Ff = n_samples / (micro)frame. -// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) +// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 +// for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); -static inline bool tud_audio_fb_set(uint32_t feedback); -// Update feedback value with passed cycles since last time this update function is called. +// Update feedback value with passed MCLK cycles since last time this update function is called. // Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented // This function will also call tud_audio_feedback_set() // return feedback value in 16.16 for reference (0 for error) +// Example : +// binterval=3 (4ms); FS = 48kHz; MCLK = 12.288MHz +// In 4 SOF MCLK counted 49152 cycles uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); enum { AUDIO_FEEDBACK_METHOD_DISABLED, AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, - AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, - - // impelemnt later - // AUDIO_FEEDBACK_METHOD_FIFO_COUNT + AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, // For driver internal use only + AUDIO_FEEDBACK_METHOD_FIFO_COUNT }; typedef struct { @@ -514,52 +534,50 @@ typedef struct { uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on }frequency; -#if 0 // implement later - struct { - uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready - }fifo_count; -#endif }; }audio_feedback_params_t; // Invoked when needed to set feedback parameters -TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); +void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); // Callback in ISR context, invoked periodically according to feedback endpoint bInterval. // Could be used to compute and update feedback value, should be placed in RAM if possible // frame_number : current SOF count // interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor -TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); +TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); +// (Full-Speed only) Callback to set feedback format correction is applied or not, +// default to CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION if not implemented. +bool tud_audio_feedback_format_correction_cb(uint8_t func_id); #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport); +void tud_audio_int_done_cb(uint8_t rhport); #endif // Invoked when audio set interface request received -TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio set interface request received which closes an EP -TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific set request received for an EP -TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific set request received for an interface -TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific set request received for an entity -TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific get request received for an EP -TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific get request received for an interface -TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific get request received for an entity -TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); //--------------------------------------------------------------------+ // Inline Functions diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index cbf6e1332..a79908627 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -42,10 +42,14 @@ typedef struct uint8_t itf_num; uint8_t ep_ev; uint8_t ep_acl_in; + uint16_t ep_acl_in_pkt_sz; uint8_t ep_acl_out; uint8_t ep_voice[2]; // Not used yet uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; + // Previous amount of bytes sent when issuing ZLP + uint32_t prev_xferred_bytes; + // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; @@ -127,11 +131,25 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); _btd_itf.ep_ev = desc_ep->bEndpointAddress; - // Open endpoint pair - TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, - &_btd_itf.ep_acl_in), 0); + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); + // Open endpoint pair + TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *)desc_ep, 2, + TUSB_XFER_BULK, &_btd_itf.ep_acl_out, + &_btd_itf.ep_acl_in), + 0); + + // Save acl in endpoint max packet size + tusb_desc_endpoint_t const *desc_ep_acl_in = desc_ep; + for (size_t p = 0; p < 2; p++) { + if (tu_edpt_dir(desc_ep_acl_in->bEndpointAddress) == TUSB_DIR_IN) { + _btd_itf.ep_acl_in_pkt_sz = tu_edpt_packet_size(desc_ep_acl_in); + break; + } + desc_ep_acl_in = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep_acl_in); + } + + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep)); // Prepare for incoming data from host TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); @@ -238,10 +256,8 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c return true; } -bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - +bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, + uint32_t xferred_bytes) { // received new data from host if (ep_addr == _btd_itf.ep_acl_out) { @@ -256,7 +272,20 @@ bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t } else if (ep_addr == _btd_itf.ep_acl_in) { - if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + if ((result == XFER_RESULT_SUCCESS) && (xferred_bytes > 0) && + ((xferred_bytes & (_btd_itf.ep_acl_in_pkt_sz - 1)) == 0)) { + // Save number of transferred bytes + _btd_itf.prev_xferred_bytes = xferred_bytes; + + // Send zero-length packet + tud_bt_acl_data_send(NULL, 0); + } else if (tud_bt_acl_data_sent_cb) { + if (xferred_bytes == 0) { + xferred_bytes = _btd_itf.prev_xferred_bytes; + _btd_itf.prev_xferred_bytes = 0; + } + tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + } } return true; diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index f36725eba..ebc408f5a 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -45,8 +45,7 @@ //--------------------------------------------------------------------+ #define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_notif; uint8_t ep_in; @@ -56,7 +55,7 @@ typedef struct uint8_t line_state; /*------------- From this point, data is not cleared by bus reset -------------*/ - char wanted_char; + char wanted_char; TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // FIFO @@ -72,19 +71,22 @@ typedef struct // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; - -}cdcd_interface_t; +} cdcd_interface_t; #define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUD_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +static tud_cdc_configure_fifo_t _cdcd_fifo_cfg; -static bool _prep_out_transaction (cdcd_interface_t* p_cdc) -{ +static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { uint8_t const rhport = 0; + + // Skip if usb is not ready yet + TU_VERIFY(tud_ready() && p_cdc->ep_out); + uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); // Prepare for incoming data but only allow what we can store in the ring buffer. @@ -99,14 +101,11 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) // fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&p_cdc->rx_ff); - if ( available >= sizeof(p_cdc->epout_buf) ) - { + if ( available >= sizeof(p_cdc->epout_buf) ) { return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); - }else - { + }else { // Release endpoint since we don't make any transfer usbd_edpt_release(rhport, p_cdc->ep_out); - return false; } } @@ -114,51 +113,53 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_cdc_n_connected(uint8_t itf) -{ + +bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg) { + TU_VERIFY(cfg); + _cdcd_fifo_cfg = (*cfg); + return true; +} + +bool tud_cdc_n_ready(uint8_t itf) { + return tud_ready() && _cdcd_itf[itf].ep_in != 0 && _cdcd_itf[itf].ep_out != 0; +} + +bool tud_cdc_n_connected(uint8_t itf) { // DTR (bit 0) active is considered as connected return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); } -uint8_t tud_cdc_n_get_line_state (uint8_t itf) -{ +uint8_t tud_cdc_n_get_line_state(uint8_t itf) { return _cdcd_itf[itf].line_state; } -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) -{ +void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) { (*coding) = _cdcd_itf[itf].line_coding; } -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) -{ +void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { _cdcd_itf[itf].wanted_char = wanted; } - //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ -uint32_t tud_cdc_n_available(uint8_t itf) -{ +uint32_t tud_cdc_n_available(uint8_t itf) { return tu_fifo_count(&_cdcd_itf[itf].rx_ff); } -uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) -{ +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); _prep_out_transaction(p_cdc); return num_read; } -bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) -{ +bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) { return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); } -void tud_cdc_n_read_flush (uint8_t itf) -{ +void tud_cdc_n_read_flush(uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; tu_fifo_clear(&p_cdc->rx_ff); _prep_out_transaction(p_cdc); @@ -167,16 +168,15 @@ void tud_cdc_n_read_flush (uint8_t itf) //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ -uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) -{ +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size - if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE - #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE - || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size - #endif + if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE + #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size + #endif ) { tud_cdc_n_write_flush(itf); } @@ -184,30 +184,27 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) return ret; } -uint32_t tud_cdc_n_write_flush (uint8_t itf) -{ +uint32_t tud_cdc_n_write_flush(uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); + TU_VERIFY(tud_ready(), 0); // No data to send - if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; + if (!tu_fifo_count(&p_cdc->tx_ff)) return 0; uint8_t const rhport = 0; // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0); // Pull data from FIFO uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + if (count) { + TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected usbd_edpt_release(rhport, p_cdc->ep_in); @@ -215,33 +212,30 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf) } } -uint32_t tud_cdc_n_write_available (uint8_t itf) -{ +uint32_t tud_cdc_n_write_available(uint8_t itf) { return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); } -bool tud_cdc_n_write_clear (uint8_t itf) -{ +bool tud_cdc_n_write_clear(uint8_t itf) { return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); } //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void cdcd_init(void) -{ +void cdcd_init(void) { tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); + tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg)); - for(uint8_t i=0; iwanted_char = (char) -1; // default line coding is : stop bit = 1, parity = none, data bits = 8 - p_cdc->line_coding.bit_rate = 115200; + p_cdc->line_coding.bit_rate = 115200; p_cdc->line_coding.stop_bits = 0; - p_cdc->line_coding.parity = 0; + p_cdc->line_coding.parity = 0; p_cdc->line_coding.data_bits = 8; // Config RX fifo @@ -285,35 +279,28 @@ bool cdcd_deinit(void) { return true; } -void cdcd_reset(uint8_t rhport) -{ +void cdcd_reset(uint8_t rhport) { (void) rhport; - for(uint8_t i=0; irx_ff); - #if !CFG_TUD_CDC_PERSISTENT_TX_BUFF - tu_fifo_clear(&p_cdc->tx_ff); - #endif + if (!_cdcd_fifo_cfg.rx_persistent) tu_fifo_clear(&p_cdc->rx_ff); + if (!_cdcd_fifo_cfg.tx_persistent) tu_fifo_clear(&p_cdc->tx_ff); tu_fifo_set_overwritable(&p_cdc->tx_ff, true); } } -uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ +uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { // Only support ACM subclass TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0); // Find available interface - cdcd_interface_t * p_cdc = NULL; - for(uint8_t cdc_id=0; cdc_iditf_num = itf_desc->bInterfaceNumber; uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); + uint8_t const* p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { + while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) { drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); } - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { // notification endpoint - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 ); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); p_cdc->ep_notif = desc_ep->bEndpointAddress; drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { + if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { // next to endpoint descriptor drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); // Open endpoint pair - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 ); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0); - drv_len += 2*sizeof(tusb_desc_endpoint_t); + drv_len += 2 * sizeof(tusb_desc_endpoint_t); } // Prepare for incoming data @@ -368,8 +352,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ +bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { // Handle class request only TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); @@ -377,42 +360,33 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t cdcd_interface_t* p_cdc = _cdcd_itf; // Identify which interface to use - for ( ; ; itf++, p_cdc++) - { + for (;; itf++, p_cdc++) { if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false; - if ( p_cdc->itf_num == request->wIndex ) break; + if (p_cdc->itf_num == request->wIndex) break; } - switch ( request->bRequest ) - { + switch (request->bRequest) { case CDC_REQUEST_SET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { TU_LOG_DRV(" Set Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } else if (stage == CONTROL_STAGE_ACK) { + if (tud_cdc_line_coding_cb) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); } - else if ( stage == CONTROL_STAGE_ACK) - { - if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); - } - break; + break; case CDC_REQUEST_GET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { TU_LOG_DRV(" Get Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } - break; + break; case CDC_REQUEST_SET_CONTROL_LINE_STATE: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { + } else if (stage == CONTROL_STAGE_ACK) { // CDC PSTN v1.2 section 6.3.12 // Bit 0: Indicates if DTE is present or not. // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) @@ -429,61 +403,54 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); // Invoke callback - if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); + if (tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, dtr, rts); } - break; - case CDC_REQUEST_SEND_BREAK: - if (stage == CONTROL_STAGE_SETUP) - { - tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { - TU_LOG_DRV(" Send Break\r\n"); - if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); - } - break; + break; - default: return false; // stall unsupported request + case CDC_REQUEST_SEND_BREAK: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_status(rhport, request); + } else if (stage == CONTROL_STAGE_ACK) { + TU_LOG_DRV(" Send Break\r\n"); + if (tud_cdc_send_break_cb) tud_cdc_send_break_cb(itf, request->wValue); + } + break; + + default: + return false; // stall unsupported request } return true; } -bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t itf; cdcd_interface_t* p_cdc; // Identify which interface to use - for (itf = 0; itf < CFG_TUD_CDC; itf++) - { + for (itf = 0; itf < CFG_TUD_CDC; itf++) { p_cdc = &_cdcd_itf[itf]; - if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; + if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break; } TU_ASSERT(itf < CFG_TUD_CDC); // Received new data - if ( ep_addr == p_cdc->ep_out ) - { + if (ep_addr == p_cdc->ep_out) { tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); // Check for wanted char and invoke callback if needed - if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) - { - for ( uint32_t i = 0; i < xferred_bytes; i++ ) - { - if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) - { + if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) { + for (uint32_t i = 0; i < xferred_bytes; i++) { + if ((p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); } } } // invoke receive callback (if there is still data) - if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); + if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) tud_cdc_rx_cb(itf); // prepare for OUT transaction _prep_out_transaction(p_cdc); @@ -492,19 +459,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Data sent to host, we continue to fetch from tx fifo to send. // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! - if ( ep_addr == p_cdc->ep_in ) - { + if (ep_addr == p_cdc->ep_in) { // invoke transmit callback to possibly refill tx fifo - if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf); + if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf); - if ( 0 == tud_cdc_n_write_flush(itf) ) - { + if (0 == tud_cdc_n_write_flush(itf)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP Packet size and not zero - if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) - { - if ( usbd_edpt_claim(rhport, p_cdc->ep_in) ) - { + if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) { + if (usbd_edpt_claim(rhport, p_cdc->ep_in)) { usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); } } diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index db709b3bc..3ad7c8baf 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_CDC_DEVICE_H_ -#define _TUSB_CDC_DEVICE_H_ +#ifndef TUSB_CDC_DEVICE_H_ +#define TUSB_CDC_DEVICE_H_ #include "cdc.h" @@ -41,94 +41,148 @@ #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #endif -// By default the TX fifo buffer is cleared on connect / bus reset. -// Enable this to persist any data in the fifo instead. -#ifndef CFG_TUD_CDC_PERSISTENT_TX_BUFF - #define CFG_TUD_CDC_PERSISTENT_TX_BUFF (0) -#endif - #ifdef __cplusplus extern "C" { #endif -/** \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Device Device - * @{ */ +//--------------------------------------------------------------------+ +// Driver Configuration +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { + uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect + uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect +} tud_cdc_configure_fifo_t; + +// Configure CDC FIFOs behavior +bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg); //--------------------------------------------------------------------+ -// Application API (Multiple Ports) -// CFG_TUD_CDC > 1 +// Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1 //--------------------------------------------------------------------+ +// Check if interface is ready +bool tud_cdc_n_ready(uint8_t itf); + // Check if terminal is connected to this port -bool tud_cdc_n_connected (uint8_t itf); +bool tud_cdc_n_connected(uint8_t itf); // Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) -uint8_t tud_cdc_n_get_line_state (uint8_t itf); +uint8_t tud_cdc_n_get_line_state(uint8_t itf); // Get current line encoding: bit rate, stop bits parity etc .. -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); +void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding); // Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); +void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted); // Get the number of bytes available for reading -uint32_t tud_cdc_n_available (uint8_t itf); +uint32_t tud_cdc_n_available(uint8_t itf); // Read received bytes -uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize); +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize); // Read a byte, return -1 if there is none -static inline -int32_t tud_cdc_n_read_char (uint8_t itf); +TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_n_read_char(uint8_t itf) { + uint8_t ch; + return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; +} // Clear the received FIFO -void tud_cdc_n_read_flush (uint8_t itf); +void tud_cdc_n_read_flush(uint8_t itf); // Get a byte from FIFO without removing it -bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); +bool tud_cdc_n_peek(uint8_t itf, uint8_t* ui8); // Write bytes to TX FIFO, data may remain in the FIFO for a while -uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize); // Write a byte -static inline -uint32_t tud_cdc_n_write_char (uint8_t itf, char ch); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) { + return tud_cdc_n_write(itf, &ch, 1); +} // Write a null-terminated string -static inline -uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_str(uint8_t itf, char const* str) { + return tud_cdc_n_write(itf, str, strlen(str)); +} // Force sending data if possible, return number of forced bytes -uint32_t tud_cdc_n_write_flush (uint8_t itf); +uint32_t tud_cdc_n_write_flush(uint8_t itf); // Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. -uint32_t tud_cdc_n_write_available (uint8_t itf); +uint32_t tud_cdc_n_write_available(uint8_t itf); // Clear the transmit FIFO -bool tud_cdc_n_write_clear (uint8_t itf); +bool tud_cdc_n_write_clear(uint8_t itf); //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ -static inline bool tud_cdc_connected (void); -static inline uint8_t tud_cdc_get_line_state (void); -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); -static inline void tud_cdc_set_wanted_char (char wanted); -static inline uint32_t tud_cdc_available (void); -static inline int32_t tud_cdc_read_char (void); -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize); -static inline void tud_cdc_read_flush (void); -static inline bool tud_cdc_peek (uint8_t* ui8); +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_ready(void) { + return tud_cdc_n_ready(0); +} -static inline uint32_t tud_cdc_write_char (char ch); -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_cdc_write_str (char const* str); -static inline uint32_t tud_cdc_write_flush (void); -static inline uint32_t tud_cdc_write_available (void); -static inline bool tud_cdc_write_clear (void); +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_connected(void) { + return tud_cdc_n_connected(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) { + return tud_cdc_n_get_line_state(0); +} + +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) { + tud_cdc_n_get_line_coding(0, coding); +} + +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_wanted_char(char wanted) { + tud_cdc_n_set_wanted_char(0, wanted); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_available(void) { + return tud_cdc_n_available(0); +} + +TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_read_char(void) { + return tud_cdc_n_read_char(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_read(void* buffer, uint32_t bufsize) { + return tud_cdc_n_read(0, buffer, bufsize); +} + +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_read_flush(void) { + tud_cdc_n_read_flush(0); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_peek(uint8_t* ui8) { + return tud_cdc_n_peek(0, ui8); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_char(char ch) { + return tud_cdc_n_write_char(0, ch); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write(void const* buffer, uint32_t bufsize) { + return tud_cdc_n_write(0, buffer, bufsize); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_str(char const* str) { + return tud_cdc_n_write_str(0, str); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_flush(void) { + return tud_cdc_n_write_flush(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_available(void) { + return tud_cdc_n_write_available(0); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) { + return tud_cdc_n_write_clear(0); +} //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -152,103 +206,6 @@ TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p // Invoked when received send break TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline int32_t tud_cdc_n_read_char (uint8_t itf) -{ - uint8_t ch; - return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; -} - -static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) -{ - return tud_cdc_n_write(itf, &ch, 1); -} - -static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str) -{ - return tud_cdc_n_write(itf, str, strlen(str)); -} - -static inline bool tud_cdc_connected (void) -{ - return tud_cdc_n_connected(0); -} - -static inline uint8_t tud_cdc_get_line_state (void) -{ - return tud_cdc_n_get_line_state(0); -} - -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) -{ - tud_cdc_n_get_line_coding(0, coding); -} - -static inline void tud_cdc_set_wanted_char (char wanted) -{ - tud_cdc_n_set_wanted_char(0, wanted); -} - -static inline uint32_t tud_cdc_available (void) -{ - return tud_cdc_n_available(0); -} - -static inline int32_t tud_cdc_read_char (void) -{ - return tud_cdc_n_read_char(0); -} - -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) -{ - return tud_cdc_n_read(0, buffer, bufsize); -} - -static inline void tud_cdc_read_flush (void) -{ - tud_cdc_n_read_flush(0); -} - -static inline bool tud_cdc_peek (uint8_t* ui8) -{ - return tud_cdc_n_peek(0, ui8); -} - -static inline uint32_t tud_cdc_write_char (char ch) -{ - return tud_cdc_n_write_char(0, ch); -} - -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) -{ - return tud_cdc_n_write(0, buffer, bufsize); -} - -static inline uint32_t tud_cdc_write_str (char const* str) -{ - return tud_cdc_n_write_str(0, str); -} - -static inline uint32_t tud_cdc_write_flush (void) -{ - return tud_cdc_n_write_flush(0); -} - -static inline uint32_t tud_cdc_write_available(void) -{ - return tud_cdc_n_write_available(0); -} - -static inline bool tud_cdc_write_clear(void) -{ - return tud_cdc_n_write_clear(0); -} - -/** @} */ -/** @} */ - //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index ada01582e..ef6c7f3af 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -46,43 +46,68 @@ typedef struct { uint8_t itf_protocol; // Boot mouse or keyboard uint16_t report_desc_len; - CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1) - CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate - - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + uint8_t idle_rate; // up to application to handle idle rate // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration tusb_hid_descriptor_hid_t const *hid_descriptor; + + uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; } hidd_interface_t; CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ -static inline uint8_t get_index_by_itfnum(uint8_t itf_num) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUD_HID; i++) { - if (itf_num == _hidd_itf[i].itf_num) + if (itf_num == _hidd_itf[i].itf_num) { return i; + } } - return 0xFF; } +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol) { + (void) instance; + (void) protocol; +} + +TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate) { + (void) instance; + (void) idle_rate; + return true; +} + +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len) { + (void) instance; + (void) report; + (void) len; +} + +// Invoked when a transfer wasn't successful +TU_ATTR_WEAK void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes) { + (void) instance; + (void) report_type; + (void) report; + (void) xferred_bytes; +} + //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_hid_n_ready(uint8_t instance) -{ +bool tud_hid_n_ready(uint8_t instance) { uint8_t const rhport = 0; uint8_t const ep_in = _hidd_itf[instance].ep_in; return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); } -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) -{ +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) { uint8_t const rhport = 0; hidd_interface_t *p_hid = &_hidd_itf[instance]; @@ -101,14 +126,16 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, u return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); } -uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; } +uint8_t tud_hid_n_interface_protocol(uint8_t instance) { + return _hidd_itf[instance].itf_protocol; +} -uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; } +uint8_t tud_hid_n_get_protocol(uint8_t instance) { + return _hidd_itf[instance].protocol_mode; +} -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]) { hid_keyboard_report_t report; - report.modifier = modifier; report.reserved = 0; @@ -121,8 +148,8 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { hid_mouse_report_t report = { .buttons = buttons, .x = x, @@ -134,8 +161,8 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) -{ +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) { hid_abs_mouse_report_t report = { .buttons = buttons, .x = x, @@ -146,8 +173,8 @@ bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t but return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { hid_gamepad_report_t report = { .x = x, .y = y, @@ -165,28 +192,25 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ -void hidd_init(void) -{ +void hidd_init(void) { hidd_reset(0); } -bool hidd_deinit(void) -{ +bool hidd_deinit(void) { return true; } -void hidd_reset(uint8_t rhport) -{ +void hidd_reset(uint8_t rhport) { (void)rhport; tu_memclr(_hidd_itf, sizeof(_hidd_itf)); } -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); // Find available interface @@ -211,8 +235,9 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16 p_desc = tu_desc_next(p_desc); TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) + if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) { p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + } p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode p_hid->itf_num = desc_itf->bInterfaceNumber; @@ -234,8 +259,7 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16 // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ +bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex); @@ -262,90 +286,82 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { //------------- Class Specific Request -------------// switch (request->bRequest) { - case HID_REQ_CONTROL_GET_REPORT: - if (stage == CONTROL_STAGE_SETUP) { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + case HID_REQ_CONTROL_GET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t *report_buf = p_hid->ctrl_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint8_t* report_buf = p_hid->ctrl_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint16_t xferlen = 0; - uint16_t xferlen = 0; + // If host request a specific Report ID, add ID to as 1 byte of response + if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { + *report_buf++ = report_id; + req_len--; + xferlen++; + } - // If host request a specific Report ID, add ID to as 1 byte of response - if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { - *report_buf++ = report_id; - req_len--; + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); + TU_ASSERT(xferlen > 0); - xferlen++; + tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); } + break; - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len); - TU_ASSERT(xferlen > 0); + case HID_REQ_CONTROL_SET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); + } else if (stage == CONTROL_STAGE_ACK) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); - } - break; + uint8_t const* report_buf = p_hid->ctrl_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - case HID_REQ_CONTROL_SET_REPORT: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); - tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); - } else if (stage == CONTROL_STAGE_ACK) { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { + report_buf++; + report_len--; + } - uint8_t const *report_buf = p_hid->ctrl_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { - report_buf++; - report_len--; + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); } + break; - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len); - } - break; - - case HID_REQ_CONTROL_SET_IDLE: - if (stage == CONTROL_STAGE_SETUP) { - p_hid->idle_rate = tu_u16_high(request->wValue); - if (tud_hid_set_idle_cb) { - // stall request if callback return false - TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); + case HID_REQ_CONTROL_SET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + p_hid->idle_rate = tu_u16_high(request->wValue); + TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); // stall if false + tud_control_status(rhport, request); } + break; - tud_control_status(rhport, request); - } - break; + case HID_REQ_CONTROL_GET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } + break; - case HID_REQ_CONTROL_GET_IDLE: - if (stage == CONTROL_STAGE_SETUP) { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } - break; + case HID_REQ_CONTROL_GET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } + break; - case HID_REQ_CONTROL_GET_PROTOCOL: - if (stage == CONTROL_STAGE_SETUP) { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } - break; - - case HID_REQ_CONTROL_SET_PROTOCOL: - if (stage == CONTROL_STAGE_SETUP) { - tud_control_status(rhport, request); - } else if (stage == CONTROL_STAGE_ACK) { - p_hid->protocol_mode = (uint8_t)request->wValue; - if (tud_hid_set_protocol_cb) { + case HID_REQ_CONTROL_SET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_status(rhport, request); + } else if (stage == CONTROL_STAGE_ACK) { + p_hid->protocol_mode = (uint8_t) request->wValue; tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); } - } - break; + break; - default: - return false; // stall unsupported request + default: + return false; // stall unsupported request } } else { return false; // stall unsupported request @@ -354,45 +370,35 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t return true; } -bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - +bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { uint8_t instance = 0; hidd_interface_t *p_hid = _hidd_itf; // Identify which interface to use for (instance = 0; instance < CFG_TUD_HID; instance++) { p_hid = &_hidd_itf[instance]; - if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) + if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) { break; + } } TU_ASSERT(instance < CFG_TUD_HID); - // Check if there was a problem - if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue - if (tud_hid_report_fail_cb) { - tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes); - } - - // Allow a new transfer to be received if issue happened on an OUT endpoint - if (ep_addr == p_hid->ep_out) { - // Prepare the OUT endpoint to be able to receive a new transfer - TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); - } - - return true; - } - - // Sent report successfully if (ep_addr == p_hid->ep_in) { - if (tud_hid_report_complete_cb) { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes); + // Input report + if (XFER_RESULT_SUCCESS == result) { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); + } else { + tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_INPUT, p_hid->epin_buf, (uint16_t) xferred_bytes); } - } - // Received report successfully - else if (ep_addr == p_hid->ep_out) { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); + } else { + // Output report + if (XFER_RESULT_SUCCESS == result) { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); + } else { + tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes); + } + + // prepare for new transfer TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index fcbf161c4..ab2e27373 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_HID_DEVICE_H_ -#define _TUSB_HID_DEVICE_H_ +#ifndef TUSB_HID_DEVICE_H_ +#define TUSB_HID_DEVICE_H_ #include "hid.h" @@ -48,8 +48,7 @@ #endif //--------------------------------------------------------------------+ -// Application API (Multiple Instances) -// CFG_TUD_HID > 1 +// Application API (Multiple Instances) i.e. CFG_TUD_HID > 1 //--------------------------------------------------------------------+ // Check if the interface is ready to use @@ -66,7 +65,7 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u // KEYBOARD: convenient helper to send keyboard report if application // use template layout report as defined by hid_keyboard_report_t -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]); // MOUSE: convenient helper to send mouse report if application // use template layout report as defined by hid_mouse_report_t @@ -76,12 +75,6 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons // use template layout report as defined by hid_abs_mouse_report_t bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal); - -static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - // Gamepad: convenient helper to send gamepad report if application // use template layout report TUD_HID_REPORT_DESC_GAMEPAD bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); @@ -89,16 +82,40 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void); -static inline uint8_t tud_hid_interface_protocol(void); -static inline uint8_t tud_hid_get_protocol(void); -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_ready(void) { + return tud_hid_n_ready(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_interface_protocol(void) { + return tud_hid_n_interface_protocol(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_get_protocol(void) { + return tud_hid_n_get_protocol(0); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) { + return tud_hid_n_report(0, report_id, report, len); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]) { + return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { + return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) { + return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { + return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); +} //--------------------------------------------------------------------+ -// Callbacks (Weak is optional) +// Application Callbacks //--------------------------------------------------------------------+ // Invoked when received GET HID REPORT DESCRIPTOR request @@ -111,63 +128,25 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); // Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +// received data on OUT endpoint (Report ID = 0, Type = OUTPUT) void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); // Invoked when received SET_PROTOCOL request // protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); +void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); // Invoked when received SET_IDLE request. return false will stall the request -// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication +// - Idle Rate = 0 : only send report if there is changes, i.e. skip duplication // - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). -TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); +bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Invoked when sent REPORT successfully to host // Application can use this to send the next report // Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); // Invoked when a transfer wasn't successful -TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void) -{ - return tud_hid_n_ready(0); -} - -static inline uint8_t tud_hid_interface_protocol(void) -{ - return tud_hid_n_interface_protocol(0); -} - -static inline uint8_t tud_hid_get_protocol(void) -{ - return tud_hid_n_get_protocol(0); -} - -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) -{ - return tud_hid_n_report(0, report_id, report, len); -} - -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); -} - -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ - return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); -} +void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes); /* --------------------------------------------------------------------+ * HID Report Descriptor Template @@ -645,9 +624,8 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - #ifdef __cplusplus } #endif -#endif /* _TUSB_HID_DEVICE_H_ */ +#endif diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 115a8a4df..7639a8fc6 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -657,7 +657,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t const data8 = desc_report[0]; TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for (uint32_t i = 0; i < size; i++) TU_LOG(3, "%02X ", desc_report[i]); + for (uint32_t i = 0; i < size; i++) { + TU_LOG(3, "%02X ", desc_report[i]); + } TU_LOG(3, "\r\n"); switch (type) { diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 8a0fd4417..5f2dcabad 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -315,9 +315,8 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, // Read data wrapped part if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); } -#endif break; - +#endif default: break; } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 6c0efb509..879acda4f 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -154,14 +154,14 @@ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_m #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif -bool tu_fifo_write (tu_fifo_t* f, void const * p_data); -uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); +bool tu_fifo_write (tu_fifo_t* f, void const * data); +uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * data, uint16_t n); #ifdef TUP_MEM_CONST_ADDR uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); #endif -bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); -uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +bool tu_fifo_read (tu_fifo_t* f, void * buffer); +uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t n); #ifdef TUP_MEM_CONST_ADDR uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); #endif diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 80826c895..0a4462a0a 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -138,21 +138,21 @@ #elif TU_CHECK_MCU(OPT_MCU_SAMG) #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_SAMX7X) #define TUP_DCD_ENDPOINT_MAX 10 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \ TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // ST @@ -195,7 +195,6 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32F4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_USBIP_DWC2_TEST_MODE // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 #define TUP_DCD_ENDPOINT_MAX 6 @@ -210,7 +209,6 @@ // MCU with on-chip HS Phy #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS - #define TUP_USBIP_DWC2_TEST_MODE #endif #elif TU_CHECK_MCU(OPT_MCU_STM32H7) @@ -285,7 +283,6 @@ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) #define TUP_DCD_ENDPOINT_MAX 9 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_USBIP_DWC2_TEST_MODE #else #define TUP_DCD_ENDPOINT_MAX 6 #endif @@ -302,7 +299,7 @@ #elif TU_CHECK_MCU(OPT_MCU_CXD56) #define TUP_DCD_ENDPOINT_MAX 7 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // TI @@ -311,6 +308,8 @@ #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #define TUP_USBIP_MUSB + #define TUP_USBIP_MUSB_TI #define TUP_DCD_ENDPOINT_MAX 8 //--------------------------------------------------------------------+ @@ -337,10 +336,14 @@ //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_ESP32 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) +#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) + #if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" + #endif + #define TUP_DCD_ENDPOINT_MAX 0 //--------------------------------------------------------------------+ // Dialog @@ -398,10 +401,12 @@ #elif TU_CHECK_MCU(OPT_MCU_FT90X) #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_FT93X) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // Allwinner @@ -468,6 +473,16 @@ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) +//--------------------------------------------------------------------+ +// Analog Devices +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) + #define TUP_USBIP_MUSB + #define TUP_USBIP_MUSB_ADI + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #endif //--------------------------------------------------------------------+ @@ -504,7 +519,8 @@ #define TU_ATTR_FAST_FUNC #endif -#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) +// USBIP that support ISO alloc & activate API +#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_MUSB) #define TUP_DCD_EDPT_ISO_ALLOC #endif diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index b571f9b72..1501a5af6 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -214,6 +214,15 @@ enum { #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) +// USB 2.0 Spec Table 9-7: Test Mode Selectors +typedef enum { + TUSB_FEATURE_TEST_J = 1, + TUSB_FEATURE_TEST_K, + TUSB_FEATURE_TEST_SE0_NAK, + TUSB_FEATURE_TEST_PACKET, + TUSB_FEATURE_TEST_FORCE_ENABLE, +} tusb_feature_test_mode_t; + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index dde0550d3..4344575b7 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -56,8 +56,8 @@ * #define TU_VERIFY(cond) if(cond) return false; * #define TU_VERIFY(cond,ret) if(cond) return ret; * - * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} - * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} + * #define TU_ASSERT(cond) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;} + * #define TU_ASSERT(cond,ret) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;} *------------------------------------------------------------------*/ #ifdef __cplusplus @@ -70,9 +70,9 @@ #if CFG_TUSB_DEBUG #include - #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) + #define TU_MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) #else - #define _MESS_FAILED() do {} while (0) + #define TU_MESS_FAILED() do {} while (0) #endif // Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55 @@ -119,7 +119,7 @@ *------------------------------------------------------------------*/ #define TU_ASSERT_DEFINE(_cond, _ret) \ do { \ - if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ + if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ } while(0) #define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false) diff --git a/src/device/dcd.h b/src/device/dcd.h index f6735b077..3ef5188fc 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -40,19 +40,15 @@ //--------------------------------------------------------------------+ typedef enum { - DCD_EVENT_INVALID = 0, - DCD_EVENT_BUS_RESET, - DCD_EVENT_UNPLUGGED, - DCD_EVENT_SOF, - DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support - DCD_EVENT_RESUME, - - DCD_EVENT_SETUP_RECEIVED, - DCD_EVENT_XFER_COMPLETE, - - // Not an DCD event, just a convenient way to defer ISR function - USBD_EVENT_FUNC_CALL, - + DCD_EVENT_INVALID = 0, // 0 + DCD_EVENT_BUS_RESET, // 1 + DCD_EVENT_UNPLUGGED, // 2 + DCD_EVENT_SOF, // 3 + DCD_EVENT_SUSPEND, // 4 TODO LPM Sleep L1 support + DCD_EVENT_RESUME, // 5 + DCD_EVENT_SETUP_RECEIVED, // 6 + DCD_EVENT_XFER_COMPLETE, // 7 + USBD_EVENT_FUNC_CALL, // 8 Not an DCD event, just a convenient way to defer ISR function DCD_EVENT_COUNT } dcd_eventid_t; @@ -89,14 +85,6 @@ typedef struct TU_ATTR_ALIGNED(4) { }; } dcd_event_t; -typedef enum { - TEST_J = 1, - TEST_K, - TEST_SE0_NAK, - TEST_PACKET, - TEST_FORCE_ENABLE, -} test_mode_t; - //TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); //--------------------------------------------------------------------+ @@ -150,11 +138,8 @@ void dcd_disconnect(uint8_t rhport); void dcd_sof_enable(uint8_t rhport, bool en); #if CFG_TUD_TEST_MODE -// Check if the test mode is supported, returns true is test mode selector is supported -bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK; - // Put device into a test mode (needs power cycle to quit) -void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK; +void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector); #endif //--------------------------------------------------------------------+ // Endpoint API @@ -172,10 +157,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc // required for multiple configuration support. void dcd_edpt_close_all (uint8_t rhport); -// Close an endpoint. -// Since it is weak, caller must TU_ASSERT this function's existence before calling it. -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; - // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); @@ -190,12 +171,19 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +#ifdef TUP_DCD_EDPT_ISO_ALLOC // Allocate packet buffer used by ISO endpoints // Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering -TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); // Configure and enable an ISO endpoint according to descriptor -TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +#else +// Close an endpoint. +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +#endif //--------------------------------------------------------------------+ // Event API (implemented by stack) diff --git a/src/device/usbd.c b/src/device/usbd.c index 800d9c824..67faf0da7 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -46,13 +46,46 @@ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { - (void)rhport; - (void)eventid; - (void)in_isr; + (void) rhport; + (void) eventid; + (void) in_isr; } TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) { - (void)frame_count; + (void) frame_count; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_bos_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index; + return NULL; +} + +TU_ATTR_WEAK void tud_mount_cb(void) { +} + +TU_ATTR_WEAK void tud_umount_cb(void) { +} + +TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; +} + +TU_ATTR_WEAK void tud_resume_cb(void) { +} + +TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { + (void) rhport; + (void) stage; + (void) request; + return false; } TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { @@ -87,7 +120,6 @@ typedef struct { }; volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) uint8_t speed; - volatile uint8_t setup_count; volatile uint8_t sof_consumer; uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) @@ -98,6 +130,7 @@ typedef struct { }usbd_device_t; tu_static usbd_device_t _usbd_dev; +static volatile uint8_t _usbd_queued_setup; //--------------------------------------------------------------------+ // Class Driver @@ -321,9 +354,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); static bool process_set_config(uint8_t rhport, uint8_t cfg_num); static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); + #if CFG_TUD_TEST_MODE -static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + TU_VERIFY(CONTROL_STAGE_ACK == stage); + uint8_t const selector = tu_u16_high(request->wIndex); + TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + dcd_enter_test_mode(rhport, (tusb_feature_test_mode_t) selector); + return true; +} #endif + // from usbd_control.c void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); @@ -418,6 +459,7 @@ bool tud_init(uint8_t rhport) { TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); + _usbd_queued_setup = 0; #if OSAL_MUTEX_REQUIRED // Init device mutex @@ -549,13 +591,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_UNPLUGGED: TU_LOG_USBD("\r\n"); usbd_reset(event.rhport); - if (tud_umount_cb) tud_umount_cb(); + tud_umount_cb(); break; case DCD_EVENT_SETUP_RECEIVED: - _usbd_dev.setup_count--; + TU_ASSERT(_usbd_queued_setup > 0,); + _usbd_queued_setup--; TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); - if (_usbd_dev.setup_count) { + if (_usbd_queued_setup) { TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n"); break; } @@ -609,7 +652,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected if (_usbd_dev.connected) { TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); - if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + tud_suspend_cb(_usbd_dev.remote_wakeup_en); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -618,7 +661,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_RESUME: if (_usbd_dev.connected) { TU_LOG_USBD("\r\n"); - if (tud_resume_cb) tud_resume_cb(); + tud_resume_cb(); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -667,8 +710,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Vendor request if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) { - TU_VERIFY(tud_vendor_control_xfer_cb); - usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); } @@ -695,7 +736,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const } if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { - // Non standard request is not supported + // Non-standard request is not supported TU_BREAKPOINT(); return false; } @@ -739,17 +780,23 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.speed = speed; // restore speed } + _usbd_dev.cfg_num = cfg_num; + // Handle the new configuration and execute the corresponding callback if ( cfg_num ) { // switch to new configuration if not zero - TU_ASSERT( process_set_config(rhport, cfg_num) ); - if ( tud_mount_cb ) tud_mount_cb(); + if (!process_set_config(rhport, cfg_num)) { + TU_MESS_FAILED(); + TU_BREAKPOINT(); + _usbd_dev.cfg_num = 0; + return false; + } + tud_mount_cb(); } else { - if ( tud_umount_cb ) tud_umount_cb(); + tud_umount_cb(); } } - _usbd_dev.cfg_num = cfg_num; tud_control_status(rhport, p_request); } break; @@ -759,43 +806,27 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_SET_FEATURE: - // Handle the feature selector - switch(p_request->wValue) - { - // Support for remote wakeup + switch(p_request->wValue) { case TUSB_REQ_FEATURE_REMOTE_WAKEUP: TU_LOG_USBD(" Enable Remote Wakeup\r\n"); - // Host may enable remote wake up before suspending especially HID device _usbd_dev.remote_wakeup_en = true; tud_control_status(rhport, p_request); break; -#if CFG_TUD_TEST_MODE - // Support for TEST_MODE + #if CFG_TUD_TEST_MODE case TUSB_REQ_FEATURE_TEST_MODE: { // Only handle the test mode if supported and valid - TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex)); + TU_VERIFY(0 == tu_u16_low(p_request->wIndex)); - uint8_t selector = tu_u16_high(p_request->wIndex); - - // Stall request if the selected test mode isn't supported - if (!dcd_check_test_mode_support((test_mode_t)selector)) - { - TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector); - - return false; - } - - // Acknowledge request - tud_control_status(rhport, p_request); - - TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + uint8_t const selector = tu_u16_high(p_request->wIndex); + TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE); usbd_control_set_complete_callback(process_test_mode_cb); + tud_control_status(rhport, p_request); break; } -#endif /* CFG_TUD_TEST_MODE */ + #endif /* CFG_TUD_TEST_MODE */ // Stall unsupported feature selector default: return false; @@ -1029,39 +1060,34 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const switch(desc_type) { - case TUSB_DESC_DEVICE: - { + case TUSB_DESC_DEVICE: { TU_LOG_USBD(" Device\r\n"); void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); + TU_ASSERT(desc_device); // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has. // This only happens with the very first get device descriptor and EP0 size = 8 or 16. if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed && - ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) - { + ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) { // Hack here: we modify the request length to prevent usbd_control response with zlp // since we are responding with 1 packet & less data than wLength. tusb_control_request_t mod_request = *p_request; mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE; return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE); - }else - { + }else { return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t)); } } // break; // unreachable - case TUSB_DESC_BOS: - { + case TUSB_DESC_BOS: { TU_LOG_USBD(" BOS\r\n"); // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) - if (!tud_descriptor_bos_cb) return false; - uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb(); - TU_ASSERT(desc_bos); + TU_VERIFY(desc_bos); // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) ); @@ -1071,24 +1097,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const // break; // unreachable case TUSB_DESC_CONFIGURATION: - case TUSB_DESC_OTHER_SPEED_CONFIG: - { + case TUSB_DESC_OTHER_SPEED_CONFIG: { uintptr_t desc_config; - if ( desc_type == TUSB_DESC_CONFIGURATION ) - { + if ( desc_type == TUSB_DESC_CONFIGURATION ) { TU_LOG_USBD(" Configuration[%u]\r\n", desc_index); desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); - }else - { + TU_ASSERT(desc_config); + }else { // Host only request this after getting Device Qualifier descriptor TU_LOG_USBD(" Other Speed Configuration\r\n"); - TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); + TU_VERIFY(desc_config); } - TU_ASSERT(desc_config); - // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) ); @@ -1109,16 +1131,10 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } // break; // unreachable - case TUSB_DESC_DEVICE_QUALIFIER: - { + case TUSB_DESC_DEVICE_QUALIFIER: { TU_LOG_USBD(" Device Qualifier\r\n"); - - TU_VERIFY( tud_descriptor_device_qualifier_cb ); - uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); TU_VERIFY(desc_qualifier); - - // first byte of descriptor is its size return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier)); } // break; // unreachable @@ -1127,20 +1143,6 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } } -#if CFG_TUD_TEST_MODE -static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // At this point it should already be ensured that dcd_enter_test_mode() is defined - - // Only enter the test mode after the request for it has completed - TU_VERIFY(CONTROL_STAGE_ACK == stage); - - dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex)); - - return true; -} -#endif /* CFG_TUD_TEST_MODE */ - //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ @@ -1199,7 +1201,7 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - _usbd_dev.setup_count++; + _usbd_queued_setup++; send = true; break; @@ -1416,9 +1418,12 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { * In progress transfers on this EP may be delivered after this call. */ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC + (void) rhport; (void) ep_addr; + // ISO alloc/activate Should be used instead +#else rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_close, /**/); TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr); @@ -1428,6 +1433,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { _usbd_dev.ep_status[epnum][dir].stalled = 0; _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; +#endif return; } @@ -1450,21 +1456,24 @@ void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) { } bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_iso_alloc); TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX); - return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); +#else + (void) rhport; (void) ep_addr; (void) largest_packet_size; + return false; +#endif } bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); - TU_ASSERT(dcd_edpt_iso_activate); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); @@ -1472,6 +1481,10 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; return dcd_edpt_iso_activate(rhport, desc_ep); +#else + (void) rhport; (void) desc_ep; + return false; +#endif } #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index e47f674ea..7913096e3 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -109,7 +109,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request); //--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) +// Application Callbacks //--------------------------------------------------------------------+ // Invoked when received GET DEVICE DESCRIPTOR request @@ -126,31 +126,31 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); // Invoked when received GET BOS DESCRIPTOR request // Application return pointer to descriptor -TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); +uint8_t const * tud_descriptor_bos_cb(void); // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); +uint8_t const* tud_descriptor_device_qualifier_cb(void); // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); // Invoked when device is mounted (configured) -TU_ATTR_WEAK void tud_mount_cb(void); +void tud_mount_cb(void); // Invoked when device is unmounted -TU_ATTR_WEAK void tud_umount_cb(void); +void tud_umount_cb(void); // Invoked when usb bus is suspended // Within 7ms, device must draw an average of current less than 2.5 mA from bus -TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); +void tud_suspend_cb(bool remote_wakeup_en); // Invoked when usb bus is resumed -TU_ATTR_WEAK void tud_resume_cb(void); +void tud_resume_cb(void); // Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext() void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); @@ -159,7 +159,7 @@ void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); void tud_sof_cb(uint32_t frame_count); // Invoked when received control request with VENDOR TYPE -TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); //--------------------------------------------------------------------+ // Binary Device Object Store (BOS) Descriptor Templates @@ -434,8 +434,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _epsize, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(_epsize), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -553,7 +553,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) -#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ +#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ /* Standard Interface Association Descriptor (IAD) */\ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ @@ -567,7 +567,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Output Terminal Descriptor(4.7.2.5) */\ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ @@ -579,11 +579,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ 1) // Calculate wMaxPacketSize of Endpoints #define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 35cce1f7e..b1fd357aa 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -137,7 +137,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const* request); void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); -bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); diff --git a/src/host/usbh.c b/src/host/usbh.c index a94c22c4c..8c488aaa2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1421,6 +1421,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { break; case ENUM_GET_DEVICE_DESC: { + // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 + osal_task_delay(2); + uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); usbh_device_t* new_dev = get_device(new_addr); diff --git a/src/host/usbh.h b/src/host/usbh.h index 359684169..d0a5732e5 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -81,7 +81,7 @@ enum { }; typedef struct { - uint8_t max_nak; // max NAK per endpoint per frame + uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage uint8_t cpuctl; // R16: CPU Control Register uint8_t pinctl; // R17: Pin Control Register. FDUPSPI bit is ignored } tuh_configure_max3421_t; diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index f1f05f353..a3a0f3a3f 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -78,7 +78,7 @@ typedef struct // _int_set is not used with an RTOS #define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) }; + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) } //--------------------------------------------------------------------+ // TASK API diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index d9b8e1fc3..215feb481 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -168,14 +168,14 @@ enum { }; enum { - MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame + MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame to save CPU/SPI bus usage }; enum { EP_STATE_IDLE = 0, EP_STATE_COMPLETE = 1, EP_STATE_ABORTING = 2, - EP_STATE_ATTEMPT_1 = 3, // pending 1st attempt + EP_STATE_ATTEMPT_1 = 3, // Number of attempts to transfer in a frame. Incremented after each NAK EP_STATE_ATTEMPT_MAX = 15 }; @@ -183,17 +183,20 @@ enum { // //--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED { + uint8_t ep_num : 4; + uint8_t is_setup : 1; + uint8_t is_out : 1; + uint8_t is_iso : 1; +} hxfr_bm_t; + +TU_VERIFY_STATIC(sizeof(hxfr_bm_t) == 1, "size is not correct"); + typedef struct { uint8_t daddr; - union { ; - struct TU_ATTR_PACKED { - uint8_t ep_num : 4; - uint8_t is_setup : 1; - uint8_t is_out : 1; - uint8_t is_iso : 1; - }hxfr_bm; - + union { + hxfr_bm_t hxfr_bm; uint8_t hxfr; }; @@ -219,7 +222,16 @@ typedef struct { uint8_t hien; uint8_t mode; uint8_t peraddr; - uint8_t hxfr; + union { + hxfr_bm_t hxfr_bm; + uint8_t hxfr; + }; + + // owner of data in SNDFIFO, for retrying NAKed without re-writing to FIFO + struct { + uint8_t daddr; + uint8_t hxfr; + }sndfifo_owner; atomic_flag busy; // busy transferring @@ -317,33 +329,9 @@ bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_is return ret; } -static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint16_t len, bool in_isr) { - uint8_t hirq; - reg |= CMDBYTE_WRITE; - - max3421_spi_lock(rhport, in_isr); - - tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); - _hcd_data.hirq = hirq; - tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len); - - max3421_spi_unlock(rhport, in_isr); -} - -static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { - uint8_t hirq; - uint8_t const reg = RCVVFIFO_ADDR; - - max3421_spi_lock(rhport, in_isr); - - tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); - _hcd_data.hirq = hirq; - tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len); - - max3421_spi_unlock(rhport, in_isr); -} - -//------------- register write helper -------------// +//-------------------------------------------------------------------- +// Register helper +//-------------------------------------------------------------------- TU_ATTR_ALWAYS_INLINE static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) { reg_write(rhport, HIRQ_ADDR, data, in_isr); // HIRQ write 1 is clear @@ -377,6 +365,47 @@ TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t dat reg_write(rhport, SNDBC_ADDR, data, in_isr); } +//-------------------------------------------------------------------- +// FIFO access (receive, send, setup) +//-------------------------------------------------------------------- +static void hwfifo_write(uint8_t rhport, uint8_t reg, const uint8_t* buffer, uint8_t len, bool in_isr) { + uint8_t hirq; + reg |= CMDBYTE_WRITE; + + max3421_spi_lock(rhport, in_isr); + + tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len); + + max3421_spi_unlock(rhport, in_isr); +} + +// Write to SNDFIFO if len > 0 and update SNDBC +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_send(uint8_t rhport, const uint8_t* buffer, uint8_t len, bool in_isr) { + if (len) { + hwfifo_write(rhport, SNDFIFO_ADDR, buffer, len, in_isr); + } + sndbc_write(rhport, len, in_isr); +} + +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_setup(uint8_t rhport, const uint8_t* buffer, bool in_isr) { + hwfifo_write(rhport, SUDFIFO_ADDR, buffer, 8, in_isr); +} + +static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { + uint8_t hirq; + uint8_t const reg = RCVVFIFO_ADDR; + + max3421_spi_lock(rhport, in_isr); + + tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len); + + max3421_spi_unlock(rhport, in_isr); +} + //--------------------------------------------------------------------+ // Endpoint helper //--------------------------------------------------------------------+ @@ -417,7 +446,7 @@ static void free_ep(uint8_t daddr) { } } -// Check if endpoint has an queued transfer and not reach max NAK +// Check if endpoint has a queued transfer and not reach max NAK in this frame TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) { uint8_t const state = ep->state; return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) && @@ -487,6 +516,7 @@ bool hcd_init(uint8_t rhport) { reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false); // v1 is 0x01, v2 is 0x12, v3 is 0x13 + // Note: v1 and v2 has host OUT errata whose workaround is not implemented in this driver uint8_t const revision = reg_read(rhport, REVISION_ADDR, false); TU_LOG2_HEX(revision); TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false); @@ -615,22 +645,45 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e return true; } +/* The microcontroller repeatedly writes the SNDFIFO register R2 to load the FIFO with up to 64 data bytes. + * Then the microcontroller writes the SNDBC register, which this does three things: + * 1. Tells the MAX3421E SIE (Serial Interface Engine) how many bytes in the FIFO to send. + * 2. Connects the SNDFIFO and SNDBC register to the USB logic for USB transmission. + * 3. Clears the SNDBAVIRQ interrupt flag. If the second FIFO is available for µC loading, the SNDBAVIRQ immediately re-asserts. + + +-----------+ + --->| SNDBC-A | + / | SNDFIFO-A | + / +-----------+ + +------+ +-------------+ / +----------+ + | MCU |------>| R2: SNDFIFO |---- << Write R7 Flip >> ---| MAX3241E | + |(hcd) | | R7: SNDBC | / | SIE | + +------+ +-------------+ / +----------+ + +-----------+ / + | SNDBC-B | / + | SNDFIFO-B |<--- + +-----------+ + Note: xact_out() is called when starting a new transfer, continue a transfer (isr) or retry a transfer (NAK) + For NAK retry, we do not need to write to FIFO or SNDBC register again. +*/ static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 12: Programming BULK-OUT Transfers - // TODO double buffered + // TODO: double buffering for ISO transfer if (switch_ep) { peraddr_write(rhport, ep->daddr, in_isr); - - uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + const uint8_t hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); reg_write(rhport, HCTL_ADDR, hctl, in_isr); } - uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); - if (xact_len) { - fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); + // Only write to sndfifo and sdnbc register if it is not a NAKed retry + if (!(ep->daddr == _hcd_data.sndfifo_owner.daddr && ep->hxfr == _hcd_data.sndfifo_owner.hxfr)) { + // skip SNDBAV IRQ check, overwrite sndfifo if needed + const uint8_t xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + hwfifo_send(rhport, ep->buf, xact_len, in_isr); } - sndbc_write(rhport, xact_len, in_isr); + _hcd_data.sndfifo_owner.daddr = ep->daddr; + _hcd_data.sndfifo_owner.hxfr = ep->hxfr; + hxfr_write(rhport, ep->hxfr, in_isr); } @@ -648,7 +701,7 @@ static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_is static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) { peraddr_write(rhport, ep->daddr, in_isr); - fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr); + hwfifo_setup(rhport, ep->buf, in_isr); hxfr_write(rhport, HXFR_SETUP, in_isr); } @@ -662,7 +715,7 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool // status if (ep->buf == NULL || ep->total_len == 0) { - uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN)); + const uint8_t hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN)); peraddr_write(rhport, ep->daddr, in_isr); hxfr_write(rhport, hxfr, in_isr); return; @@ -823,11 +876,11 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re } static void handle_xfer_done(uint8_t rhport, bool in_isr) { - uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr); - uint8_t const hresult = hrsl & HRSL_RESULT_MASK; - uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; - uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; - uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; + const uint8_t hrsl = reg_read(rhport, HRSL_ADDR, in_isr); + const uint8_t hresult = hrsl & HRSL_RESULT_MASK; + const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num; + const uint8_t hxfr_type = _hcd_data.hxfr & 0xf0; + const uint8_t ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir); TU_VERIFY(ep, ); @@ -842,7 +895,8 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { // control endpoint -> retry immediately and return hxfr_write(rhport, _hcd_data.hxfr, in_isr); return; - } else if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { + } + if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { ep->state++; } } @@ -853,7 +907,6 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { hxfr_write(rhport, _hcd_data.hxfr, in_isr); } else if (next_ep) { // switch to next pending endpoint - // TODO could have issue with double buffered if not clear previously out data xact_generic(rhport, next_ep, true, in_isr); } else { // no more pending in this frame -> clear busy @@ -896,11 +949,15 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { if (ep->state == EP_STATE_COMPLETE) { xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr); }else { - // more to transfer - hxfr_write(rhport, _hcd_data.hxfr, in_isr); + hxfr_write(rhport, _hcd_data.hxfr, in_isr); // more to transfer } } else { // SETUP or OUT transfer + + // clear sndfifo owner since data is sent + _hcd_data.sndfifo_owner.daddr = 0xff; + _hcd_data.sndfifo_owner.hxfr = 0xff; + uint8_t xact_len; if (hxfr_type & HXFR_SETUP) { @@ -917,8 +974,7 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr); } else { - // more to transfer - xact_out(rhport, ep, false, in_isr); + xact_out(rhport, ep, false, in_isr); // more to transfer } } } @@ -978,16 +1034,16 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { // not call this handler again. So we need to loop until all IRQ are cleared while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) { if (hirq & HIRQ_RCVDAV_IRQ) { - uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num; max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1); uint8_t xact_len = 0; // RCVDAV_IRQ can trigger 2 times (dual buffered) while (hirq & HIRQ_RCVDAV_IRQ) { - uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr); + const uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr); xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); if (xact_len) { - fifo_read(rhport, ep->buf, xact_len, in_isr); + hwfifo_receive(rhport, ep->buf, xact_len, in_isr); ep->buf += xact_len; ep->xferred_len += xact_len; } diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index f912bef89..61911ab4c 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -207,6 +207,7 @@ void dcd_init(uint8_t rhport) USB_USBRSTMSK_M | USB_ENUMDONEMSK_M | USB_RESETDETMSK_M | + USB_WKUPINT_M | USB_DISCONNINTMSK_M; // host most only dcd_connect(rhport); diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index a817c5d6e..a40b3dc07 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2021 Koji KITAYAMA + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,8 +27,10 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && \ - TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) +#if CFG_TUD_ENABLED && defined(TUP_USBIP_MUSB) + +#define MUSB_DEBUG 2 +#define MUSB_REGS(rhport) ((musb_regs_t*) MUSB_BASES[rhport]) #if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED) /* GCC warns that an address may be unaligned, even though @@ -35,48 +38,30 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\""); #endif +#include "musb_type.h" #include "device/dcd.h" -#if TU_CHECK_MCU(OPT_MCU_MSP432E4) - #include "musb_msp432e.h" - -#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129) - #include "musb_tm4c.h" - - // HACK generalize later - #include "musb_type.h" - #define FIFO0_WORD FIFO0 - #define FIFO1_WORD FIFO1 - +// Following symbols must be defined by port header +// - musb_dcd_int_enable/disable/clear/get_enable +// - musb_dcd_int_handler_enter/exit +#if defined(TUP_USBIP_MUSB_TI) + #include "musb_ti.h" +#elif defined(TUP_USBIP_MUSB_ADI) + #include "musb_max32.h" #else - #error "Unsupported MCUs" + #error "Unsupported MCU" #endif /*------------------------------------------------------------------ * MACRO TYPEDEF CONSTANT ENUM DECLARATION *------------------------------------------------------------------*/ + #define REQUEST_TYPE_INVALID (0xFFu) -typedef struct { - uint_fast16_t beg; /* offset of including first element */ - uint_fast16_t end; /* offset of excluding the last element */ -} free_block_t; - -typedef struct TU_ATTR_PACKED { - uint16_t TXMAXP; - uint8_t TXCSRL; - uint8_t TXCSRH; - uint16_t RXMAXP; - uint8_t RXCSRL; - uint8_t RXCSRH; - uint16_t RXCOUNT; - uint16_t RESERVED[3]; -} hw_endpoint_t; - typedef union { - uint8_t u8; - uint16_t u16; - uint32_t u32; + volatile uint8_t u8; + volatile uint16_t u16; + volatile uint32_t u32; } hw_fifo_t; typedef struct TU_ATTR_PACKED @@ -92,134 +77,97 @@ typedef struct uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */ int8_t status_out; pipe_state_t pipe0; - pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */ + pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* pipe[direction][endpoint number - 1] */ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */ } dcd_data_t; -/*------------------------------------------------------------------ - * INTERNAL OBJECT & FUNCTION DECLARATION - *------------------------------------------------------------------*/ static dcd_data_t _dcd; +//-------------------------------------------------------------------- +// HW FIFO Helper +// Note: Index register is already set by caller +//-------------------------------------------------------------------- -static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr) -{ - free_block_t *cur = beg; - for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ; - return cur; -} +#if MUSB_CFG_DYNAMIC_FIFO -static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size) -{ - free_block_t *p = find_containing_block(blks, blks + num, addr); - TU_ASSERT(p != blks + num, -2); - if (p->beg == addr) { - /* Shrink block */ - p->beg = addr + size; - if (p->beg != p->end) return 0; - /* remove block */ - free_block_t *end = blks + num; - while (p + 1 < end) { - *p = *(p + 1); - ++p; - } - return -1; - } else { - /* Split into 2 blocks */ - free_block_t tmp = { - .beg = addr + size, - .end = p->end - }; - p->end = addr; - if (p->beg == p->end) { - if (tmp.beg != tmp.end) { - *p = tmp; - return 0; - } - /* remove block */ - free_block_t *end = blks + num; - while (p + 1 < end) { - *p = *(p + 1); - ++p; - } - return -1; - } - if (tmp.beg == tmp.end) return 0; - blks[num] = tmp; - return 1; +// musb is configured to use dynamic FIFO sizing. +// FF Size is encodded: 1 << (fifo_size[3:0] + 3) = 8 << fifo_size[3:0] +// FF Address is 8*ff_addr[12:0] +// First 64 bytes are reserved for EP0 +static uint32_t alloced_fifo_bytes; + +// ffsize is log2(mps) - 3 (round up) +TU_ATTR_ALWAYS_INLINE static inline uint8_t hwfifo_byte2size(uint16_t nbytes) { + uint8_t ffsize = 28 - tu_min8(28, __builtin_clz(nbytes)); + if ((8u << ffsize) < nbytes) { + ++ffsize; } + return ffsize; } -static inline unsigned free_block_size(free_block_t const *blk) -{ - return blk->end - blk->beg; +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) { + (void) epnum; + musb->fifo_size[is_rx] = 0; + musb->fifo_addr[is_rx] = 0; } -#if 0 -static inline void print_block_list(free_block_t const *blk, unsigned num) -{ - TU_LOG1("*************\r\n"); - for (unsigned i = 0; i < num; ++i) { - TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end); - ++blk; +TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps, + bool double_packet) { + (void) epnum; + uint8_t ffsize = hwfifo_byte2size(mps); + mps = 8 << ffsize; // round up to the next power of 2 + + if (double_packet) { + ffsize |= MUSB_FIFOSZ_DOUBLE_PACKET; + mps <<= 1; } + + TU_ASSERT(alloced_fifo_bytes + mps <= MUSB_CFG_DYNAMIC_FIFO_SIZE); + musb->fifo_addr[is_rx] = alloced_fifo_bytes / 8; + musb->fifo_size[is_rx] = ffsize; + + alloced_fifo_bytes += mps; + return true; } + #else -#define print_block_list(a,b) + +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) { + (void) musb; (void) epnum; (void) is_rx; + // nothing to do for static FIFO +} + +TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps, + bool double_packet) { + (void) epnum; (void) mps; + if (!double_packet) { + #if defined(TUP_USBIP_MUSB_ADI) + musb->indexed_csr.maxp_csr[is_rx].csrh |= MUSB_CSRH_DISABLE_DOUBLE_PACKET(is_rx); + #else + if (is_rx) { + musb->rx_doulbe_packet_disable |= 1u << epnum; + } else { + musb->tx_double_packet_disable |= 1u << epnum; + } + #endif + } + + return true; +} + #endif -static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3) -{ - free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)]; - unsigned num_blocks = 1; - - /* Initialize free memory block list */ - free_blocks[0].beg = 64 / 8; - free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */ - for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - uint_fast16_t addr; - int num; - USB0->EPIDX = i; - addr = USB0->TXFIFOADD; - if (addr) { - unsigned sz = USB0->TXFIFOSZ; - unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0); - num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft); - TU_ASSERT(-2 < num, 0); - num_blocks += num; - print_block_list(free_blocks, num_blocks); - } - addr = USB0->RXFIFOADD; - if (addr) { - unsigned sz = USB0->RXFIFOSZ; - unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0); - num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft); - TU_ASSERT(-2 < num, 0); - num_blocks += num; - print_block_list(free_blocks, num_blocks); +// Flush FIFO and clear data toggle +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigned epnum, unsigned is_rx, bool clear_dtog) { + (void) epnum; + const uint8_t csrl_dtog = clear_dtog ? MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx) : 0; + musb_ep_maxp_csr_t* maxp_csr = &musb->indexed_csr.maxp_csr[is_rx]; + // may need to flush twice for double packet + for (unsigned i=0; i<2; i++) { + if (maxp_csr->csrl & MUSB_CSRL_PACKET_READY(is_rx)) { + maxp_csr->csrl = MUSB_CSRL_FLUSH_FIFO(is_rx) | csrl_dtog; } } - print_block_list(free_blocks, num_blocks); - - /* Find the best fit memory block */ - uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3; - free_block_t const *min = NULL; - uint_fast16_t min_sz = 0xFFFFu; - free_block_t const *end = &free_blocks[num_blocks]; - for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) { - uint_fast16_t sz = free_block_size(cur); - if (sz < size_in_8byte_unit) continue; - if (size_in_8byte_unit == sz) return cur->beg; - if (sz < min_sz) min = cur; - } - TU_ASSERT(min, 0); - return min->beg; -} - -static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1) -{ - volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1); - return regs + epnum_minus1; } static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len) @@ -284,11 +232,14 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne ops[dir].tu_fifo_advance(f, total_len - rem); } -static void process_setup_packet(uint8_t rhport) -{ +static void process_setup_packet(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + + // Read setup packet uint32_t *p = (void*)&_dcd.setup_packet; - p[0] = USB0->FIFO0_WORD; - p[1] = USB0->FIFO0_WORD; + volatile uint32_t *fifo_ptr = &musb_regs->fifo[0]; + p[0] = *fifo_ptr; + p[1] = *fifo_ptr; _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; @@ -299,12 +250,16 @@ static void process_setup_packet(uint8_t rhport) _dcd.remaining_ctrl = len; const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType); /* Clear RX FIFO and reverse the transaction direction */ - if (len && dir_in) USB0->CSRL0 = USB_CSRL0_RXRDYC; + if (len && dir_in) { + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + ep_csr->csr0l = MUSB_CSRL0_RXRDYC; + } } -static bool handle_xfer_in(uint_fast8_t ep_addr) +static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) { - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; const unsigned rem = pipe->remaining; @@ -313,44 +268,49 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) return true; } - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - const unsigned mps = regs->TXMAXP; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + const unsigned mps = ep_csr->tx_maxp; const unsigned len = TU_MIN(mps, rem); void *buf = pipe->buf; + volatile void *fifo_ptr = &musb_regs->fifo[epnum]; // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem); if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN); + pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN); } else { - pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len); + pipe_write_packet(buf, fifo_ptr, len); pipe->buf = buf + len; } pipe->remaining = rem - len; } - regs->TXCSRL = USB_TXCSRL1_TXRDY; - // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); + ep_csr->tx_csrl = MUSB_TXCSRL1_TXRDY; + // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum, ep_csr->tx_csrl, rem - len); return false; } -static bool handle_xfer_out(uint_fast8_t ep_addr) +static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) { - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl); - TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY); + TU_ASSERT(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY); - const unsigned mps = regs->RXMAXP; + const unsigned mps = ep_csr->rx_maxp; const unsigned rem = pipe->remaining; - const unsigned vld = regs->RXCOUNT; + const unsigned vld = ep_csr->rx_count; const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); void *buf = pipe->buf; + volatile void *fifo_ptr = &musb_regs->fifo[epnum]; if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_OUT); + pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT); } else { - pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len); + pipe_read_packet(buf, fifo_ptr, len); pipe->buf = buf + len; } pipe->remaining = rem - len; @@ -359,15 +319,14 @@ static bool handle_xfer_out(uint_fast8_t ep_addr) pipe->buf = NULL; return NULL != buf; } - regs->RXCSRL = 0; /* Clear RXRDY bit */ + ep_csr->rx_csrl = 0; /* Clear RXRDY bit */ return false; } static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { - (void)rhport; - - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; unsigned dir_in = tu_edpt_dir(ep_addr); pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1]; @@ -376,10 +335,11 @@ static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16 pipe->remaining = total_bytes; if (dir_in) { - handle_xfer_in(ep_addr); + handle_xfer_in(rhport, ep_addr); } else { - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) ep_csr->rx_csrl = 0; } return true; } @@ -388,7 +348,8 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ { (void)rhport; TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */ - + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); const unsigned req = _dcd.setup_packet.bmRequestType; TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0); @@ -399,7 +360,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ * may have already finished and received the next setup packet * without calling this function, so we have no choice but to * invoke the callback function of status packet here. */ - // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" STATUS OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.status_out = 0; if (req == REQUEST_TYPE_INVALID) { dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); @@ -415,8 +376,9 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl); const unsigned rem = _dcd.remaining_ctrl; const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes); + volatile void *fifo_ptr = &musb_regs->fifo[0]; if (dir_in) { - pipe_write_packet(buffer, &USB0->FIFO0_WORD, len); + pipe_write_packet(buffer, fifo_ptr, len); _dcd.pipe0.buf = buffer + len; _dcd.pipe0.length = len; @@ -427,45 +389,48 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */ _dcd.status_out = 1; /* Flush TX FIFO and reverse the transaction direction. */ - USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_TXRDY | MUSB_CSRL0_DATAEND; } else { - USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */ + ep_csr->csr0l = MUSB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */ } - // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l); } else { - // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.pipe0.buf = buffer; _dcd.pipe0.length = len; _dcd.pipe0.remaining = len; - USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */ + ep_csr->csr0l = MUSB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */ } } else if (dir_in) { - // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" STATUS IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; /* Clear RX FIFO and reverse the transaction direction */ - USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND; } return true; } static void process_ep0(uint8_t rhport) { - uint_fast8_t csrl = USB0->CSRL0; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + uint_fast8_t csrl = ep_csr->csr0l; - // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl); + // TU_LOG1(" EP0 ep_csr->csr0l = %x\r\n", csrl); + // 21.1.5: endpoint 0 service routine as peripheral - if (csrl & USB_CSRL0_STALLED) { + if (csrl & MUSB_CSRL0_STALLED) { /* Returned STALL packet to HOST. */ - USB0->CSRL0 = 0; /* Clear STALL */ + ep_csr->csr0l = 0; /* Clear STALL */ return; } unsigned req = _dcd.setup_packet.bmRequestType; - if (csrl & USB_CSRL0_SETEND) { + if (csrl & MUSB_CSRL0_SETEND) { TU_LOG1(" ABORT by the next packets\r\n"); - USB0->CSRL0 = USB_CSRL0_SETENDC; + ep_csr->csr0l = MUSB_CSRL0_SETENDC; if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) { /* DATA stage was aborted by receiving STATUS or SETUP packet. */ _dcd.pipe0.buf = NULL; @@ -476,23 +441,24 @@ static void process_ep0(uint8_t rhport) XFER_RESULT_SUCCESS, true); } req = REQUEST_TYPE_INVALID; - if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */ + if (!(csrl & MUSB_CSRL0_RXRDY)) return; /* Received SETUP packet */ } - if (csrl & USB_CSRL0_RXRDY) { + if (csrl & MUSB_CSRL0_RXRDY) { /* Received SETUP or DATA OUT packet */ if (req == REQUEST_TYPE_INVALID) { /* SETUP */ - TU_ASSERT(sizeof(tusb_control_request_t) == USB0->COUNT0,); + TU_ASSERT(sizeof(tusb_control_request_t) == ep_csr->count0,); process_setup_packet(rhport); return; } if (_dcd.pipe0.buf) { /* DATA OUT */ - const unsigned vld = USB0->COUNT0; + const unsigned vld = ep_csr->count0; const unsigned rem = _dcd.pipe0.remaining; const unsigned len = TU_MIN(TU_MIN(rem, 64), vld); - pipe_read_packet(_dcd.pipe0.buf, &USB0->FIFO0_WORD, len); + volatile void *fifo_ptr = &musb_regs->fifo[0]; + pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len); _dcd.pipe0.remaining = rem - len; _dcd.remaining_ctrl -= len; @@ -512,7 +478,7 @@ static void process_ep0(uint8_t rhport) /* STATUS IN */ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) { /* The address must be changed on completion of the control transfer. */ - USB0->FADDR = (uint8_t)_dcd.setup_packet.wValue; + musb_regs->faddr = (uint8_t)_dcd.setup_packet.wValue; } _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; dcd_event_xfer_complete(rhport, @@ -534,118 +500,147 @@ static void process_ep0(uint8_t rhport) static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr) { bool completed; - const unsigned dir_in = tu_edpt_dir(ep_addr); - const unsigned epn_minus1 = tu_edpt_number(ep_addr) - 1; + const unsigned dir_in = tu_edpt_dir(ep_addr); + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned epn_minus1 = epn - 1; - volatile hw_endpoint_t *regs = edpt_regs(epn_minus1); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); if (dir_in) { - // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL); - if (regs->TXCSRL & USB_TXCSRL1_STALLED) { - regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN); + // TU_LOG1(" TX CSRL%d = %x\r\n", epn, ep_csr->tx_csrl); + if (ep_csr->tx_csrl & MUSB_TXCSRL1_STALLED) { + ep_csr->tx_csrl &= ~(MUSB_TXCSRL1_STALLED | MUSB_TXCSRL1_UNDRN); return; } - completed = handle_xfer_in(ep_addr); + completed = handle_xfer_in(rhport, ep_addr); } else { - // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL); - if (regs->RXCSRL & USB_RXCSRL1_STALLED) { - regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER); + // TU_LOG1(" RX CSRL%d = %x\r\n", epn, ep_csr->rx_csrl); + if (ep_csr->rx_csrl & MUSB_RXCSRL1_STALLED) { + ep_csr->rx_csrl &= ~(MUSB_RXCSRL1_STALLED | MUSB_RXCSRL1_OVER); return; } - completed = handle_xfer_out(ep_addr); + completed = handle_xfer_out(rhport, ep_addr); } if (completed) { - pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1]; + pipe_state_t *pipe = &_dcd.pipe[dir_in][epn_minus1]; dcd_event_xfer_complete(rhport, ep_addr, pipe->length - pipe->remaining, XFER_RESULT_SUCCESS, true); } } -static void process_bus_reset(uint8_t rhport) -{ - /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF), - * a control transfer state is SETUP or STATUS stage. */ +// Upon BUS RESET is detected, hardware havs already done: +// faddr = 0, index = 0, flushes all ep fifos, clears all ep csr, enabled all ep interrupts +static void process_bus_reset(uint8_t rhport) { + musb_regs_t* musb = MUSB_REGS(rhport); + +#if MUSB_CFG_DYNAMIC_FIFO + alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE; +#endif + + /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF), a control transfer state is SETUP or STATUS stage. */ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; _dcd.status_out = 0; /* When pipe0.buf has not NULL, DATA stage works in progress. */ _dcd.pipe0.buf = NULL; - USB0->TXIE = 1; /* Enable only EP0 */ - USB0->RXIE = 0; + musb->intr_txen = 1; /* Enable only EP0 */ + musb->intr_rxen = 0; /* Clear FIFO settings */ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - USB0->EPIDX = i; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; + musb->index = i; + hwfifo_reset(musb, i, 0); + hwfifo_reset(musb, i, 1); } - dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); + dcd_event_bus_reset(rhport, (musb->power & MUSB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true); } /*------------------------------------------------------------------ * Device API *------------------------------------------------------------------*/ -void dcd_init(uint8_t rhport) -{ - (void)rhport; - USB0->IE |= USB_IE_SUSPND; - NVIC_ClearPendingIRQ(USB0_IRQn); +#if CFG_TUSB_DEBUG >= MUSB_DEBUG +void print_musb_info(musb_regs_t* musb_regs) { + // print version, epinfo, raminfo, config_data0, fifo_size + TU_LOG1("musb version = %u.%u\r\n", musb_regs->hwvers_bit.major, musb_regs->hwvers_bit.minor); + TU_LOG1("Number of endpoints: %u TX, %u RX\r\n", musb_regs->epinfo_bit.tx_ep_num, musb_regs->epinfo_bit.rx_ep_num); + TU_LOG1("RAM Info: %u DMA Channel, %u RAM address width\r\n", musb_regs->raminfo_bit.dma_channel, musb_regs->raminfo_bit.ram_bits); + musb_regs->index = 0; + TU_LOG1("config_data0 = 0x%x\r\n", musb_regs->indexed_csr.config_data0); + +#if MUSB_CFG_DYNAMIC_FIFO + TU_LOG1("Dynamic FIFO configuration\r\n"); +#else + for (uint8_t i=1; i <= musb_regs->epinfo_bit.tx_ep_num; i++) { + musb_regs->index = i; + TU_LOG1("FIFO %u Size: TX %u RX %u\r\n", i, musb_regs->indexed_csr.fifo_size_bit.tx, musb_regs->indexed_csr.fifo_size_bit.rx); + } +#endif +} +#endif + +void dcd_init(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + +#if CFG_TUSB_DEBUG >= MUSB_DEBUG + print_musb_info(musb_regs); +#endif + + musb_regs->intr_usben |= MUSB_IE_SUSPND; + musb_dcd_int_clear(rhport); + musb_dcd_phy_init(rhport); dcd_connect(rhport); } -void dcd_int_enable(uint8_t rhport) -{ - (void)rhport; - NVIC_EnableIRQ(USB0_IRQn); +void dcd_int_enable(uint8_t rhport) { + musb_dcd_int_enable(rhport); } -void dcd_int_disable(uint8_t rhport) -{ - (void)rhport; - NVIC_DisableIRQ(USB0_IRQn); +void dcd_int_disable(uint8_t rhport) { + musb_dcd_int_disable(rhport); } // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void)rhport; (void)dev_addr; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; /* Clear RX FIFO to return ACK. */ - USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND; } // Wake up host -void dcd_remote_wakeup(uint8_t rhport) -{ - (void)rhport; - USB0->POWER |= USB_POWER_RESUME; +void dcd_remote_wakeup(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power |= MUSB_POWER_RESUME; unsigned cnt = SystemCoreClock / 1000; while (cnt--) __NOP(); - USB0->POWER &= ~USB_POWER_RESUME; + musb_regs->power &= ~MUSB_POWER_RESUME; } // Connect by enabling internal pull-up resistor on D+/D- void dcd_connect(uint8_t rhport) { - (void)rhport; - USB0->POWER |= USB_POWER_SOFTCONN; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power |= TUD_OPT_HIGH_SPEED ? MUSB_POWER_HSENAB : 0; + musb_regs->power |= MUSB_POWER_SOFTCONN; } // Disconnect by disabling internal pull-up resistor on D+/D- void dcd_disconnect(uint8_t rhport) { - (void)rhport; - USB0->POWER &= ~USB_POWER_SOFTCONN; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power &= ~MUSB_POWER_SOFTCONN; } void dcd_sof_enable(uint8_t rhport, bool en) @@ -659,129 +654,119 @@ void dcd_sof_enable(uint8_t rhport, bool en) //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ +// static void edpt_setup(musb_regs_t* musb, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_size){ +// const unsigned epn = tu_edpt_number(ep_addr); +// const unsigned dir_in = tu_edpt_dir(ep_addr); +// } // Configure endpoint's registers according to descriptor -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) -{ - (void) rhport; - +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { const unsigned ep_addr = ep_desc->bEndpointAddress; const unsigned epn = tu_edpt_number(ep_addr); const unsigned dir_in = tu_edpt_dir(ep_addr); - const unsigned xfer = ep_desc->bmAttributes.xfer; const unsigned mps = tu_edpt_packet_size(ep_desc); - TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX); - pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1]; pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; - volatile hw_endpoint_t *regs = edpt_regs(epn - 1); - if (dir_in) { - regs->TXMAXP = mps; - regs->TXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_TXCSRH1_ISO : 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; - USB0->TXIE |= TU_BIT(epn); - } else { - regs->RXMAXP = mps; - regs->RXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_RXCSRH1_ISO : 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; - USB0->RXIE |= TU_BIT(epn); - } + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; - /* Setup FIFO */ - int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps)); - if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3; - unsigned addr = find_free_memory(size_in_log2_minus3); - TU_ASSERT(addr); - - USB0->EPIDX = epn; + maxp_csr->maxp = mps; + maxp_csr->csrh = 0; +#if MUSB_CFG_SHARED_FIFO if (dir_in) { - USB0->TXFIFOADD = addr; - USB0->TXFIFOSZ = size_in_log2_minus3; - } else { - USB0->RXFIFOADD = addr; - USB0->RXFIFOSZ = size_in_log2_minus3; + maxp_csr->csrh |= MUSB_CSRH_TX_MODE; } +#endif + + hwfifo_flush(musb, epn, is_rx, true); + + TU_ASSERT(hwfifo_config(musb, epn, is_rx, mps, false)); + musb->intren_ep[is_rx] |= TU_BIT(epn); + + return true; +} + +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir_in = tu_edpt_dir(ep_addr); + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + ep_csr->maxp_csr[is_rx].csrh = 0; + return hwfifo_config(musb, epn, is_rx, largest_packet_size, true); +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) { + const unsigned ep_addr = ep_desc->bEndpointAddress; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir_in = tu_edpt_dir(ep_addr); + const unsigned mps = tu_edpt_packet_size(ep_desc); + + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + + pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1]; + pipe->buf = NULL; + pipe->length = 0; + pipe->remaining = 0; + + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; + + maxp_csr->maxp = mps; + maxp_csr->csrh |= MUSB_CSRH_ISO; +#if MUSB_CFG_SHARED_FIFO + if (dir_in) { + maxp_csr->csrh |= MUSB_CSRH_TX_MODE; + } +#endif + + hwfifo_flush(musb, epn, is_rx, true); + +#if MUSB_CFG_DYNAMIC_FIFO + // fifo space is already allocated, keep the address and just change packet size + musb->fifo_size[is_rx] = hwfifo_byte2size(mps) | MUSB_FIFOSZ_DOUBLE_PACKET; +#endif + + musb->intren_ep[is_rx] |= TU_BIT(epn); + + if (ie) musb_dcd_int_enable(rhport); return true; } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; - volatile hw_endpoint_t *regs = (volatile hw_endpoint_t *)(uintptr_t)&USB0->TXMAXP1; - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - USB0->TXIE = 1; /* Enable only EP0 */ - USB0->RXIE = 0; + musb_regs_t* musb = MUSB_REGS(rhport); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + + musb->intr_txen = 1; /* Enable only EP0 */ + musb->intr_rxen = 0; for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - regs->TXMAXP = 0; - regs->TXCSRH = 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; - - regs->RXMAXP = 0; - regs->RXCSRH = 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; - - USB0->EPIDX = i; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; + musb_ep_csr_t* ep_csr = get_ep_csr(musb, i); + for (unsigned d = 0; d < 2; d++) { + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[d]; + hwfifo_flush(musb, i, d, true); + hwfifo_reset(musb, i, d); + maxp_csr->maxp = 0; + maxp_csr->csrh = 0; + } } - if (ie) NVIC_EnableIRQ(USB0_IRQn); -} -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; - unsigned const epn = tu_edpt_number(ep_addr); - unsigned const dir_in = tu_edpt_dir(ep_addr); +#if MUSB_CFG_DYNAMIC_FIFO + alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE; +#endif - hw_endpoint_t volatile *regs = edpt_regs(epn - 1); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - if (dir_in) { - USB0->TXIE &= ~TU_BIT(epn); - regs->TXMAXP = 0; - regs->TXCSRH = 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; - - USB0->EPIDX = epn; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - } else { - USB0->RXIE &= ~TU_BIT(epn); - regs->RXMAXP = 0; - regs->RXCSRH = 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; - - USB0->EPIDX = epn; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; - } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) musb_dcd_int_enable(rhport); } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack @@ -791,18 +776,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + if (epnum) { _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1); ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes); - } else + } else { ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes); - if (ie) NVIC_EnableIRQ(USB0_IRQn); + } + + if (ie) musb_dcd_int_enable(rhport); return ret; } -// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c +// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack +// - optional, however, must be listed in usbd.c bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void)rhport; @@ -810,99 +799,104 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); TU_ASSERT(epnum); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1); ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes); - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) musb_dcd_int_enable(rhport); return ret; } // Stall endpoint -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + unsigned const epn = tu_edpt_number(ep_addr); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); + if (0 == epn) { if (!ep_addr) { /* Ignore EP80 */ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; _dcd.pipe0.buf = NULL; - USB0->CSRL0 = USB_CSRL0_STALL; + ep_csr->csr0l = MUSB_CSRL0_STALL; } } else { - volatile hw_endpoint_t *regs = edpt_regs(epn - 1); - if (tu_edpt_dir(ep_addr)) { /* IN */ - regs->TXCSRL = USB_TXCSRL1_STALL; - } else { /* OUT */ - TU_ASSERT(!(regs->RXCSRL & USB_RXCSRL1_RXRDY),); - regs->RXCSRL = USB_RXCSRL1_STALL; - } + const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr); + ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx); } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + + if (ie) musb_dcd_int_enable(rhport); } // clear stall, data toggle is also reset to DATA0 void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + unsigned const epn = tu_edpt_number(ep_addr); - hw_endpoint_t volatile *regs = edpt_regs(epn - 1); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - if (tu_edpt_dir(ep_addr)) { /* IN */ - regs->TXCSRL = USB_TXCSRL1_CLRDT; - } else { /* OUT */ - regs->RXCSRL = USB_RXCSRL1_CLRDT; - } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); + const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr); + + ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx); + + if (ie) musb_dcd_int_enable(rhport); } /*------------------------------------------------------------------- * ISR *-------------------------------------------------------------------*/ -void dcd_int_handler(uint8_t rhport) -{ - uint_fast8_t is, txis, rxis; +void dcd_int_handler(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + const uint8_t saved_index = musb_regs->index; // save endpoint index - is = USB0->IS; /* read and clear interrupt status */ - txis = USB0->TXIS; /* read and clear interrupt status */ - rxis = USB0->RXIS; /* read and clear interrupt status */ + //Part specific ISR setup/entry + musb_dcd_int_handler_enter(rhport); + + uint_fast8_t intr_usb = musb_regs->intr_usb; // a read will clear this interrupt status + uint_fast8_t intr_tx = musb_regs->intr_tx; // a read will clear this interrupt status + uint_fast8_t intr_rx = musb_regs->intr_rx; // a read will clear this interrupt status // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis); - is &= USB0->IE; /* Clear disabled interrupts */ - if (is & USB_IS_DISCON) { + intr_usb &= musb_regs->intr_usben; /* Clear disabled interrupts */ + if (intr_usb & MUSB_IS_DISCON) { } - if (is & USB_IS_SOF) { + if (intr_usb & MUSB_IS_SOF) { dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); } - if (is & USB_IS_RESET) { + if (intr_usb & MUSB_IS_RESET) { process_bus_reset(rhport); } - if (is & USB_IS_RESUME) { + if (intr_usb & MUSB_IS_RESUME) { dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } - if (is & USB_IS_SUSPEND) { + if (intr_usb & MUSB_IS_SUSPEND) { dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - txis &= USB0->TXIE; /* Clear disabled interrupts */ - if (txis & USB_TXIE_EP0) { + intr_tx &= musb_regs->intr_txen; /* Clear disabled interrupts */ + if (intr_tx & TU_BIT(0)) { process_ep0(rhport); - txis &= ~TU_BIT(0); + intr_tx &= ~TU_BIT(0); } - while (txis) { - unsigned const num = __builtin_ctz(txis); + while (intr_tx) { + unsigned const num = __builtin_ctz(intr_tx); process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN)); - txis &= ~TU_BIT(num); + intr_tx &= ~TU_BIT(num); } - rxis &= USB0->RXIE; /* Clear disabled interrupts */ - while (rxis) { - unsigned const num = __builtin_ctz(rxis); + + intr_rx &= musb_regs->intr_rxen; /* Clear disabled interrupts */ + while (intr_rx) { + unsigned const num = __builtin_ctz(intr_rx); process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT)); - rxis &= ~TU_BIT(num); + intr_rx &= ~TU_BIT(num); } + + musb_regs->index = saved_index; // restore endpoint index } #endif diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 5312c2812..8fc225676 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -37,16 +37,10 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\""); #include "host/hcd.h" -#if TU_CHECK_MCU(OPT_MCU_MSP432E4) - #include "musb_msp432e.h" - -#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129) - #include "musb_tm4c.h" - - // HACK generalize later - #include "musb_type.h" - #define FIFO0_WORD FIFO0 +#include "musb_type.h" +#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #include "musb_ti.h" #else #error "Unsupported MCUs" #endif diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h new file mode 100644 index 000000000..35849b5f8 --- /dev/null +++ b/src/portable/mentor/musb/musb_max32.h @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MUSB_MAX32_H_ +#define TUSB_MUSB_MAX32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mxc_device.h" +#include "usbhs_regs.h" + +#define MUSB_CFG_SHARED_FIFO 1 // shared FIFO for TX and RX endpoints +#define MUSB_CFG_DYNAMIC_FIFO 0 // dynamic EP FIFO sizing + +const uintptr_t MUSB_BASES[] = { MXC_BASE_USBHS }; + +#if CFG_TUD_ENABLED +#define USBHS_M31_CLOCK_RECOVERY + +// Mapping of IRQ numbers to port. Currently just 1. +static const IRQn_Type musb_irqs[] = { + USB_IRQn +}; + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) { + #ifdef NVIC_GetEnableIRQ // only defined in CMSIS 5 + return NVIC_GetEnableIRQ(musb_irqs[rhport]); + #else + uint32_t IRQn = (uint32_t) musb_irqs[rhport]; + return ((NVIC->ISER[IRQn >> 5UL] & (1UL << (IRQn & 0x1FUL))) != 0UL) ? 1UL : 0UL; + #endif +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) { + NVIC_ClearPendingIRQ(musb_irqs[rhport]); +} + +static inline void musb_dcd_int_handler_enter(uint8_t rhport) { + mxc_usbhs_regs_t* hs_phy = MXC_USBHS; + uint32_t mxm_int, mxm_int_en, mxm_is; + + //Handle PHY specific events + mxm_int = hs_phy->mxm_int; + mxm_int_en = hs_phy->mxm_int_en; + mxm_is = mxm_int & mxm_int_en; + hs_phy->mxm_int = mxm_is; + + if (mxm_is & MXC_F_USBHS_MXM_INT_NOVBUS) { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } +} + +static inline void musb_dcd_phy_init(uint8_t rhport) { + (void) rhport; + mxc_usbhs_regs_t* hs_phy = MXC_USBHS; + + // Interrupt for VBUS disconnect + hs_phy->mxm_int_en |= MXC_F_USBHS_MXM_INT_EN_NOVBUS; + + musb_dcd_int_clear(rhport); + + // Unsuspend the MAC + hs_phy->mxm_suspend = 0; + + // Configure PHY + hs_phy->m31_phy_xcfgi_31_0 = (0x1 << 3) | (0x1 << 11); + hs_phy->m31_phy_xcfgi_63_32 = 0; + hs_phy->m31_phy_xcfgi_95_64 = 0x1 << (72 - 64); + hs_phy->m31_phy_xcfgi_127_96 = 0; + + #ifdef USBHS_M31_CLOCK_RECOVERY + hs_phy->m31_phy_noncry_rstb = 1; + hs_phy->m31_phy_noncry_en = 1; + hs_phy->m31_phy_outclksel = 0; + hs_phy->m31_phy_coreclkin = 0; + hs_phy->m31_phy_xtlsel = 2; /* Select 25 MHz clock */ + #else + hs_phy->m31_phy_noncry_rstb = 0; + hs_phy->m31_phy_noncry_en = 0; + hs_phy->m31_phy_outclksel = 1; + hs_phy->m31_phy_coreclkin = 1; + hs_phy->m31_phy_xtlsel = 3; /* Select 30 MHz clock */ + #endif + hs_phy->m31_phy_pll_en = 1; + hs_phy->m31_phy_oscouten = 1; + + /* Reset PHY */ + hs_phy->m31_phy_ponrst = 0; + hs_phy->m31_phy_ponrst = 1; +} + +// static inline void musb_dcd_setup_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in, unsigned mps) { +// (void) mps; +// +// //Most likely the caller has already grabbed the right register block. But +// //as a precaution save and restore the register bank anyways +// unsigned saved_index = musb_periph_inst[rhport]->index; +// +// musb_periph_inst[rhport]->index = epnum; +// +// //Disable double buffering +// if (dir_in) { +// musb_periph_inst[rhport]->incsru |= (MXC_F_USBHS_INCSRU_DPKTBUFDIS | MXC_F_USBHS_INCSRU_MODE); +// } else { +// musb_periph_inst[rhport]->outcsru |= (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS); +// } +// +// musb_periph_inst[rhport]->index = saved_index; +// } + +#endif // CFG_TUD_ENABLED + +#ifdef __cplusplus +} +#endif + +#endif // TUSB_MUSB_MAX32_H_ diff --git a/src/portable/mentor/musb/musb_ti.h b/src/portable/mentor/musb/musb_ti.h new file mode 100644 index 000000000..d17e836ee --- /dev/null +++ b/src/portable/mentor/musb/musb_ti.h @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MUSB_TI_H_ +#define TUSB_MUSB_TI_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#if CFG_TUSB_MCU == OPT_MCU_TM4C123 + #include "TM4C123.h" + #define FIFO0_WORD FIFO0 + #define FIFO1_WORD FIFO1 +//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129 +#elif CFG_TUSB_MCU == OPT_MCU_MSP432E4 + #include "msp.h" +#else + #error "Unsupported MCUs" +#endif + +#define MUSB_CFG_SHARED_FIFO 0 +#define MUSB_CFG_DYNAMIC_FIFO 1 +#define MUSB_CFG_DYNAMIC_FIFO_SIZE 4096 + +const uintptr_t MUSB_BASES[] = { USB0_BASE }; + +// Header supports both device and host modes. Only include what's necessary +#if CFG_TUD_ENABLED + +// Mapping of IRQ numbers to port. Currently just 1. +static const IRQn_Type musb_irqs[] = { + USB0_IRQn +}; + +static inline void musb_dcd_phy_init(uint8_t rhport){ + (void)rhport; + //Nothing to do for this part +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) { + return NVIC_GetEnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) { + NVIC_ClearPendingIRQ(musb_irqs[rhport]); +} + +static inline void musb_dcd_int_handler_enter(uint8_t rhport) { + (void)rhport; + //Nothing to do for this part +} + +#endif // CFG_TUD_ENABLED + +#ifdef __cplusplus + } +#endif + +#endif // TUSB_MUSB_TI_H_ diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h index 8f83305a5..4e448c0ed 100644 --- a/src/portable/mentor/musb/musb_type.h +++ b/src/portable/mentor/musb/musb_type.h @@ -1,3 +1,29 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ @@ -32,2590 +58,696 @@ * *******************************************************************************/ -#ifndef _TUSB_MUSB_TYPE_H_ -#define _TUSB_MUSB_TYPE_H_ +#ifndef TUSB_MUSB_TYPE_H_ +#define TUSB_MUSB_TYPE_H_ + +#include "stdint.h" #ifdef __cplusplus extern "C" { #endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FADDR register. -// -//***************************************************************************** -#define USB_FADDR_M 0x0000007F // Function Address -#define USB_FADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_POWER register. -// -//***************************************************************************** -#define USB_POWER_ISOUP 0x00000080 // Isochronous Update -#define USB_POWER_SOFTCONN 0x00000040 // Soft Connect/Disconnect -#define USB_POWER_HSENAB 0x00000020 // High Speed Enable -#define USB_POWER_HSMODE 0x00000010 // High Speed Enable -#define USB_POWER_RESET 0x00000008 // RESET Signaling -#define USB_POWER_RESUME 0x00000004 // RESUME Signaling -#define USB_POWER_SUSPEND 0x00000002 // SUSPEND Mode -#define USB_POWER_PWRDNPHY 0x00000001 // Power Down PHY - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXIS register. -// -//***************************************************************************** -#define USB_TXIS_EP7 0x00000080 // TX Endpoint 7 Interrupt -#define USB_TXIS_EP6 0x00000040 // TX Endpoint 6 Interrupt -#define USB_TXIS_EP5 0x00000020 // TX Endpoint 5 Interrupt -#define USB_TXIS_EP4 0x00000010 // TX Endpoint 4 Interrupt -#define USB_TXIS_EP3 0x00000008 // TX Endpoint 3 Interrupt -#define USB_TXIS_EP2 0x00000004 // TX Endpoint 2 Interrupt -#define USB_TXIS_EP1 0x00000002 // TX Endpoint 1 Interrupt -#define USB_TXIS_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXIS register. -// -//***************************************************************************** -#define USB_RXIS_EP7 0x00000080 // RX Endpoint 7 Interrupt -#define USB_RXIS_EP6 0x00000040 // RX Endpoint 6 Interrupt -#define USB_RXIS_EP5 0x00000020 // RX Endpoint 5 Interrupt -#define USB_RXIS_EP4 0x00000010 // RX Endpoint 4 Interrupt -#define USB_RXIS_EP3 0x00000008 // RX Endpoint 3 Interrupt -#define USB_RXIS_EP2 0x00000004 // RX Endpoint 2 Interrupt -#define USB_RXIS_EP1 0x00000002 // RX Endpoint 1 Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXIE register. -// -//***************************************************************************** -#define USB_TXIE_EP7 0x00000080 // TX Endpoint 7 Interrupt Enable -#define USB_TXIE_EP6 0x00000040 // TX Endpoint 6 Interrupt Enable -#define USB_TXIE_EP5 0x00000020 // TX Endpoint 5 Interrupt Enable -#define USB_TXIE_EP4 0x00000010 // TX Endpoint 4 Interrupt Enable -#define USB_TXIE_EP3 0x00000008 // TX Endpoint 3 Interrupt Enable -#define USB_TXIE_EP2 0x00000004 // TX Endpoint 2 Interrupt Enable -#define USB_TXIE_EP1 0x00000002 // TX Endpoint 1 Interrupt Enable -#define USB_TXIE_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt - // Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXIE register. -// -//***************************************************************************** -#define USB_RXIE_EP7 0x00000080 // RX Endpoint 7 Interrupt Enable -#define USB_RXIE_EP6 0x00000040 // RX Endpoint 6 Interrupt Enable -#define USB_RXIE_EP5 0x00000020 // RX Endpoint 5 Interrupt Enable -#define USB_RXIE_EP4 0x00000010 // RX Endpoint 4 Interrupt Enable -#define USB_RXIE_EP3 0x00000008 // RX Endpoint 3 Interrupt Enable -#define USB_RXIE_EP2 0x00000004 // RX Endpoint 2 Interrupt Enable -#define USB_RXIE_EP1 0x00000002 // RX Endpoint 1 Interrupt Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_IS register. -// -//***************************************************************************** -#define USB_IS_VBUSERR 0x00000080 // VBUS Error (OTG only) -#define USB_IS_SESREQ 0x00000040 // SESSION REQUEST (OTG only) -#define USB_IS_DISCON 0x00000020 // Session Disconnect (OTG only) -#define USB_IS_CONN 0x00000010 // Session Connect -#define USB_IS_SOF 0x00000008 // Start of Frame -#define USB_IS_BABBLE 0x00000004 // Babble Detected -#define USB_IS_RESET 0x00000004 // RESET Signaling Detected -#define USB_IS_RESUME 0x00000002 // RESUME Signaling Detected -#define USB_IS_SUSPEND 0x00000001 // SUSPEND Signaling Detected - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_IE register. -// -//***************************************************************************** -#define USB_IE_VBUSERR 0x00000080 // Enable VBUS Error Interrupt (OTG - // only) -#define USB_IE_SESREQ 0x00000040 // Enable Session Request (OTG - // only) -#define USB_IE_DISCON 0x00000020 // Enable Disconnect Interrupt -#define USB_IE_CONN 0x00000010 // Enable Connect Interrupt -#define USB_IE_SOF 0x00000008 // Enable Start-of-Frame Interrupt -#define USB_IE_BABBLE 0x00000004 // Enable Babble Interrupt -#define USB_IE_RESET 0x00000004 // Enable RESET Interrupt -#define USB_IE_RESUME 0x00000002 // Enable RESUME Interrupt -#define USB_IE_SUSPND 0x00000001 // Enable SUSPEND Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FRAME register. -// -//***************************************************************************** -#define USB_FRAME_M 0x000007FF // Frame Number -#define USB_FRAME_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPIDX register. -// -//***************************************************************************** -#define USB_EPIDX_EPIDX_M 0x0000000F // Endpoint Index -#define USB_EPIDX_EPIDX_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TEST register. -// -//***************************************************************************** -#define USB_TEST_FORCEH 0x00000080 // Force Host Mode -#define USB_TEST_FIFOACC 0x00000040 // FIFO Access -#define USB_TEST_FORCEFS 0x00000020 // Force Full-Speed Mode -#define USB_TEST_FORCEHS 0x00000010 // Force High-Speed Mode -#define USB_TEST_TESTPKT 0x00000008 // Test Packet Mode Enable -#define USB_TEST_TESTK 0x00000004 // Test_K Mode Enable -#define USB_TEST_TESTJ 0x00000002 // Test_J Mode Enable -#define USB_TEST_TESTSE0NAK 0x00000001 // Test_SE0_NAK Test Mode Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO0 register. -// -//***************************************************************************** -#define USB_FIFO0_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO0_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO1 register. -// -//***************************************************************************** -#define USB_FIFO1_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO1_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO2 register. -// -//***************************************************************************** -#define USB_FIFO2_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO2_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO3 register. -// -//***************************************************************************** -#define USB_FIFO3_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO3_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO4 register. -// -//***************************************************************************** -#define USB_FIFO4_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO4_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO5 register. -// -//***************************************************************************** -#define USB_FIFO5_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO5_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO6 register. -// -//***************************************************************************** -#define USB_FIFO6_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO6_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO7 register. -// -//***************************************************************************** -#define USB_FIFO7_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO7_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DEVCTL register. -// -//***************************************************************************** -#define USB_DEVCTL_DEV 0x00000080 // Device Mode (OTG only) -#define USB_DEVCTL_FSDEV 0x00000040 // Full-Speed Device Detected -#define USB_DEVCTL_LSDEV 0x00000020 // Low-Speed Device Detected -#define USB_DEVCTL_VBUS_M 0x00000018 // VBUS Level (OTG only) -#define USB_DEVCTL_VBUS_NONE 0x00000000 // Below SessionEnd -#define USB_DEVCTL_VBUS_SEND 0x00000008 // Above SessionEnd, below AValid -#define USB_DEVCTL_VBUS_AVALID 0x00000010 // Above AValid, below VBUSValid -#define USB_DEVCTL_VBUS_VALID 0x00000018 // Above VBUSValid -#define USB_DEVCTL_HOST 0x00000004 // Host Mode -#define USB_DEVCTL_HOSTREQ 0x00000002 // Host Request (OTG only) -#define USB_DEVCTL_SESSION 0x00000001 // Session Start/End (OTG only) - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CCONF register. -// -//***************************************************************************** -#define USB_CCONF_TXEDMA 0x00000002 // TX Early DMA Enable -#define USB_CCONF_RXEDMA 0x00000001 // TX Early DMA Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFIFOSZ register. -// -//***************************************************************************** -#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support -#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size -#define USB_TXFIFOSZ_SIZE_8 0x00000000 // 8 -#define USB_TXFIFOSZ_SIZE_16 0x00000001 // 16 -#define USB_TXFIFOSZ_SIZE_32 0x00000002 // 32 -#define USB_TXFIFOSZ_SIZE_64 0x00000003 // 64 -#define USB_TXFIFOSZ_SIZE_128 0x00000004 // 128 -#define USB_TXFIFOSZ_SIZE_256 0x00000005 // 256 -#define USB_TXFIFOSZ_SIZE_512 0x00000006 // 512 -#define USB_TXFIFOSZ_SIZE_1024 0x00000007 // 1024 -#define USB_TXFIFOSZ_SIZE_2048 0x00000008 // 2048 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFIFOSZ register. -// -//***************************************************************************** -#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support -#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size -#define USB_RXFIFOSZ_SIZE_8 0x00000000 // 8 -#define USB_RXFIFOSZ_SIZE_16 0x00000001 // 16 -#define USB_RXFIFOSZ_SIZE_32 0x00000002 // 32 -#define USB_RXFIFOSZ_SIZE_64 0x00000003 // 64 -#define USB_RXFIFOSZ_SIZE_128 0x00000004 // 128 -#define USB_RXFIFOSZ_SIZE_256 0x00000005 // 256 -#define USB_RXFIFOSZ_SIZE_512 0x00000006 // 512 -#define USB_RXFIFOSZ_SIZE_1024 0x00000007 // 1024 -#define USB_RXFIFOSZ_SIZE_2048 0x00000008 // 2048 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFIFOADD -// register. -// -//***************************************************************************** -#define USB_TXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address -#define USB_TXFIFOADD_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFIFOADD -// register. -// -//***************************************************************************** -#define USB_RXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address -#define USB_RXFIFOADD_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIVBUSCTL -// register. -// -//***************************************************************************** -#define USB_ULPIVBUSCTL_USEEXTVBUSIND \ - 0x00000002 // Use External VBUS Indicator -#define USB_ULPIVBUSCTL_USEEXTVBUS \ - 0x00000001 // Use External VBUS - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGDATA -// register. -// -//***************************************************************************** -#define USB_ULPIREGDATA_REGDATA_M \ - 0x000000FF // Register Data -#define USB_ULPIREGDATA_REGDATA_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGADDR -// register. -// -//***************************************************************************** -#define USB_ULPIREGADDR_ADDR_M 0x000000FF // Register Address -#define USB_ULPIREGADDR_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGCTL -// register. -// -//***************************************************************************** -#define USB_ULPIREGCTL_RDWR 0x00000004 // Read/Write Control -#define USB_ULPIREGCTL_REGCMPLT 0x00000002 // Register Access Complete -#define USB_ULPIREGCTL_REGACC 0x00000001 // Initiate Register Access - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPINFO register. -// -//***************************************************************************** -#define USB_EPINFO_RXEP_M 0x000000F0 // RX Endpoints -#define USB_EPINFO_TXEP_M 0x0000000F // TX Endpoints -#define USB_EPINFO_RXEP_S 4 -#define USB_EPINFO_TXEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RAMINFO register. -// -//***************************************************************************** -#define USB_RAMINFO_DMACHAN_M 0x000000F0 // DMA Channels -#define USB_RAMINFO_RAMBITS_M 0x0000000F // RAM Address Bus Width -#define USB_RAMINFO_DMACHAN_S 4 -#define USB_RAMINFO_RAMBITS_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CONTIM register. -// -//***************************************************************************** -#define USB_CONTIM_WTCON_M 0x000000F0 // Connect Wait -#define USB_CONTIM_WTID_M 0x0000000F // Wait ID -#define USB_CONTIM_WTCON_S 4 -#define USB_CONTIM_WTID_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VPLEN register. -// -//***************************************************************************** -#define USB_VPLEN_VPLEN_M 0x000000FF // VBUS Pulse Length -#define USB_VPLEN_VPLEN_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_HSEOF register. -// -//***************************************************************************** -#define USB_HSEOF_HSEOFG_M 0x000000FF // HIgh-Speed End-of-Frame Gap -#define USB_HSEOF_HSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FSEOF register. -// -//***************************************************************************** -#define USB_FSEOF_FSEOFG_M 0x000000FF // Full-Speed End-of-Frame Gap -#define USB_FSEOF_FSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LSEOF register. -// -//***************************************************************************** -#define USB_LSEOF_LSEOFG_M 0x000000FF // Low-Speed End-of-Frame Gap -#define USB_LSEOF_LSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR0 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR0_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR0_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR0 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR0_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR0_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT0 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT0_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT0_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR1 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR1_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR1 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR1_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT1 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT1_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT1_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR1 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR1_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR1 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR1_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT1 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT1_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT1_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR2 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR2_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR2 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR2_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT2 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT2_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT2_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR2 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR2_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR2 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR2_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT2 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT2_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT2_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR3 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR3_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR3 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR3_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT3 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT3_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT3_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR3 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR3_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR3 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR3_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT3 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT3_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT3_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR4 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR4_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR4 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR4_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT4 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT4_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT4_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR4 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR4_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR4 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR4_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT4 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT4_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT4_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR5 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR5_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR5 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR5_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT5 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT5_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT5_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR5 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR5_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR5 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR5_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT5 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT5_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT5_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR6 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR6_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR6 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR6_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT6 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT6_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT6_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR6 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR6_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR6 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR6_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT6 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT6_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT6_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR7 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR7_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR7 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR7_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT7 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT7_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT7_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR7 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR7_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR7 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR7_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT7 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT7_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT7_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CSRL0 register. -// -//***************************************************************************** -#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout -#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear -#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet -#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear -#define USB_CSRL0_REQPKT 0x00000020 // Request Packet -#define USB_CSRL0_STALL 0x00000020 // Send Stall -#define USB_CSRL0_SETEND 0x00000010 // Setup End -#define USB_CSRL0_ERROR 0x00000010 // Error -#define USB_CSRL0_DATAEND 0x00000008 // Data End -#define USB_CSRL0_SETUP 0x00000008 // Setup Packet -#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled -#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready -#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CSRH0 register. -// -//***************************************************************************** -#define USB_CSRH0_DISPING 0x00000008 // PING Disable -#define USB_CSRH0_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_CSRH0_DT 0x00000002 // Data Toggle -#define USB_CSRH0_FLUSH 0x00000001 // Flush FIFO - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_COUNT0 register. -// -//***************************************************************************** -#define USB_COUNT0_COUNT_M 0x0000007F // FIFO Count -#define USB_COUNT0_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TYPE0 register. -// -//***************************************************************************** -#define USB_TYPE0_SPEED_M 0x000000C0 // Operating Speed -#define USB_TYPE0_SPEED_HIGH 0x00000040 // High -#define USB_TYPE0_SPEED_FULL 0x00000080 // Full -#define USB_TYPE0_SPEED_LOW 0x000000C0 // Low - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_NAKLMT register. -// -//***************************************************************************** -#define USB_NAKLMT_NAKLMT_M 0x0000001F // EP0 NAK Limit -#define USB_NAKLMT_NAKLMT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP1 register. -// -//***************************************************************************** -#define USB_TXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP1_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL1 register. -// -//***************************************************************************** -#define USB_TXCSRL1_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL1_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL1_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL1_STALL 0x00000010 // Send STALL -#define USB_TXCSRL1_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL1_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL1_ERROR 0x00000004 // Error -#define USB_TXCSRL1_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL1_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL1_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH1 register. -// -//***************************************************************************** -#define USB_TXCSRH1_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH1_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH1_MODE 0x00000020 // Mode -#define USB_TXCSRH1_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH1_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH1_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH1_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH1_DT 0x00000001 // Data Toggle - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP1 register. -// -//***************************************************************************** -#define USB_RXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP1_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL1 register. -// -//***************************************************************************** -#define USB_RXCSRL1_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL1_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL1_STALL 0x00000020 // Send STALL -#define USB_RXCSRL1_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL1_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL1_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL1_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL1_OVER 0x00000004 // Overrun -#define USB_RXCSRL1_ERROR 0x00000004 // Error -#define USB_RXCSRL1_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL1_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH1 register. -// -//***************************************************************************** -#define USB_RXCSRH1_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH1_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH1_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH1_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH1_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH1_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH1_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH1_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH1_DT 0x00000002 // Data Toggle -#define USB_RXCSRH1_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT1 register. -// -//***************************************************************************** -#define USB_RXCOUNT1_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT1_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE1 register. -// -//***************************************************************************** -#define USB_TXTYPE1_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE1_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE1_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE1_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE1_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE1_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE1_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE1_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE1_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE1_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE1_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE1_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL1 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL1_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL1_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL1_TXPOLL_S \ - 0 -#define USB_TXINTERVAL1_NAKLMT_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE1 register. -// -//***************************************************************************** -#define USB_RXTYPE1_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE1_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE1_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE1_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE1_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE1_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE1_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE1_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE1_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE1_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE1_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE1_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL1 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL1_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL1_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL1_TXPOLL_S \ - 0 -#define USB_RXINTERVAL1_NAKLMT_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP2 register. -// -//***************************************************************************** -#define USB_TXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP2_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL2 register. -// -//***************************************************************************** -#define USB_TXCSRL2_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL2_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL2_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL2_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL2_STALL 0x00000010 // Send STALL -#define USB_TXCSRL2_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL2_ERROR 0x00000004 // Error -#define USB_TXCSRL2_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL2_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL2_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH2 register. -// -//***************************************************************************** -#define USB_TXCSRH2_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH2_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH2_MODE 0x00000020 // Mode -#define USB_TXCSRH2_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH2_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH2_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH2_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH2_DT 0x00000001 // Data Toggle - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP2 register. -// -//***************************************************************************** -#define USB_RXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP2_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL2 register. -// -//***************************************************************************** -#define USB_RXCSRL2_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL2_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL2_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL2_STALL 0x00000020 // Send STALL -#define USB_RXCSRL2_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL2_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL2_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL2_ERROR 0x00000004 // Error -#define USB_RXCSRL2_OVER 0x00000004 // Overrun -#define USB_RXCSRL2_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL2_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH2 register. -// -//***************************************************************************** -#define USB_RXCSRH2_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH2_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH2_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH2_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH2_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH2_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH2_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH2_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH2_DT 0x00000002 // Data Toggle -#define USB_RXCSRH2_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT2 register. -// -//***************************************************************************** -#define USB_RXCOUNT2_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT2_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE2 register. -// -//***************************************************************************** -#define USB_TXTYPE2_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE2_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE2_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE2_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE2_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE2_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE2_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE2_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE2_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE2_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE2_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE2_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL2 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL2_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL2_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL2_NAKLMT_S \ - 0 -#define USB_TXINTERVAL2_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE2 register. -// -//***************************************************************************** -#define USB_RXTYPE2_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE2_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE2_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE2_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE2_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE2_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE2_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE2_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE2_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE2_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE2_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE2_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL2 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL2_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL2_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL2_TXPOLL_S \ - 0 -#define USB_RXINTERVAL2_NAKLMT_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP3 register. -// -//***************************************************************************** -#define USB_TXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP3_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL3 register. -// -//***************************************************************************** -#define USB_TXCSRL3_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL3_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL3_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL3_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL3_STALL 0x00000010 // Send STALL -#define USB_TXCSRL3_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL3_ERROR 0x00000004 // Error -#define USB_TXCSRL3_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL3_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL3_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH3 register. -// -//***************************************************************************** -#define USB_TXCSRH3_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH3_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH3_MODE 0x00000020 // Mode -#define USB_TXCSRH3_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH3_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH3_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH3_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH3_DT 0x00000001 // Data Toggle - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP3 register. -// -//***************************************************************************** -#define USB_RXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP3_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL3 register. -// -//***************************************************************************** -#define USB_RXCSRL3_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL3_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL3_STALL 0x00000020 // Send STALL -#define USB_RXCSRL3_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL3_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL3_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL3_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL3_ERROR 0x00000004 // Error -#define USB_RXCSRL3_OVER 0x00000004 // Overrun -#define USB_RXCSRL3_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL3_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH3 register. -// -//***************************************************************************** -#define USB_RXCSRH3_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH3_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH3_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH3_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH3_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH3_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH3_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH3_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH3_DT 0x00000002 // Data Toggle -#define USB_RXCSRH3_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT3 register. -// -//***************************************************************************** -#define USB_RXCOUNT3_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT3_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE3 register. -// -//***************************************************************************** -#define USB_TXTYPE3_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE3_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE3_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE3_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE3_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE3_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE3_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE3_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE3_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE3_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE3_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE3_TEP_S 0 +#ifndef __IO + #define __IO volatile +#endif + +#ifndef __I + #define __I volatile const +#endif + +#ifndef __O + #define __O volatile +#endif + +#ifndef __R + #define __R volatile const +#endif + +typedef struct TU_ATTR_PACKED { + __IO uint16_t maxp; // 0x00, 0x04: MAXP + __IO uint8_t csrl; // 0x02, 0x06: CSRL + __IO uint8_t csrh; // 0x03, 0x07: CSRH +}musb_ep_maxp_csr_t; + +// 0: TX (device IN, host OUT) +// 1: RX (device OUT, host IN) +typedef struct TU_ATTR_PACKED { + union { + struct { + __IO uint16_t tx_maxp; // 0x00: TXMAXP + union { + __IO uint8_t csr0l; // 0x02: CSR0 + __IO uint8_t tx_csrl; // 0x02: TX CSRL + }; + union { + __IO uint8_t csr0h; // 0x03: CSR0H + __IO uint8_t tx_csrh; // 0x03: TX CSRH + }; + + __IO uint16_t rx_maxp; // 0x04: RX MAXP + __IO uint8_t rx_csrl; // 0x06: RX CSRL + __IO uint8_t rx_csrh; // 0x07: RX CSRH + }; + + musb_ep_maxp_csr_t maxp_csr[2]; + }; + + union { + __IO uint16_t count0; // 0x08: COUNT0 + __IO uint16_t rx_count; // 0x08: RX COUNT + }; + union { + __IO uint8_t type0; // 0x0A: TYPE0 (host only) + __IO uint8_t tx_type; // 0x0A: TX TYPE + }; + __IO uint8_t tx_interval; // 0x0B: TX INTERVAL + __IO uint8_t rx_type; // 0x0C: RX TYPE + __IO uint8_t rx_interval; // 0x0D: RX INTERVAL + __IO uint8_t reserved_0x0e; // 0x0E: Reserved + union { + __IO uint8_t config_data0; // 0x0F: CONFIG DATA + struct { + __IO uint8_t utmi_data_width : 1; // [0] UTMI Data Width + __IO uint8_t softconn_en : 1; // [1] Soft Connect Enable + __IO uint8_t dynamic_fifo : 1; // [2] Dynamic FIFO Sizing + __IO uint8_t hb_tx_en : 1; // [3] High Bandwidth TX ISO Enable + __IO uint8_t hb_rx_en : 1; // [4] High Bandwidth RX ISO Enable + __IO uint8_t big_endian : 1; // [5] Big Endian + __IO uint8_t mp_tx_en : 1; // [6] Auto splitting BULK TX Enable + __IO uint8_t mp_rx_en : 1; // [7] Auto amalgamation BULK RX Enable + } config_data0_bit; + + __IO uint8_t fifo_size; // 0x0F: FIFO_SIZE + struct { + __IO uint8_t tx : 4; // [3:0] TX FIFO Size + __IO uint8_t rx : 4; // [7:4] RX FIFO Size + }fifo_size_bit; + }; +} musb_ep_csr_t; + +TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct"); + +typedef struct TU_ATTR_PACKED { + //------------- Common -------------// + __IO uint8_t faddr; // 0x00: FADDR + union { + __IO uint8_t power; // 0x01: POWER + struct { + __IO uint8_t suspend_mode_en : 1; // [0] SUSPEND Mode Enable + __IO uint8_t suspend_mode : 1; // [1] SUSPEND Mode + __IO uint8_t resume_mode : 1; // [2] RESUME + __IO uint8_t reset : 1; // [3] RESET + __IO uint8_t highspeed_mode : 1; // [4] High Speed Mode + __IO uint8_t highspeed_en : 1; // [5] High Speed Enable + __IO uint8_t soft_conn : 1; // [6] Soft Connect/Disconnect + __IO uint8_t iso_update : 1; // [7] Isochronous Update + } power_bit; + }; + + union { + struct { + __IO uint16_t intr_tx; // 0x02: INTR_TX + __IO uint16_t intr_rx; // 0x04: INTR_RX + }; + + __IO uint16_t intr_ep[2]; // 0x02-0x05: INTR_EP0-1 + }; + + union { + struct { + __IO uint16_t intr_txen; // 0x06: INTR_TXEN + __IO uint16_t intr_rxen; // 0x08: INTR_RXEN + }; + + __IO uint16_t intren_ep[2]; // 0x06-0x09: INTREN_EP0-1 + }; + + __IO uint8_t intr_usb; // 0x0A: INTRUSB + __IO uint8_t intr_usben; // 0x0B: INTRUSBEN + + __IO uint16_t frame; // 0x0C: FRAME + __IO uint8_t index; // 0x0E: INDEX + __IO uint8_t testmode; // 0x0F: TESTMODE + + //------------- Endpoint CSR (indexed) -------------// + musb_ep_csr_t indexed_csr; // 0x10-0x1F: Indexed CSR 0-15 + + //------------- FIFOs -------------// + __IO uint32_t fifo[16]; // 0x20-0x5C: FIFO 0-15 + + // Common (2) + __IO uint8_t devctl; // 0x60: DEVCTL + __IO uint8_t misc; // 0x61: MISC + + //------------- Dynammic FIFO (indexed) -------------// + union { + struct { + __IO uint8_t txfifo_sz; // 0x62: TXFIFO_SZ + __IO uint8_t rxfifo_sz; // 0x63: RXFIFO_SZ + }; + __IO uint8_t fifo_size[2]; + }; + + union { + struct { + __IO uint16_t txfifo_addr; // 0x64: TXFIFO_ADDR + __IO uint16_t rxfifo_addr; // 0x66: RXFIFO_ADDR + }; + __IO uint16_t fifo_addr[2]; + }; + + //------------- Additional Control and Configuration -------------// + union { + __O uint32_t vcontrol; // 0x68: PHY VCONTROL + __IO uint32_t vstatus; // 0x68: PHY VSTATUS + }; + union { + __IO uint16_t hwvers; // 0x6C: HWVERS + struct { + __IO uint16_t minor : 10; // [9:0] Minor + __IO uint16_t major : 5; // [14:10] Major + __IO uint16_t rc : 1; // [15] Release Candidate + } hwvers_bit; + }; + __R uint16_t rsv_0x6e_0x77[5]; // 0x6E-0x77: Reserved + + //------------- Additional Configuration -------------// + union { + __IO uint8_t epinfo; // 0x78: EPINFO + struct { + __IO uint8_t tx_ep_num : 4; // [3:0] TX Endpoints + __IO uint8_t rx_ep_num : 4; // [7:4] RX Endpoints + } epinfo_bit; + }; + union { + __IO uint8_t raminfo; // 0x79: RAMINFO + struct { + __IO uint8_t ram_bits : 4; // [3:0] RAM Address Bus Width + __IO uint8_t dma_channel : 4; // [7:4] DMA Channels + }raminfo_bit; + }; + union { + __IO uint8_t link_info; // 0x7A: LINK_INFO + __IO uint8_t adi_softreset; // 0x7A: AnalogDevice SOFTRESET + }; + __IO uint8_t vplen; // 0x7B: VPLEN + __IO uint8_t hs_eof1; // 0x7C: HS_EOF1 + __IO uint8_t fs_eof1; // 0x7D: FS_EOF1 + __IO uint8_t ls_eof1; // 0x7E: LS_EOF1 + __IO uint8_t soft_rst; // 0x7F: SOFT_RST + + //------------- Target Endpoints (multipoint option) -------------// + __IO uint16_t ctuch; // 0x80: CTUCH + __IO uint16_t cthsrtn; // 0x82: CTHSRTN + __R uint32_t rsv_0x84_0xff[31]; // 0x84-0xFF: Reserved + + //------------- Non-Indexed Endpoint CSRs -------------// + // TI tm4c can access this directly, but should use indexed_csr for portability + musb_ep_csr_t abs_csr[16]; // 0x100-0x1FF: EP0-15 CSR + + //------------- DMA -------------// + __IO uint8_t dma_intr; // 0x200: DMA_INTR + __R uint8_t rsv_0x201_0x203[3]; // 0x201-0x203: Reserved + struct { + __IO uint16_t cntl; // 0x204: DMA_CNTL + __IO uint16_t rsv_0x206; // 0x206: Reserved + __IO uint32_t addr; // 0x208: DMA_ADDR + __IO uint32_t count; // 0x20C: DMA_COUNT + __IO uint32_t rsv_0x210; // 0x210: Reserved + }dma[8]; + __R uint32_t rsv_0x284_0x2FF[31]; // 0x284-0x2FF: Reserved + + //------------- Extended -------------// + __R uint32_t rsv_0x300; // 0x300: Reserved + struct { + __IO uint16_t count; // 0x304: REQ_PACKET_COUNT + __R uint16_t rsv_0x306; // 0x306: Reserved + }req_packet[15]; + + __IO uint16_t rx_doulbe_packet_disable; // 0x340: RX_DOUBLE_PACKET_DISABLE + __IO uint16_t tx_double_packet_disable; // 0x342: TX_DOUBLE_PACKET_DISABLE + + __IO uint16_t chirp_timeout; // 0x344: CHIRP_TIMEOUT + __IO uint16_t hs_to_utm; // 0x346: HS_TO_UTM delay + __IO uint16_t hs_timeout_adder; // 0x348: HS_TIMEOUT_ADDER + + __R uint8_t rsv_34A_34f[6]; // 0x34A-0x34F: Reserved +} musb_regs_t; + +TU_VERIFY_STATIC(sizeof(musb_regs_t) == 0x350, "size is not correct"); + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline musb_ep_csr_t* get_ep_csr(musb_regs_t* musb_regs, unsigned epnum) { + musb_regs->index = epnum; + return &musb_regs->indexed_csr; +} + +//--------------------------------------------------------------------+ +// Register Bit Field +//--------------------------------------------------------------------+ + +// 0x01: Power +#define MUSB_POWER_ISOUP 0x0080 // Isochronous Update +#define MUSB_POWER_SOFTCONN 0x0040 // Soft Connect/Disconnect +#define MUSB_POWER_HSENAB 0x0020 // High Speed Enable +#define MUSB_POWER_HSMODE 0x0010 // High Speed Enable +#define MUSB_POWER_RESET 0x0008 // RESET Signaling +#define MUSB_POWER_RESUME 0x0004 // RESUME Signaling +#define MUSB_POWER_SUSPEND 0x0002 // SUSPEND Mode +#define MUSB_POWER_PWRDNPHY 0x0001 // Power Down PHY + +// Interrupt TX/RX Status and Enable: each bit is for an endpoint + +// 0x6c: HWVERS +#define MUSB_HWVERS_RC_SHIFT 15 +#define MUSB_HWVERS_RC_MASK 0x8000 +#define MUSB_HWVERS_MAJOR_SHIFT 10 +#define MUSB_HWVERS_MAJOR_MASK 0x7C00 +#define MUSB_HWVERS_MINOR_SHIFT 0 +#define MUSB_HWVERS_MINOR_MASK 0x03FF -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL3 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL3_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL3_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL3_TXPOLL_S \ - 0 -#define USB_TXINTERVAL3_NAKLMT_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE3 register. -// -//***************************************************************************** -#define USB_RXTYPE3_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE3_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE3_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE3_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE3_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE3_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE3_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE3_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE3_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE3_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE3_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE3_TEP_S 0 +// 0x12, 0x16: TX/RX CSRL +#define MUSB_CSRL_PACKET_READY(_rx) (1u << 0) +#define MUSB_CSRL_FLUSH_FIFO(_rx) (1u << ((_rx) ? 4 : 3)) +#define MUSB_CSRL_SEND_STALL(_rx) (1u << ((_rx) ? 5 : 4)) +#define MUSB_CSRL_STALLED(_rx) (1u << ((_rx) ? 6 : 5)) +#define MUSB_CSRL_CLEAR_DATA_TOGGLE(_rx) (1u << ((_rx) ? 7 : 6)) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL3 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL3_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL3_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL3_TXPOLL_S \ - 0 -#define USB_RXINTERVAL3_NAKLMT_S \ - 0 +// 0x13, 0x17: TX/RX CSRH +#define MUSB_CSRH_DISABLE_DOUBLE_PACKET(_rx) (1u << 1) +#define MUSB_CSRH_TX_MODE (1u << 5) // 1 = TX, 0 = RX. only relevant for SHARED FIFO +#define MUSB_CSRH_ISO (1u << 6) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP4 register. -// -//***************************************************************************** -#define USB_TXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP4_MAXLOAD_S 0 +// 0x62, 0x63: TXFIFO_SZ, RXFIFO_SZ +#define MUSB_FIFOSZ_DOUBLE_PACKET (1u << 4) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL4 register. -// -//***************************************************************************** -#define USB_TXCSRL4_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL4_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL4_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL4_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL4_STALL 0x00000010 // Send STALL -#define USB_TXCSRL4_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL4_ERROR 0x00000004 // Error -#define USB_TXCSRL4_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL4_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL4_TXRDY 0x00000001 // Transmit Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRH4 register. +// The following are defines for the bit fields in the MUSB_O_IS register. // //***************************************************************************** -#define USB_TXCSRH4_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH4_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH4_MODE 0x00000020 // Mode -#define USB_TXCSRH4_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH4_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH4_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH4_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH4_DT 0x00000001 // Data Toggle +#define MUSB_IS_VBUSERR 0x0080 // VBUS Error (OTG only) +#define MUSB_IS_SESREQ 0x0040 // SESSION REQUEST (OTG only) +#define MUSB_IS_DISCON 0x0020 // Session Disconnect (OTG only) +#define MUSB_IS_CONN 0x0010 // Session Connect +#define MUSB_IS_SOF 0x0008 // Start of Frame +#define MUSB_IS_BABBLE 0x0004 // Babble Detected +#define MUSB_IS_RESET 0x0004 // RESET Signaling Detected +#define MUSB_IS_RESUME 0x0002 // RESUME Signaling Detected +#define MUSB_IS_SUSPEND 0x0001 // SUSPEND Signaling Detected //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXMAXP4 register. +// The following are defines for the bit fields in the MUSB_O_IE register. // //***************************************************************************** -#define USB_RXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP4_MAXLOAD_S 0 +#define MUSB_IE_VBUSERR 0x0080 // Enable VBUS Error Interrupt (OTG only) +#define MUSB_IE_SESREQ 0x0040 // Enable Session Request (OTG only) +#define MUSB_IE_DISCON 0x0020 // Enable Disconnect Interrupt +#define MUSB_IE_CONN 0x0010 // Enable Connect Interrupt +#define MUSB_IE_SOF 0x0008 // Enable Start-of-Frame Interrupt +#define MUSB_IE_BABBLE 0x0004 // Enable Babble Interrupt +#define MUSB_IE_RESET 0x0004 // Enable RESET Interrupt +#define MUSB_IE_RESUME 0x0002 // Enable RESUME Interrupt +#define MUSB_IE_SUSPND 0x0001 // Enable SUSPEND Interrupt //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRL4 register. +// The following are defines for the bit fields in the MUSB_O_FRAME register. // //***************************************************************************** -#define USB_RXCSRL4_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL4_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL4_STALL 0x00000020 // Send STALL -#define USB_RXCSRL4_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL4_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL4_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL4_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL4_OVER 0x00000004 // Overrun -#define USB_RXCSRL4_ERROR 0x00000004 // Error -#define USB_RXCSRL4_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL4_RXRDY 0x00000001 // Receive Packet Ready +#define MUSB_FRAME_M 0x07FF // Frame Number +#define MUSB_FRAME_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRH4 register. +// The following are defines for the bit fields in the MUSB_O_TEST register. // //***************************************************************************** -#define USB_RXCSRH4_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH4_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH4_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH4_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH4_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH4_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH4_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH4_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH4_DT 0x00000002 // Data Toggle -#define USB_RXCSRH4_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +#define MUSB_TEST_FORCEH 0x0080 // Force Host Mode +#define MUSB_TEST_FIFOACC 0x0040 // FIFO Access +#define MUSB_TEST_FORCEFS 0x0020 // Force Full-Speed Mode +#define MUSB_TEST_FORCEHS 0x0010 // Force High-Speed Mode +#define MUSB_TEST_TESTPKT 0x0008 // Test Packet Mode Enable +#define MUSB_TEST_TESTK 0x0004 // Test_K Mode Enable +#define MUSB_TEST_TESTJ 0x0002 // Test_J Mode Enable +#define MUSB_TEST_TESTSE0NAK 0x0001 // Test_SE0_NAK Test Mode Enable //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCOUNT4 register. +// The following are defines for the bit fields in the MUSB_O_DEVCTL register. // //***************************************************************************** -#define USB_RXCOUNT4_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT4_COUNT_S 0 +#define MUSB_DEVCTL_DEV 0x0080 // Device Mode (OTG only) +#define MUSB_DEVCTL_FSDEV 0x0040 // Full-Speed Device Detected +#define MUSB_DEVCTL_LSDEV 0x0020 // Low-Speed Device Detected +#define MUSB_DEVCTL_VBUS_M 0x0018 // VBUS Level (OTG only) +#define MUSB_DEVCTL_VBUS_NONE 0x0000 // Below SessionEnd +#define MUSB_DEVCTL_VBUS_SEND 0x0008 // Above SessionEnd, below AValid +#define MUSB_DEVCTL_VBUS_AVALID 0x0010 // Above AValid, below VBUSValid +#define MUSB_DEVCTL_VBUS_VALID 0x0018 // Above VBUSValid +#define MUSB_DEVCTL_HOST 0x0004 // Host Mode +#define MUSB_DEVCTL_HOSTREQ 0x0002 // Host Request (OTG only) +#define MUSB_DEVCTL_SESSION 0x0001 // Session Start/End (OTG only) //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXTYPE4 register. +// The following are defines for the bit fields in the MUSB_O_CCONF register. // //***************************************************************************** -#define USB_TXTYPE4_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE4_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE4_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE4_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE4_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE4_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE4_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE4_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE4_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE4_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE4_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE4_TEP_S 0 +#define MUSB_CCONF_TXEDMA 0x0002 // TX Early DMA Enable +#define MUSB_CCONF_RXEDMA 0x0001 // TX Early DMA Enable //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL4 +// The following are defines for the bit fields in the MUSB_O_ULPIVBUSCTL // register. // //***************************************************************************** -#define USB_TXINTERVAL4_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL4_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL4_NAKLMT_S \ - 0 -#define USB_TXINTERVAL4_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE4 register. -// -//***************************************************************************** -#define USB_RXTYPE4_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE4_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE4_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE4_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE4_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE4_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE4_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE4_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE4_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE4_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE4_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE4_TEP_S 0 +#define MUSB_ULPIVBUSCTL_USEEXTVBUSIND 0x0002 // Use External VBUS Indicator +#define MUSB_ULPIVBUSCTL_USEEXTVBUS 0x0001 // Use External VBUS //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL4 +// The following are defines for the bit fields in the MUSB_O_ULPIREGDATA // register. // //***************************************************************************** -#define USB_RXINTERVAL4_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL4_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL4_NAKLMT_S \ - 0 -#define USB_RXINTERVAL4_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP5 register. -// -//***************************************************************************** -#define USB_TXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP5_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL5 register. -// -//***************************************************************************** -#define USB_TXCSRL5_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL5_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL5_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL5_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL5_STALL 0x00000010 // Send STALL -#define USB_TXCSRL5_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL5_ERROR 0x00000004 // Error -#define USB_TXCSRL5_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL5_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL5_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH5 register. -// -//***************************************************************************** -#define USB_TXCSRH5_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH5_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH5_MODE 0x00000020 // Mode -#define USB_TXCSRH5_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH5_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH5_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH5_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH5_DT 0x00000001 // Data Toggle - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP5 register. -// -//***************************************************************************** -#define USB_RXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP5_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL5 register. -// -//***************************************************************************** -#define USB_RXCSRL5_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL5_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL5_STALL 0x00000020 // Send STALL -#define USB_RXCSRL5_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL5_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL5_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL5_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL5_ERROR 0x00000004 // Error -#define USB_RXCSRL5_OVER 0x00000004 // Overrun -#define USB_RXCSRL5_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL5_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH5 register. -// -//***************************************************************************** -#define USB_RXCSRH5_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH5_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH5_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH5_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH5_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH5_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH5_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH5_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH5_DT 0x00000002 // Data Toggle -#define USB_RXCSRH5_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT5 register. -// -//***************************************************************************** -#define USB_RXCOUNT5_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT5_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE5 register. -// -//***************************************************************************** -#define USB_TXTYPE5_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE5_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE5_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE5_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE5_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE5_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE5_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE5_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE5_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE5_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE5_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE5_TEP_S 0 - +#define MUSB_ULPIREGDATA_REGDATA_M 0x00FF // Register Data +#define MUSB_ULPIREGDATA_REGDATA_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL5 +// The following are defines for the bit fields in the MUSB_O_ULPIREGADDR // register. // //***************************************************************************** -#define USB_TXINTERVAL5_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL5_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL5_NAKLMT_S \ - 0 -#define USB_TXINTERVAL5_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE5 register. -// -//***************************************************************************** -#define USB_RXTYPE5_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE5_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE5_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE5_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE5_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE5_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE5_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE5_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE5_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE5_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE5_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE5_TEP_S 0 +#define MUSB_ULPIREGADDR_ADDR_M 0x00FF // Register Address +#define MUSB_ULPIREGADDR_ADDR_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL5 +// The following are defines for the bit fields in the MUSB_O_ULPIREGCTL // register. // //***************************************************************************** -#define USB_RXINTERVAL5_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL5_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL5_TXPOLL_S \ - 0 -#define USB_RXINTERVAL5_NAKLMT_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP6 register. -// -//***************************************************************************** -#define USB_TXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP6_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL6 register. -// -//***************************************************************************** -#define USB_TXCSRL6_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL6_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL6_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL6_STALL 0x00000010 // Send STALL -#define USB_TXCSRL6_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL6_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL6_ERROR 0x00000004 // Error -#define USB_TXCSRL6_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL6_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL6_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH6 register. -// -//***************************************************************************** -#define USB_TXCSRH6_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH6_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH6_MODE 0x00000020 // Mode -#define USB_TXCSRH6_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH6_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH6_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH6_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH6_DT 0x00000001 // Data Toggle +#define MUSB_ULPIREGCTL_RDWR 0x0004 // Read/Write Control +#define MUSB_ULPIREGCTL_REGCMPLT 0x0002 // Register Access Complete +#define MUSB_ULPIREGCTL_REGACC 0x0001 // Initiate Register Access //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXMAXP6 register. +// The following are defines for the bit fields in the MUSB_O_EPINFO register. // //***************************************************************************** -#define USB_RXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP6_MAXLOAD_S 0 +#define MUSB_EPINFO_RXEP_M 0x00F0 // RX Endpoints +#define MUSB_EPINFO_TXEP_M 0x000F // TX Endpoints +#define MUSB_EPINFO_RXEP_S 4 +#define MUSB_EPINFO_TXEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRL6 register. +// The following are defines for the bit fields in the MUSB_O_RAMINFO register. // //***************************************************************************** -#define USB_RXCSRL6_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL6_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL6_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL6_STALL 0x00000020 // Send STALL -#define USB_RXCSRL6_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL6_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL6_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL6_ERROR 0x00000004 // Error -#define USB_RXCSRL6_OVER 0x00000004 // Overrun -#define USB_RXCSRL6_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL6_RXRDY 0x00000001 // Receive Packet Ready +#define MUSB_RAMINFO_DMACHAN_M 0x00F0 // DMA Channels +#define MUSB_RAMINFO_RAMBITS_M 0x000F // RAM Address Bus Width +#define MUSB_RAMINFO_DMACHAN_S 4 +#define MUSB_RAMINFO_RAMBITS_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRH6 register. +// The following are defines for the bit fields in the MUSB_O_CONTIM register. // //***************************************************************************** -#define USB_RXCSRH6_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH6_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH6_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH6_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH6_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH6_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH6_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH6_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH6_DT 0x00000002 // Data Toggle -#define USB_RXCSRH6_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +#define MUSB_CONTIM_WTCON_M 0x00F0 // Connect Wait +#define MUSB_CONTIM_WTID_M 0x000F // Wait ID +#define MUSB_CONTIM_WTCON_S 4 +#define MUSB_CONTIM_WTID_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCOUNT6 register. +// The following are defines for the bit fields in the MUSB_O_VPLEN register. // //***************************************************************************** -#define USB_RXCOUNT6_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT6_COUNT_S 0 +#define MUSB_VPLEN_VPLEN_M 0x00FF // VBUS Pulse Length +#define MUSB_VPLEN_VPLEN_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXTYPE6 register. +// The following are defines for the bit fields in the MUSB_O_HSEOF register. // //***************************************************************************** -#define USB_TXTYPE6_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE6_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE6_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE6_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE6_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE6_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE6_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE6_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE6_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE6_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE6_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE6_TEP_S 0 +#define MUSB_HSEOF_HSEOFG_M 0x00FF // HIgh-Speed End-of-Frame Gap +#define MUSB_HSEOF_HSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL6 -// register. +// The following are defines for the bit fields in the MUSB_O_FSEOF register. // //***************************************************************************** -#define USB_TXINTERVAL6_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL6_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL6_TXPOLL_S \ - 0 -#define USB_TXINTERVAL6_NAKLMT_S \ - 0 +#define MUSB_FSEOF_FSEOFG_M 0x00FF // Full-Speed End-of-Frame Gap +#define MUSB_FSEOF_FSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXTYPE6 register. +// The following are defines for the bit fields in the MUSB_O_LSEOF register. // //***************************************************************************** -#define USB_RXTYPE6_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE6_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE6_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE6_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE6_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE6_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE6_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE6_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE6_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE6_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE6_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE6_TEP_S 0 +#define MUSB_LSEOF_LSEOFG_M 0x00FF // Low-Speed End-of-Frame Gap +#define MUSB_LSEOF_LSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL6 -// register. +// The following are defines for the bit fields in the MUSB_O_CSRL0 register. // //***************************************************************************** -#define USB_RXINTERVAL6_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL6_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL6_NAKLMT_S \ - 0 -#define USB_RXINTERVAL6_TXPOLL_S \ - 0 +#define MUSB_CSRL0_NAKTO 0x0080 // NAK Timeout +#define MUSB_CSRL0_SETENDC 0x0080 // Setup End Clear +#define MUSB_CSRL0_STATUS 0x0040 // STATUS Packet +#define MUSB_CSRL0_RXRDYC 0x0040 // RXRDY Clear +#define MUSB_CSRL0_REQPKT 0x0020 // Request Packet +#define MUSB_CSRL0_STALL 0x0020 // Send Stall +#define MUSB_CSRL0_SETEND 0x0010 // Setup End +#define MUSB_CSRL0_ERROR 0x0010 // Error +#define MUSB_CSRL0_DATAEND 0x0008 // Data End +#define MUSB_CSRL0_SETUP 0x0008 // Setup Packet +#define MUSB_CSRL0_STALLED 0x0004 // Endpoint Stalled +#define MUSB_CSRL0_TXRDY 0x0002 // Transmit Packet Ready +#define MUSB_CSRL0_RXRDY 0x0001 // Receive Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXMAXP7 register. +// The following are defines for the bit fields in the MUSB_O_CSRH0 register. // //***************************************************************************** -#define USB_TXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP7_MAXLOAD_S 0 +#define MUSB_CSRH0_DISPING 0x0008 // PING Disable +#define MUSB_CSRH0_DTWE 0x0004 // Data Toggle Write Enable +#define MUSB_CSRH0_DT 0x0002 // Data Toggle +#define MUSB_CSRH0_FLUSH 0x0001 // Flush FIFO //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRL7 register. +// The following are defines for the bit fields in the MUSB_O_TYPE0 register. // //***************************************************************************** -#define USB_TXCSRL7_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL7_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL7_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL7_STALL 0x00000010 // Send STALL -#define USB_TXCSRL7_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL7_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL7_ERROR 0x00000004 // Error -#define USB_TXCSRL7_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL7_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL7_TXRDY 0x00000001 // Transmit Packet Ready +#define MUSB_TYPE0_SPEED_M 0x00C0 // Operating Speed +#define MUSB_TYPE0_SPEED_HIGH 0x0040 // High +#define MUSB_TYPE0_SPEED_FULL 0x0080 // Full +#define MUSB_TYPE0_SPEED_LOW 0x00C0 // Low //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRH7 register. +// The following are defines for the bit fields in the MUSB_O_NAKLMT register. // //***************************************************************************** -#define USB_TXCSRH7_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH7_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH7_MODE 0x00000020 // Mode -#define USB_TXCSRH7_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH7_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH7_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH7_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH7_DT 0x00000001 // Data Toggle +#define MUSB_NAKLMT_NAKLMT_M 0x001F // EP0 NAK Limit +#define MUSB_NAKLMT_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXMAXP7 register. +// The following are defines for the bit fields in the MUSB_O_TXCSRL1 register. // //***************************************************************************** -#define USB_RXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP7_MAXLOAD_S 0 +#define MUSB_TXCSRL1_NAKTO 0x0080 // NAK Timeout +#define MUSB_TXCSRL1_CLRDT 0x0040 // Clear Data Toggle +#define MUSB_TXCSRL1_STALLED 0x0020 // Endpoint Stalled +#define MUSB_TXCSRL1_STALL 0x0010 // Send STALL +#define MUSB_TXCSRL1_SETUP 0x0010 // Setup Packet +#define MUSB_TXCSRL1_FLUSH 0x0008 // Flush FIFO +#define MUSB_TXCSRL1_ERROR 0x0004 // Error +#define MUSB_TXCSRL1_UNDRN 0x0004 // Underrun +#define MUSB_TXCSRL1_FIFONE 0x0002 // FIFO Not Empty +#define MUSB_TXCSRL1_TXRDY 0x0001 // Transmit Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRL7 register. +// The following are defines for the bit fields in the MUSB_O_TXCSRH1 register. // //***************************************************************************** -#define USB_RXCSRL7_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL7_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL7_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL7_STALL 0x00000020 // Send STALL -#define USB_RXCSRL7_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL7_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL7_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL7_ERROR 0x00000004 // Error -#define USB_RXCSRL7_OVER 0x00000004 // Overrun -#define USB_RXCSRL7_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL7_RXRDY 0x00000001 // Receive Packet Ready +#define MUSB_TXCSRH1_AUTOSET 0x0080 // Auto Set +#define MUSB_TXCSRH1_ISO 0x0040 // Isochronous Transfers +#define MUSB_TXCSRH1_MODE 0x0020 // Mode +#define MUSB_TXCSRH1_DMAEN 0x0010 // DMA Request Enable +#define MUSB_TXCSRH1_FDT 0x0008 // Force Data Toggle +#define MUSB_TXCSRH1_DMAMOD 0x0004 // DMA Request Mode +#define MUSB_TXCSRH1_DTWE 0x0002 // Data Toggle Write Enable +#define MUSB_TXCSRH1_DT 0x0001 // Data Toggle //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRH7 register. +// The following are defines for the bit fields in the MUSB_O_RXCSRL1 register. // //***************************************************************************** -#define USB_RXCSRH7_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH7_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH7_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH7_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH7_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH7_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH7_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH7_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH7_DT 0x00000002 // Data Toggle -#define USB_RXCSRH7_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +#define MUSB_RXCSRL1_CLRDT 0x0080 // Clear Data Toggle +#define MUSB_RXCSRL1_STALLED 0x0040 // Endpoint Stalled +#define MUSB_RXCSRL1_STALL 0x0020 // Send STALL +#define MUSB_RXCSRL1_REQPKT 0x0020 // Request Packet +#define MUSB_RXCSRL1_FLUSH 0x0010 // Flush FIFO +#define MUSB_RXCSRL1_DATAERR 0x0008 // Data Error +#define MUSB_RXCSRL1_NAKTO 0x0008 // NAK Timeout +#define MUSB_RXCSRL1_OVER 0x0004 // Overrun +#define MUSB_RXCSRL1_ERROR 0x0004 // Error +#define MUSB_RXCSRL1_FULL 0x0002 // FIFO Full +#define MUSB_RXCSRL1_RXRDY 0x0001 // Receive Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCOUNT7 register. +// The following are defines for the bit fields in the MUSB_O_RXCSRH1 register. // //***************************************************************************** -#define USB_RXCOUNT7_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT7_COUNT_S 0 +#define MUSB_RXCSRH1_AUTOCL 0x0080 // Auto Clear +#define MUSB_RXCSRH1_AUTORQ 0x0040 // Auto Request +#define MUSB_RXCSRH1_ISO 0x0040 // Isochronous Transfers +#define MUSB_RXCSRH1_DMAEN 0x0020 // DMA Request Enable +#define MUSB_RXCSRH1_DISNYET 0x0010 // Disable NYET +#define MUSB_RXCSRH1_PIDERR 0x0010 // PID Error +#define MUSB_RXCSRH1_DMAMOD 0x0008 // DMA Request Mode +#define MUSB_RXCSRH1_DTWE 0x0004 // Data Toggle Write Enable +#define MUSB_RXCSRH1_DT 0x0002 // Data Toggle +#define MUSB_RXCSRH1_INCOMPRX 0x0001 // Incomplete RX Transmission Status //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXTYPE7 register. +// The following are defines for the bit fields in the MUSB_O_TXTYPE1 register. // //***************************************************************************** -#define USB_TXTYPE7_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE7_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE7_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE7_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE7_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE7_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE7_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE7_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE7_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE7_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE7_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE7_TEP_S 0 +#define MUSB_TXTYPE1_SPEED_M 0x00C0 // Operating Speed +#define MUSB_TXTYPE1_SPEED_DFLT 0x0000 // Default +#define MUSB_TXTYPE1_SPEED_HIGH 0x0040 // High +#define MUSB_TXTYPE1_SPEED_FULL 0x0080 // Full +#define MUSB_TXTYPE1_SPEED_LOW 0x00C0 // Low +#define MUSB_TXTYPE1_PROTO_M 0x0030 // Protocol +#define MUSB_TXTYPE1_PROTO_CTRL 0x0000 // Control +#define MUSB_TXTYPE1_PROTO_ISOC 0x0010 // Isochronous +#define MUSB_TXTYPE1_PROTO_BULK 0x0020 // Bulk +#define MUSB_TXTYPE1_PROTO_INT 0x0030 // Interrupt +#define MUSB_TXTYPE1_TEP_M 0x000F // Target Endpoint Number +#define MUSB_TXTYPE1_TEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL7 +// The following are defines for the bit fields in the MUSB_O_TXINTERVAL1 // register. // //***************************************************************************** -#define USB_TXINTERVAL7_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL7_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL7_NAKLMT_S \ - 0 -#define USB_TXINTERVAL7_TXPOLL_S \ - 0 +#define MUSB_TXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit +#define MUSB_TXINTERVAL1_TXPOLL_M 0x00FF // TX Polling +#define MUSB_TXINTERVAL1_TXPOLL_S 0 +#define MUSB_TXINTERVAL1_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXTYPE7 register. +// The following are defines for the bit fields in the MUSB_O_RXTYPE1 register. // //***************************************************************************** -#define USB_RXTYPE7_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE7_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE7_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE7_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE7_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE7_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE7_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE7_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE7_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE7_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE7_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE7_TEP_S 0 +#define MUSB_RXTYPE1_SPEED_M 0x00C0 // Operating Speed +#define MUSB_RXTYPE1_SPEED_DFLT 0x0000 // Default +#define MUSB_RXTYPE1_SPEED_HIGH 0x0040 // High +#define MUSB_RXTYPE1_SPEED_FULL 0x0080 // Full +#define MUSB_RXTYPE1_SPEED_LOW 0x00C0 // Low +#define MUSB_RXTYPE1_PROTO_M 0x0030 // Protocol +#define MUSB_RXTYPE1_PROTO_CTRL 0x0000 // Control +#define MUSB_RXTYPE1_PROTO_ISOC 0x0010 // Isochronous +#define MUSB_RXTYPE1_PROTO_BULK 0x0020 // Bulk +#define MUSB_RXTYPE1_PROTO_INT 0x0030 // Interrupt +#define MUSB_RXTYPE1_TEP_M 0x000F // Target Endpoint Number +#define MUSB_RXTYPE1_TEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL7 +// The following are defines for the bit fields in the MUSB_O_RXINTERVAL1 // register. // //***************************************************************************** -#define USB_RXINTERVAL7_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL7_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL7_NAKLMT_S \ - 0 -#define USB_RXINTERVAL7_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAINTR register. -// -//***************************************************************************** -#define USB_DMAINTR_CH7 0x00000080 // Channel 7 DMA Interrupt -#define USB_DMAINTR_CH6 0x00000040 // Channel 6 DMA Interrupt -#define USB_DMAINTR_CH5 0x00000020 // Channel 5 DMA Interrupt -#define USB_DMAINTR_CH4 0x00000010 // Channel 4 DMA Interrupt -#define USB_DMAINTR_CH3 0x00000008 // Channel 3 DMA Interrupt -#define USB_DMAINTR_CH2 0x00000004 // Channel 2 DMA Interrupt -#define USB_DMAINTR_CH1 0x00000002 // Channel 1 DMA Interrupt -#define USB_DMAINTR_CH0 0x00000001 // Channel 0 DMA Interrupt +#define MUSB_RXINTERVAL1_TXPOLL_M 0x00FF // RX Polling +#define MUSB_RXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit +#define MUSB_RXINTERVAL1_TXPOLL_S 0 +#define MUSB_RXINTERVAL1_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL0 register. +// The following are defines for the bit fields in the MUSB_O_DMACTL0 register. // //***************************************************************************** -#define USB_DMACTL0_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL0_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL0_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL0_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified +#define MUSB_DMACTL0_BRSTM_M 0x0600 // Burst Mode +#define MUSB_DMACTL0_BRSTM_ANY 0x0000 // Bursts of unspecified length +#define MUSB_DMACTL0_BRSTM_INC4 0x0200 // INCR4 or unspecified length +#define MUSB_DMACTL0_BRSTM_INC8 0x0400 // INCR8, INCR4 or unspecified // length -#define USB_DMACTL0_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or +#define MUSB_DMACTL0_BRSTM_INC16 0x0600 // INCR16, INCR8, INCR4 or // unspecified length -#define USB_DMACTL0_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL0_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL0_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL0_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL0_DIR 0x00000002 // DMA Direction -#define USB_DMACTL0_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL0_EP_S 4 +#define MUSB_DMACTL0_ERR 0x0100 // Bus Error Bit +#define MUSB_DMACTL0_EP_M 0x00F0 // Endpoint number +#define MUSB_DMACTL0_IE 0x0008 // DMA Interrupt Enable +#define MUSB_DMACTL0_MODE 0x0004 // DMA Transfer Mode +#define MUSB_DMACTL0_DIR 0x0002 // DMA Direction +#define MUSB_DMACTL0_ENABLE 0x0001 // DMA Transfer Enable +#define MUSB_DMACTL0_EP_S 4 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMAADDR0 register. +// The following are defines for the bit fields in the MUSB_O_DMAADDR0 register. // //***************************************************************************** -#define USB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR0_ADDR_S 2 +#define MUSB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address +#define MUSB_DMAADDR0_ADDR_S 2 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACOUNT0 +// The following are defines for the bit fields in the MUSB_O_DMACOUNT0 // register. // //***************************************************************************** -#define USB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT0_COUNT_S 2 +#define MUSB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count +#define MUSB_DMACOUNT0_COUNT_S 2 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL1 register. +// The following are defines for the bit fields in the MUSB_O_CTO register. // //***************************************************************************** -#define USB_DMACTL1_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL1_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL1_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL1_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL1_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL1_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL1_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL1_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL1_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL1_DIR 0x00000002 // DMA Direction -#define USB_DMACTL1_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL1_EP_S 4 +#define MUSB_CTO_CCTV_M 0xFFFF // Configurable Chirp Timeout Value +#define MUSB_CTO_CCTV_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMAADDR1 register. +// The following are defines for the bit fields in the MUSB_O_HHSRTN register. // //***************************************************************************** -#define USB_DMAADDR1_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR1_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT1 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT1_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT1_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL2 register. -// -//***************************************************************************** -#define USB_DMACTL2_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL2_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL2_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL2_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL2_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL2_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL2_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL2_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL2_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL2_DIR 0x00000002 // DMA Direction -#define USB_DMACTL2_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL2_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR2 register. -// -//***************************************************************************** -#define USB_DMAADDR2_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR2_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT2 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT2_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT2_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL3 register. -// -//***************************************************************************** -#define USB_DMACTL3_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL3_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL3_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL3_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL3_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL3_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL3_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL3_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL3_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL3_DIR 0x00000002 // DMA Direction -#define USB_DMACTL3_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL3_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR3 register. -// -//***************************************************************************** -#define USB_DMAADDR3_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR3_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT3 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT3_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT3_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL4 register. -// -//***************************************************************************** -#define USB_DMACTL4_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL4_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL4_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL4_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL4_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL4_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL4_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL4_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL4_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL4_DIR 0x00000002 // DMA Direction -#define USB_DMACTL4_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL4_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR4 register. -// -//***************************************************************************** -#define USB_DMAADDR4_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR4_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT4 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT4_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT4_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL5 register. -// -//***************************************************************************** -#define USB_DMACTL5_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL5_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL5_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL5_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL5_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL5_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL5_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL5_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL5_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL5_DIR 0x00000002 // DMA Direction -#define USB_DMACTL5_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL5_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR5 register. -// -//***************************************************************************** -#define USB_DMAADDR5_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR5_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT5 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT5_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT5_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL6 register. -// -//***************************************************************************** -#define USB_DMACTL6_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL6_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL6_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL6_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL6_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL6_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL6_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL6_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL6_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL6_DIR 0x00000002 // DMA Direction -#define USB_DMACTL6_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL6_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR6 register. -// -//***************************************************************************** -#define USB_DMAADDR6_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR6_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT6 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT6_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT6_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL7 register. -// -//***************************************************************************** -#define USB_DMACTL7_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL7_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL7_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL7_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL7_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL7_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL7_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL7_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL7_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL7_DIR 0x00000002 // DMA Direction -#define USB_DMACTL7_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL7_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR7 register. -// -//***************************************************************************** -#define USB_DMAADDR7_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR7_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT7 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT7_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT7_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT1 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT1_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT1_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT2 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT2_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT2_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT3 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT3_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT3_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT4 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT4_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT4_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT5 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT5_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT5_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT6 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT6_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT6_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT7 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT7_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT7_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXDPKTBUFDIS -// register. -// -//***************************************************************************** -#define USB_RXDPKTBUFDIS_EP7 0x00000080 // EP7 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP6 0x00000040 // EP6 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP5 0x00000020 // EP5 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP4 0x00000010 // EP4 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP3 0x00000008 // EP3 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP2 0x00000004 // EP2 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP1 0x00000002 // EP1 RX Double-Packet Buffer - // Disable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXDPKTBUFDIS -// register. -// -//***************************************************************************** -#define USB_TXDPKTBUFDIS_EP7 0x00000080 // EP7 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP6 0x00000040 // EP6 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP5 0x00000020 // EP5 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP4 0x00000010 // EP4 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP3 0x00000008 // EP3 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP2 0x00000004 // EP2 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP1 0x00000002 // EP1 TX Double-Packet Buffer - // Disable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CTO register. -// -//***************************************************************************** -#define USB_CTO_CCTV_M 0x0000FFFF // Configurable Chirp Timeout Value -#define USB_CTO_CCTV_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_HHSRTN register. -// -//***************************************************************************** -#define USB_HHSRTN_HHSRTN_M 0x0000FFFF // HIgh Speed to UTM Operating +#define MUSB_HHSRTN_HHSRTN_M 0xFFFF // HIgh Speed to UTM Operating // Delay -#define USB_HHSRTN_HHSRTN_S 0 +#define MUSB_HHSRTN_HHSRTN_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_HSBT register. +// The following are defines for the bit fields in the MUSB_O_HSBT register. // //***************************************************************************** -#define USB_HSBT_HSBT_M 0x0000000F // High Speed Timeout Adder -#define USB_HSBT_HSBT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMATTR register. -// -//***************************************************************************** -#define USB_LPMATTR_ENDPT_M 0x0000F000 // Endpoint -#define USB_LPMATTR_RMTWAK 0x00000100 // Remote Wake -#define USB_LPMATTR_HIRD_M 0x000000F0 // Host Initiated Resume Duration -#define USB_LPMATTR_LS_M 0x0000000F // Link State -#define USB_LPMATTR_LS_L1 0x00000001 // Sleep State (L1) -#define USB_LPMATTR_ENDPT_S 12 -#define USB_LPMATTR_HIRD_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMCNTRL register. -// -//***************************************************************************** -#define USB_LPMCNTRL_NAK 0x00000010 // LPM NAK -#define USB_LPMCNTRL_EN_M 0x0000000C // LPM Enable -#define USB_LPMCNTRL_EN_NONE 0x00000000 // LPM and Extended transactions - // are not supported. In this case, - // the USB does not respond to LPM - // transactions and LPM - // transactions cause a timeout -#define USB_LPMCNTRL_EN_EXT 0x00000004 // LPM is not supported but - // extended transactions are - // supported. In this case, the USB - // does respond to an LPM - // transaction with a STALL -#define USB_LPMCNTRL_EN_LPMEXT 0x0000000C // The USB supports LPM extended - // transactions. In this case, the - // USB responds with a NYET or an - // ACK as determined by the value - // of TXLPM and other conditions -#define USB_LPMCNTRL_RES 0x00000002 // LPM Resume -#define USB_LPMCNTRL_TXLPM 0x00000001 // Transmit LPM Transaction Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMIM register. -// -//***************************************************************************** -#define USB_LPMIM_ERR 0x00000020 // LPM Error Interrupt Mask -#define USB_LPMIM_RES 0x00000010 // LPM Resume Interrupt Mask -#define USB_LPMIM_NC 0x00000008 // LPM NC Interrupt Mask -#define USB_LPMIM_ACK 0x00000004 // LPM ACK Interrupt Mask -#define USB_LPMIM_NY 0x00000002 // LPM NY Interrupt Mask -#define USB_LPMIM_STALL 0x00000001 // LPM STALL Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMRIS register. -// -//***************************************************************************** -#define USB_LPMRIS_ERR 0x00000020 // LPM Interrupt Status -#define USB_LPMRIS_RES 0x00000010 // LPM Resume Interrupt Status -#define USB_LPMRIS_NC 0x00000008 // LPM NC Interrupt Status -#define USB_LPMRIS_ACK 0x00000004 // LPM ACK Interrupt Status -#define USB_LPMRIS_NY 0x00000002 // LPM NY Interrupt Status -#define USB_LPMRIS_LPMST 0x00000001 // LPM STALL Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMFADDR register. -// -//***************************************************************************** -#define USB_LPMFADDR_ADDR_M 0x0000007F // LPM Function Address -#define USB_LPMFADDR_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPC register. -// -//***************************************************************************** -#define USB_EPC_PFLTACT_M 0x00000300 // Power Fault Action -#define USB_EPC_PFLTACT_UNCHG 0x00000000 // Unchanged -#define USB_EPC_PFLTACT_TRIS 0x00000100 // Tristate -#define USB_EPC_PFLTACT_LOW 0x00000200 // Low -#define USB_EPC_PFLTACT_HIGH 0x00000300 // High -#define USB_EPC_PFLTAEN 0x00000040 // Power Fault Action Enable -#define USB_EPC_PFLTSEN_HIGH 0x00000020 // Power Fault Sense -#define USB_EPC_PFLTEN 0x00000010 // Power Fault Input Enable -#define USB_EPC_EPENDE 0x00000004 // EPEN Drive Enable -#define USB_EPC_EPEN_M 0x00000003 // External Power Supply Enable - // Configuration -#define USB_EPC_EPEN_LOW 0x00000000 // Power Enable Active Low -#define USB_EPC_EPEN_HIGH 0x00000001 // Power Enable Active High -#define USB_EPC_EPEN_VBLOW 0x00000002 // Power Enable High if VBUS Low - // (OTG only) -#define USB_EPC_EPEN_VBHIGH 0x00000003 // Power Enable High if VBUS High - // (OTG only) - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCRIS register. -// -//***************************************************************************** -#define USB_EPCRIS_PF 0x00000001 // USB Power Fault Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCIM register. -// -//***************************************************************************** -#define USB_EPCIM_PF 0x00000001 // USB Power Fault Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCISC register. -// -//***************************************************************************** -#define USB_EPCISC_PF 0x00000001 // USB Power Fault Interrupt Status - // and Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRRIS register. -// -//***************************************************************************** -#define USB_DRRIS_RESUME 0x00000001 // RESUME Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRIM register. -// -//***************************************************************************** -#define USB_DRIM_RESUME 0x00000001 // RESUME Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRISC register. -// -//***************************************************************************** -#define USB_DRISC_RESUME 0x00000001 // RESUME Interrupt Status and - // Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_GPCS register. -// -//***************************************************************************** -#define USB_GPCS_DEVMOD_M 0x00000007 // Device Mode -#define USB_GPCS_DEVMOD_OTG 0x00000000 // Use USB0VBUS and USB0ID pin -#define USB_GPCS_DEVMOD_HOST 0x00000002 // Force USB0VBUS and USB0ID low -#define USB_GPCS_DEVMOD_DEV 0x00000003 // Force USB0VBUS and USB0ID high -#define USB_GPCS_DEVMOD_HOSTVBUS \ - 0x00000004 // Use USB0VBUS and force USB0ID - // low -#define USB_GPCS_DEVMOD_DEVVBUS 0x00000005 // Use USB0VBUS and force USB0ID - // high - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDC register. -// -//***************************************************************************** -#define USB_VDC_VBDEN 0x00000001 // VBUS Droop Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCRIS register. -// -//***************************************************************************** -#define USB_VDCRIS_VD 0x00000001 // VBUS Droop Raw Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCIM register. -// -//***************************************************************************** -#define USB_VDCIM_VD 0x00000001 // VBUS Droop Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCISC register. -// -//***************************************************************************** -#define USB_VDCISC_VD 0x00000001 // VBUS Droop Interrupt Status and - // Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_PP register. -// -//***************************************************************************** -#define USB_PP_ECNT_M 0x0000FF00 // Endpoint Count -#define USB_PP_USB_M 0x000000C0 // USB Capability -#define USB_PP_USB_DEVICE 0x00000040 // DEVICE -#define USB_PP_USB_HOSTDEVICE 0x00000080 // HOST -#define USB_PP_USB_OTG 0x000000C0 // OTG -#define USB_PP_ULPI 0x00000020 // ULPI Present -#define USB_PP_PHY 0x00000010 // PHY Present -#define USB_PP_TYPE_M 0x0000000F // Controller Type -#define USB_PP_TYPE_0 0x00000000 // The first-generation USB - // controller -#define USB_PP_TYPE_1 0x00000001 // The second-generation USB - // controller revision -#define USB_PP_ECNT_S 8 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_PC register. -// -//***************************************************************************** -#define USB_PC_ULPIEN 0x00010000 // ULPI Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CC register. -// -//***************************************************************************** -#define USB_CC_CLKEN 0x00000200 // USB Clock Enable -#define USB_CC_CSD 0x00000100 // Clock Source/Direction -#define USB_CC_CLKDIV_M 0x0000000F // PLL Clock Divisor -#define USB_CC_CLKDIV_S 0 +#define MUSB_HSBT_HSBT_M 0x000F // High Speed Timeout Adder +#define MUSB_HSBT_HSBT_S 0 #ifdef __cplusplus } diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index e3fa51e31..a15431937 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -277,6 +277,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 1cc5c1836..a63e442f3 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -441,11 +441,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE)); if (control_status) { - // Status Phase also requires EasyDMA has to be available as well !!!! - edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); - // The nRF doesn't interrupt on status transmit so we queue up a success response. dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr()); + + // Status Phase also requires EasyDMA has to be available as well !!!! + edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); } else if (dir == TUSB_DIR_OUT) { xfer->started = true; if (epnum == 0) { diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index b880c2870..75b29faf3 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -335,6 +335,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 1ca711c77..43f48da39 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -53,6 +53,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) { //--------------------------------------------------------------------+ // Implementation //--------------------------------------------------------------------+ +// Provide own byte by byte memcpy as not all copies are aligned +static void unaligned_memcpy(void *dst, const void *src, size_t n) { + uint8_t *dst_byte = (uint8_t*)dst; + const uint8_t *src_byte = (const uint8_t*)src; + while (n--) { + *dst_byte++ = *src_byte++; + } +} void rp2040_usb_init(void) { // Reset usb controller @@ -67,7 +75,6 @@ void rp2040_usb_init(void) { #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif #endif - memset(usb_hw, 0, sizeof(*usb_hw)); memset(usb_dpram, 0, sizeof(*usb_dpram)); #ifdef __GNUC__ #pragma GCC diagnostic pop @@ -125,7 +132,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, if (!ep->rx) { // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen); + unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen); ep->user_buf += buflen; // Mark as full @@ -230,7 +237,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin // we have received AFTER we have copied it to the user buffer at the appropriate offset assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes); + unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes); ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes); ep->user_buf += xferred_bytes; } diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 8bfb899ca..6eea1ab32 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -4,7 +4,6 @@ * Copyright (c) 2019 Nathan Conrad * * Portions: - * Copyright (c) 2016 STMicroelectronics * Copyright (c) 2019 Ha Thach (tinyusb.org) * Copyright (c) 2022 Simon Küppers (skuep) * Copyright (c) 2022 HiFiPhile @@ -114,8 +113,6 @@ #include "device/dcd.h" #if defined(TUP_USBIP_FSDEV_STM32) - // Undefine to reduce the dependence on HAL - #undef USE_HAL_DRIVER #include "fsdev_stm32.h" #elif defined(TUP_USBIP_FSDEV_CH32) #include "fsdev_ch32.h" @@ -123,27 +120,7 @@ #error "Unknown USB IP" #endif -#include "fsdev_common.h" - -//--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ - -// hardware limit endpoint -#define FSDEV_EP_COUNT 8 - -// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it -// Both of these MUST be a multiple of 2, and are in byte units. -#ifndef DCD_STM32_BTABLE_BASE -#define DCD_STM32_BTABLE_BASE 0U -#endif - -#ifndef DCD_STM32_BTABLE_SIZE -#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) -#endif - -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); +#include "fsdev_type.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -168,11 +145,7 @@ typedef struct { } ep_alloc_t; static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2]; - static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT]; - -static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; - static uint8_t remoteWakeCountdown; // When wake is requested //--------------------------------------------------------------------+ @@ -180,99 +153,90 @@ static uint8_t remoteWakeCountdown; // When wake is requested //--------------------------------------------------------------------+ // into the stack. -static void dcd_handle_bus_reset(void); +static void handle_bus_reset(uint8_t rhport); static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix); -static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr); -static void dcd_ep_ctr_handler(void); +static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir); // PMA allocation/access static uint16_t ep_buf_ptr; ///< Points to first free memory location -static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf); +static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf); static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); +static void edpt0_open(uint8_t rhport); + +TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) { + btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8); +} + //--------------------------------------------------------------------+ // Inline helper //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr) -{ - uint8_t epnum = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - // Fix -Werror=null-dereference - TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX, &xfer_status[0][0]); - +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint8_t dir) { return &xfer_status[epnum][dir]; } //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ - -void dcd_init(uint8_t rhport) -{ - /* Clocks should already be enabled */ - /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ - - /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. - * Here, the RM is followed. */ - +void dcd_init(uint8_t rhport) { + // Follow the RM mentions to use a special ordering of PDWN and FRES for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } + // Perform USB peripheral reset - USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR &= ~USB_CNTR_PDWN; + FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; // Wait startup time, for F042 and F070, this is <= 1 us. for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR = 0; // Enable USB + FSDEV_REG->CNTR = 0; // Enable USB -#if !defined(STM32G0) && !defined(STM32H5) && !defined(STM32U5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address - USB->BTABLE = DCD_STM32_BTABLE_BASE; +#if !defined(FSDEV_BUS_32BIT) + // BTABLE register does not exist any more on 32-bit bus devices + FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif - USB->ISTR = 0; // Clear pending interrupts + + FSDEV_REG->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED. - pcd_set_endpoint(USB, i, 0u); + ep_write(i, 0u, false); } - USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; - dcd_handle_bus_reset(); + FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | + USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; + handle_bus_reset(rhport); // Enable pull-up if supported dcd_connect(rhport); } - -void dcd_sof_enable(uint8_t rhport, bool en) -{ +void dcd_sof_enable(uint8_t rhport, bool en) { (void)rhport; - (void)en; if (en) { - USB->CNTR |= USB_CNTR_SOFM; + FSDEV_REG->CNTR |= USB_CNTR_SOFM; } else { - USB->CNTR &= ~USB_CNTR_SOFM; + FSDEV_REG->CNTR &= ~USB_CNTR_SOFM; } } // Receive Set Address request, mcu port must also include status IN response -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) -{ - (void)rhport; +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { (void)dev_addr; // Respond with status @@ -282,35 +246,15 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // do it at dcd_edpt0_status_complete() } -void dcd_remote_wakeup(uint8_t rhport) -{ +void dcd_remote_wakeup(uint8_t rhport) { (void)rhport; - USB->CNTR |= USB_CNTR_RESUME; + FSDEV_REG->CNTR |= USB_CNTR_RESUME; remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. } -static const tusb_desc_endpoint_t ep0OUT_desc = { - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = 0x00, - .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 -}; - -static const tusb_desc_endpoint_t ep0IN_desc = { - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = 0x80, - .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 -}; - -static void dcd_handle_bus_reset(void) -{ - USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag +static void handle_bus_reset(uint8_t rhport) { + FSDEV_REG->DADDR = 0u; // disable USB Function for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // Clear EP allocation status @@ -321,35 +265,21 @@ static void dcd_handle_bus_reset(void) } // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX; + ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; - dcd_edpt_open(0, &ep0OUT_desc); - dcd_edpt_open(0, &ep0IN_desc); + edpt0_open(rhport); // open control endpoint (both IN & OUT) - USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. + FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function } // Handle CTR interrupt for the TX/IN direction -// -// Upon call, (wIstr & USB_ISTR_DIR) == 0U -static void dcd_ep_ctr_tx_handler(uint32_t wIstr) -{ - uint32_t EPindex = wIstr & USB_ISTR_EP_ID; - uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK; +static void handle_ctr_tx(uint32_t ep_id) { + uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - // Verify the CTR_TX bit is set. This was in the ST Micro code, - // but I'm not sure it's actually necessary? - if ((wEPRegVal & USB_EP_CTR_TX) == 0U) { - return; - } + uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN); - /* clear int flag */ - pcd_clear_tx_ep_ctr(USB, EPindex); - - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - - if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + if (ep_is_iso(ep_reg)) { // Ignore spurious interrupts that we don't schedule // host can send IN token while there is no data to send, since ISO does not have NAK // this will result to zero length packet --> trigger interrupt (which cannot be masked) @@ -357,189 +287,106 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) return; } xfer->iso_in_sending = false; - - if (wEPRegVal & USB_EP_DTOG_TX) { - pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0); - } else { - pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0); - } + uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1; + btable_set_count(ep_id, buf_id, 0); } - if ((xfer->total_len != xfer->queued_len)) { - dcd_transmit_packet(xfer, EPindex); + if (xfer->total_len != xfer->queued_len) { + dcd_transmit_packet(xfer, ep_id); } else { - dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } +} + +static void handle_ctr_setup(uint32_t ep_id) { + uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX); + uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX); + uint8_t setup_packet[8] TU_ATTR_ALIGNED(4); + + dcd_read_packet_memory(setup_packet, rx_addr, rx_count); + + // Clear CTR RX if another setup packet arrived before this, it will be discarded + ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); + + // Setup packet should always be 8 bytes. If not, we probably missed the packet + if (rx_count == 8) { + dcd_event_setup_received(0, (uint8_t*) setup_packet, true); + // Hardware should reset EP0 RX/TX to NAK and both toggle to 1 + } else { + // Missed setup packet !!! + TU_BREAKPOINT(); + edpt0_prepare_setup(); } } // Handle CTR interrupt for the RX/OUT direction -// Upon call, (wIstr & USB_ISTR_DIR) == 0U -static void dcd_ep_ctr_rx_handler(uint32_t wIstr) -{ -#ifdef FSDEV_BUS_32BIT - /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf - * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers - * Description: - * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses - * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. - * Workaround: - * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay - * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode - * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code - * also takes time, so we'll wait 60 cycles (count = 20). - * - Since Low Speed mode is not supported/popular, we will ignore it for now. - * - * Note: this errata also seems to apply to G0, U5, H5 etc. - */ - volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver - while (cycle_count > 0U) { - cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) - } -#endif +static void handle_ctr_rx(uint32_t ep_id) { + uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; + bool const is_iso = ep_is_iso(ep_reg); + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT); - uint32_t EPindex = wIstr & USB_ISTR_EP_ID; - uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; - - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - - // Verify the CTR_RX bit is set. This was in the ST Micro code, - // but I'm not sure it's actually necessary? - if ((wEPRegVal & USB_EP_CTR_RX) == 0U) { - return; - } - - if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) { - /* Setup packet */ - uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); - // Setup packet should always be 8 bytes. If not, ignore it, and try again. - if (count == 8) { - // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) - pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK); - pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK); -#ifdef FSDEV_BUS_32BIT - dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true); -#else - // The setup_received function uses memcpy, so this must first copy the setup data into - // user memory, to allow for the 32-bit access that memcpy performs. - uint8_t userMemBuf[8]; - dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8); - dcd_event_setup_received(0, (uint8_t *)userMemBuf, true); -#endif - } + uint8_t buf_id; + if (is_iso) { + buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered } else { - // Clear RX CTR interrupt flag - if (ep_addr != 0u) { - pcd_clear_rx_ep_ctr(USB, EPindex); - } - - uint32_t count; - uint16_t addr; - /* Read from correct register when ISOCHRONOUS (double buffered) */ - if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { - if (wEPRegVal & USB_EP_DTOG_RX) { - count = pcd_get_ep_dbuf0_cnt(USB, EPindex); - addr = pcd_get_ep_dbuf0_address(USB, EPindex); - } else { - count = pcd_get_ep_dbuf1_cnt(USB, EPindex); - addr = pcd_get_ep_dbuf1_address(USB, EPindex); - } - } else { - count = pcd_get_ep_rx_cnt(USB, EPindex); - addr = pcd_get_ep_rx_address(USB, EPindex); - } - - TU_ASSERT(count <= xfer->max_packet_size, /**/); - - if (count != 0U) { - if (xfer->ff) { - dcd_read_packet_memory_ff(xfer->ff, addr, count); - } else { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); - } - - xfer->queued_len = (uint16_t)(xfer->queued_len + count); - } - - if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { - // all bytes received or short packet - dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - } else { - /* Set endpoint active again for receiving more data. - * Note that isochronous endpoints stay active always */ - if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) { - uint16_t remaining = xfer->total_len - xfer->queued_len; - uint16_t cnt = tu_min16(remaining, xfer->max_packet_size); - pcd_set_ep_rx_cnt(USB, EPindex, cnt); - } - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); - } + buf_id = BTABLE_BUF_RX; } + uint16_t const rx_count = btable_get_count(ep_id, buf_id); + uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id); - // For EP0, prepare to receive another SETUP packet. - // Clear CTR last so that a new packet does not overwrite the packing being read. - // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if (ep_addr == 0u) { - // Always be prepared for a status packet... - pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); - pcd_clear_rx_ep_ctr(USB, EPindex); + if (xfer->ff) { + dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count); + } else { + dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count); + } + xfer->queued_len += rx_count; + + if ((rx_count < xfer->max_packet_size) || (xfer->queued_len >= xfer->total_len)) { + // all bytes received or short packet + + // For ch32v203: reset rx bufsize to mps to prevent race condition to cause PMAOVR (occurs with msc write10) + btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, xfer->max_packet_size); + + dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); + + // ch32 seems to unconditionally accept ZLP on EP0 OUT, which can incorrectly use queued_len of previous + // transfer. So reset total_len and queued_len to 0. + xfer->total_len = xfer->queued_len = 0; + } else { + // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always + if (!is_iso) { + uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt); + } + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_VALID); + ep_write(ep_id, ep_reg, false); } } -static void dcd_ep_ctr_handler(void) -{ - uint32_t wIstr; - - /* stay in loop while pending interrupts */ - while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) { - if ((wIstr & USB_ISTR_DIR) == 0U) { - /* TX/IN */ - dcd_ep_ctr_tx_handler(wIstr); - } else { - /* RX/OUT*/ - dcd_ep_ctr_rx_handler(wIstr); - } - } -} - -void dcd_int_handler(uint8_t rhport) -{ - (void)rhport; - - uint32_t int_status = USB->ISTR; - // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP - // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; - // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) - - // The ST driver loops here on the CTR bit, but that loop has been moved into the - // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't - // be triggered repeatedly. +void dcd_int_handler(uint8_t rhport) { + uint32_t int_status = FSDEV_REG->ISTR; /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ if (int_status & USB_ISTR_SOF) { - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; - dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; + dcd_event_sof(0, FSDEV_REG->FNR & USB_FNR_FN, true); } if (int_status & USB_ISTR_RESET) { // USBRST is start of reset. - USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; - dcd_handle_bus_reset(); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; + handle_bus_reset(rhport); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? } - if (int_status & USB_ISTR_CTR) { - /* servicing of the endpoint correct transfer interrupt */ - /* clear of the CTR flag into the sub */ - dcd_ep_ctr_handler(); - } - if (int_status & USB_ISTR_WKUP) { - USB->CNTR &= ~USB_CNTR_LPMODE; - USB->CNTR &= ~USB_CNTR_FSUSP; + FSDEV_REG->CNTR &= ~USB_CNTR_LPMODE; + FSDEV_REG->CNTR &= ~USB_CNTR_FSUSP; - USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -548,22 +395,70 @@ void dcd_int_handler(uint8_t rhport) * these events cannot be differentiated, so we only trigger suspend. */ /* Force low-power mode in the macrocell */ - USB->CNTR |= USB_CNTR_FSUSP; - USB->CNTR |= USB_CNTR_LPMODE; + FSDEV_REG->CNTR |= USB_CNTR_FSUSP; + FSDEV_REG->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } if (int_status & USB_ISTR_ESOF) { if (remoteWakeCountdown == 1u) { - USB->CNTR &= ~USB_CNTR_RESUME; + FSDEV_REG->CNTR &= ~USB_CNTR_RESUME; } if (remoteWakeCountdown > 0u) { remoteWakeCountdown--; } - USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; + } + + // loop to handle all pending CTR interrupts + while (FSDEV_REG->ISTR & USB_ISTR_CTR) { + // skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt + uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID; + uint32_t const ep_reg = ep_read(ep_id); + + if (ep_reg & USB_EP_CTR_RX) { + #ifdef FSDEV_BUS_32BIT + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf + * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code + * also takes time, so we'll wait 60 cycles (count = 20). + * - Since Low Speed mode is not supported/popular, we will ignore it for now. + * + * Note: this errata may also apply to G0, U5, H5 etc. + */ + volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } + #endif + + if (ep_reg & USB_EP_SETUP) { + handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet + } else { + ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); + handle_ctr_rx(ep_id); + } + } + + if (ep_reg & USB_EP_CTR_TX) { + ep_write_clear_ctr(ep_id, TUSB_DIR_IN); + handle_ctr_tx(ep_id); + } + } + + if (int_status & USB_ISTR_PMAOVR) { + TU_BREAKPOINT(); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR; } } @@ -573,19 +468,17 @@ void dcd_int_handler(uint8_t rhport) // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) -{ +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { uint8_t const dev_addr = (uint8_t)request->wValue; - - // Setting new address after the whole request is complete - USB->DADDR &= ~USB_DADDR_ADD; - USB->DADDR |= dev_addr; // leave the enable bit set + FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr); } + + edpt0_prepare_setup(); } /*** @@ -593,21 +486,19 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req * In case of double buffering, high 16bit is the address of 2nd buffer * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ -static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf) +static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) { - // Ensure allocated buffer is aligned -#ifdef FSDEV_BUS_32BIT - length = (length + 3) & ~0x03; -#else - length = (length + 1) & ~0x01; -#endif + uint8_t blsize, num_block; + uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block); + (void) blsize; + (void) num_block; uint32_t addr = ep_buf_ptr; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer if (dbuf) { addr |= ((uint32_t)ep_buf_ptr) << 16; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer } // Verify packet buffer is not overflowed @@ -654,34 +545,53 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) TU_ASSERT(0); } -// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, -// so I'm using the #define from HAL here, instead. +void edpt0_open(uint8_t rhport) { + (void) rhport; -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) -{ + dcd_ep_alloc(0x0, TUSB_XFER_CONTROL); + dcd_ep_alloc(0x80, TUSB_XFER_CONTROL); + + xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][0].ep_idx = 0; + + xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][1].ep_idx = 0; + + uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); + uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); + + btable_set_addr(0, BTABLE_BUF_RX, pma_addr0); + btable_set_addr(0, BTABLE_BUF_TX, pma_addr1); + + uint32_t ep_reg = ep_read(0) & ~USB_EPREG_MASK; // only get toggle bits + ep_reg |= USB_EP_CONTROL; + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_NAK); + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_NAK); + // no need to explicitly set DTOG bits since we aren't masked DTOG bit + + edpt0_prepare_setup(); // prepare for setup packet + ep_write(0, ep_reg, false); +} + +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { (void)rhport; - uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer); - uint8_t const dir = tu_edpt_dir(ep_addr); - const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); - const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); - uint16_t pma_addr; - uint32_t wType; - + uint8_t const ep_addr = desc_ep->bEndpointAddress; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint16_t packet_size = tu_edpt_packet_size(desc_ep); + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer); TU_ASSERT(ep_idx < FSDEV_EP_COUNT); - TU_ASSERT(buffer_size <= 64); + + uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; + ep_reg |= tu_edpt_number(ep_addr) | USB_EP_CTR_TX | USB_EP_CTR_RX; // Set type - switch (p_endpoint_desc->bmAttributes.xfer) { - case TUSB_XFER_CONTROL: - wType = USB_EP_CONTROL; - break; + switch (desc_ep->bmAttributes.xfer) { case TUSB_XFER_BULK: - wType = USB_EP_CONTROL; + ep_reg |= USB_EP_BULK; break; - case TUSB_XFER_INTERRUPT: - wType = USB_EP_INTERRUPT; + ep_reg |= USB_EP_INTERRUPT; break; default: @@ -689,35 +599,35 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) TU_ASSERT(false); } - pcd_set_eptype(USB, ep_idx, wType); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - /* Create a packet memory buffer area. */ - pma_addr = dcd_pma_alloc(buffer_size, false); + uint16_t pma_addr = dcd_pma_alloc(packet_size, false); + btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer->max_packet_size = packet_size; + xfer->ep_idx = ep_idx; + + ep_change_status(&ep_reg, dir, EP_STAT_NAK); + ep_change_dtog(&ep_reg, dir, 0); + + // reserve other direction toggle bits if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_address(USB, ep_idx, pma_addr); - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - pcd_clear_tx_dtog(USB, ep_idx); + ep_reg &= ~(USB_EPRX_STAT | USB_EP_DTOG_RX); } else { - pcd_set_ep_rx_address(USB, ep_idx, pma_addr); - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - pcd_clear_rx_dtog(USB, ep_idx); + ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX); } - xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + ep_write(ep_idx, ep_reg, true); return true; } -void dcd_edpt_close_all(uint8_t rhport) -{ - (void)rhport; +void dcd_edpt_close_all(uint8_t rhport) { + dcd_int_disable(rhport); for (uint32_t i = 1; i < FSDEV_EP_COUNT; i++) { // Reset endpoint - pcd_set_endpoint(USB, i, 0); + ep_write(i, 0, false); // Clear EP allocation status ep_alloc_status[i].ep_num = 0xFF; ep_alloc_status[i].ep_type = 0xFF; @@ -725,508 +635,340 @@ void dcd_edpt_close_all(uint8_t rhport) ep_alloc_status[i].allocated[1] = false; } + dcd_int_enable(rhport); + // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE; + ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE; } -/** - * Close an endpoint. - * - * This function may be called with interrupts enabled or disabled. - * - * This also clears transfers in progress, should there be any. - */ -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - uint8_t const ep_idx = xfer->ep_idx; + uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - - if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } -} - -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) -{ - (void)rhport; - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); - const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA, for smaller devices double buffering occupy too much space. */ #if FSDEV_PMA_SIZE > 1024u - uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true); uint16_t pma_addr2 = pma_addr >> 16; #else - uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false); uint16_t pma_addr2 = pma_addr; #endif - pcd_set_ep_tx_address(USB, ep_idx, pma_addr); - pcd_set_ep_rx_address(USB, ep_idx, pma_addr2); - pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); + btable_set_addr(ep_idx, 0, pma_addr); + btable_set_addr(ep_idx, 1, pma_addr2); - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); + xfer->ep_idx = ep_idx; return true; } -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) -{ +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { (void)rhport; - uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; - uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); - const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + uint8_t const ep_addr = desc_ep->bEndpointAddress; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + uint8_t const ep_idx = xfer->ep_idx; - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); + xfer->max_packet_size = tu_edpt_packet_size(desc_ep); - pcd_clear_tx_dtog(USB, ep_idx); - pcd_clear_rx_dtog(USB, ep_idx); + uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; + ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX; + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED); + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); + ep_change_dtog(&ep_reg, dir, 0); + ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1); - if (dir == TUSB_DIR_IN) { - pcd_rx_dtog(USB, ep_idx); - } else { - pcd_tx_dtog(USB, ep_idx); - } - - xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; + ep_write(ep_idx, ep_reg, true); return true; } // Currently, single-buffered, and only 64 bytes at a time (max) +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { + uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR -static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) -{ - uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); - if (len > xfer->max_packet_size) { - len = xfer->max_packet_size; - } - - uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); - bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; - uint16_t addr_ptr; + bool const is_iso = ep_is_iso(ep_reg); + uint8_t buf_id; if (is_iso) { - if (ep_reg & USB_EP_DTOG_TX) { - addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix); - pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len); - } else { - addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix); - pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len); - } + buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0; } else { - addr_ptr = pcd_get_ep_tx_address(USB, ep_ix); - pcd_set_ep_tx_cnt(USB, ep_ix, len); + buf_id = BTABLE_BUF_TX; } + uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id); if (xfer->ff) { dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } - xfer->queued_len = (uint16_t)(xfer->queued_len + len); + xfer->queued_len += len; + + btable_set_count(ep_ix, buf_id, len); + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_VALID); - dcd_int_disable(0); - pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); if (is_iso) { xfer->iso_in_sending = true; } - dcd_int_enable(0); + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_IN); // only change TX Status, reserve other toggle bits + ep_write(ep_ix, ep_reg, true); } -static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; +static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { + (void) rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_IN) { dcd_transmit_packet(xfer, ep_idx); } else { - // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid - // buffer for the control endpoint. - if (ep_idx == 0 && xfer->buffer == NULL) { - xfer->buffer = (uint8_t *)_setup_packet; - } + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir); - uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size); - uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx); + uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size); - if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt); - pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt); + if (ep_is_iso(ep_reg)) { + btable_set_rx_bufsize(ep_idx, 0, cnt); + btable_set_rx_bufsize(ep_idx, 1, cnt); } else { - pcd_set_ep_rx_cnt(USB, ep_idx, cnt); + btable_set_rx_bufsize(ep_idx, BTABLE_BUF_RX, cnt); } - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); + ep_change_status(&ep_reg, dir, EP_STAT_VALID); + ep_write(ep_idx, ep_reg, true); } return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) -{ - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); xfer->buffer = buffer; xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; - return edpt_xfer(rhport, ep_addr); + return edpt_xfer(rhport, ep_num, dir); } -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) -{ - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer->buffer = NULL; xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; - return edpt_xfer(rhport, ep_addr); + return edpt_xfer(rhport, ep_num, dir); } -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + (void)rhport; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + uint8_t const ep_idx = xfer->ep_idx; + + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir); + ep_change_status(&ep_reg, dir, EP_STAT_STALL); + + ep_write(ep_idx, ep_reg, true); +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir); + + if (!ep_is_iso(ep_reg)) { + ep_change_status(&ep_reg, dir, EP_STAT_NAK); } + ep_change_dtog(&ep_reg, dir, 0); // Reset to DATA0 + ep_write(ep_idx, ep_reg, true); } -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; +//--------------------------------------------------------------------+ +// PMA read/write +//--------------------------------------------------------------------+ - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); +// Write to packet memory area (PMA) from user memory +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_write = nbytes / FSDEV_BUS_SIZE; - if (dir == TUSB_DIR_IN) { // IN - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - } + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); + const uint8_t *src8 = src; - /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_tx_dtog(USB, ep_idx); - } else { // OUT - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - } - /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_rx_dtog(USB, ep_idx); - } -} - -#ifdef FSDEV_BUS_32BIT -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) -{ - const uint8_t *srcVal = src; - volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst); - - for (uint32_t n = wNBytes / 4; n > 0; --n) { - *dst32++ = tu_unaligned_read32(srcVal); - srcVal += 4; + while (n_write--) { + pma_buf->value = fsdevbus_unaligned_read(src8); + src8 += FSDEV_BUS_SIZE; + pma_buf++; } - wNBytes = wNBytes & 0x03; - if (wNBytes) { - uint32_t wrVal = *srcVal; - wNBytes--; - - if (wNBytes) { - wrVal |= *++srcVal << 8; - wNBytes--; - - if (wNBytes) { - wrVal |= *++srcVal << 16; - } + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = 0; + for(uint16_t i = 0; i < odd; i++) { + temp |= *src8++ << (i * 8); } - - *dst32 = wrVal; + pma_buf->value = temp; } return true; } -#else -// Packet buffer access can only be 8- or 16-bit. -/** - * @brief Copy a buffer from user memory area to packet memory area (PMA). - * This uses byte-access for user memory (so support non-aligned buffers) - * and 16-bit access for packet memory. - * @param dst, byte address in PMA; must be 16-bit aligned - * @param src pointer to user memory area. - * @param wPMABufAddr address into PMA. - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) -{ - uint32_t n = (uint32_t)wNBytes >> 1U; - uint16_t temp1, temp2; - const uint8_t *srcVal; - // The GCC optimizer will combine access to 32-bit sizes if we let it. Force - // it volatile so that it won't do that. - __IO uint16_t *pdwVal; +// Read from packet memory area (PMA) to user memory. +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_read = nbytes / FSDEV_BUS_SIZE; - srcVal = src; - pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)]; + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); + uint8_t *dst8 = (uint8_t *)dst; - while (n--) { - temp1 = (uint16_t)*srcVal; - srcVal++; - temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)); - *pdwVal = temp2; - pdwVal += FSDEV_PMA_STRIDE; - srcVal++; + while (n_read--) { + fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value); + dst8 += FSDEV_BUS_SIZE; + pma_buf++; } - if (wNBytes) { - temp1 = (uint16_t) *srcVal; - *pdwVal = temp1; + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = pma_buf->value; + while (odd--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } } return true; } -#endif -/** - * @brief Copy from FIFO to packet memory area (PMA). - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) -{ +// Write to PMA from FIFO +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { + if (wNBytes == 0) return true; + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies tu_fifo_buffer_info_t info; tu_fifo_get_read_info(ff, &info); - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); - uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t const cnt_total = cnt_lin + cnt_wrap; // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part - // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit) -#ifdef FSDEV_BUS_32BIT - if ((cnt_lin & 0x03) && cnt_wrap) { - // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03); - dst += cnt_lin & ~0x03; + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t const *src8 = (uint8_t const*) info.ptr_lin; - // Copy last linear bytes & first wrapped bytes to buffer - uint32_t i; - uint8_t tmp[4]; - for (i = 0; i < (cnt_lin & 0x03); i++) { - tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i]; - } - uint32_t wCnt = cnt_wrap; - for (; i < 4 && wCnt > 0; i++, wCnt--) { - tmp[i] = *(uint8_t *)info.ptr_wrap; - info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + // write even linear part + dcd_write_packet_memory(dst, src8, lin_even); + dst += lin_even; + src8 += lin_even; + + if (lin_odd == 0) { + src8 = (uint8_t const*) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp = 0; + uint16_t i; + for(i = 0; i < lin_odd; i++) { + temp |= *src8++ << (i * 8); } - // Write unaligned buffer - dcd_write_packet_memory(dst, &tmp, 4); - dst += 4; - - // Copy rest of wrapped byte - if (wCnt) - dcd_write_packet_memory(dst, info.ptr_wrap, wCnt); - } -#else - if ((cnt_lin & 0x01) && cnt_wrap) { - // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01); - dst += cnt_lin & ~0x01; - - // Copy last linear byte & first wrapped byte - uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U); - dcd_write_packet_memory(dst, &tmp, 2); - dst += 2; - - // Copy rest of wrapped byte - dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1); - } -#endif - else { - // Copy linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); - dst += info.len_lin; - - if (info.len_wrap) { - // Copy wrapped byte - dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); + src8 = (uint8_t const*) info.ptr_wrap; + for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + temp |= *src8++ << (i * 8); } + + dcd_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE); + dst += FSDEV_BUS_SIZE; } - tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap); + // write the rest of the wrapped part + dcd_write_packet_memory(dst, src8, cnt_wrap); + tu_fifo_advance_read_pointer(ff, cnt_total); return true; } -#ifdef FSDEV_BUS_32BIT -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) -{ - uint8_t *dstVal = dst; - volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src); +// Read from PMA to FIFO +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { + if (wNBytes == 0) return true; - for (uint32_t n = wNBytes / 4; n > 0; --n) { - tu_unaligned_write32(dstVal, *src32++); - dstVal += 4; - } - - wNBytes = wNBytes & 0x03; - if (wNBytes) { - uint32_t rdVal = *src32; - - *dstVal = tu_u32_byte0(rdVal); - wNBytes--; - - if (wNBytes) { - *++dstVal = tu_u32_byte1(rdVal); - wNBytes--; - - if (wNBytes) { - *++dstVal = tu_u32_byte2(rdVal); - } - } - } - - return true; -} -#else -/** - * @brief Copy a buffer from packet memory area (PMA) to user memory area. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) -{ - uint32_t n = (uint32_t)wNBytes >> 1U; - // The GCC optimizer will combine access to 32-bit sizes if we let it. Force - // it volatile so that it won't do that. - __IO const uint16_t *pdwVal; - uint32_t temp; - - pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)]; - uint8_t *dstVal = (uint8_t *)dst; - - while (n--) { - temp = *pdwVal; - pdwVal += FSDEV_PMA_STRIDE; - *dstVal++ = ((temp >> 0) & 0xFF); - *dstVal++ = ((temp >> 8) & 0xFF); - } - - if (wNBytes & 0x01) { - temp = *pdwVal; - pdwVal += FSDEV_PMA_STRIDE; - *dstVal++ = ((temp >> 0) & 0xFF); - } - return true; -} -#endif - -/** - * @brief Copy a buffer from user packet memory area (PMA) to FIFO. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) -{ // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part tu_fifo_buffer_info_t info; tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); - uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_total = cnt_lin + cnt_wrap; - // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part - // To ensure PMA is always access aligned (src aligned to 16 or 32 bit) -#ifdef FSDEV_BUS_32BIT - if ((cnt_lin & 0x03) && cnt_wrap) { - // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03); - src += cnt_lin & ~0x03; + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - // Copy last linear bytes & first wrapped bytes - uint8_t tmp[4]; - dcd_read_packet_memory(tmp, src, 4); - src += 4; + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t *dst8 = (uint8_t *) info.ptr_lin; - uint32_t i; - for (i = 0; i < (cnt_lin & 0x03); i++) { - ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i]; - } - uint32_t wCnt = cnt_wrap; - for (; i < 4 && wCnt > 0; i++, wCnt--) { - *(uint8_t *)info.ptr_wrap = tmp[i]; - info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; + // read even linear part + dcd_read_packet_memory(dst8, src, lin_even); + dst8 += lin_even; + src += lin_even; + + if (lin_odd == 0) { + dst8 = (uint8_t *) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp; + dcd_read_packet_memory(&temp, src, FSDEV_BUS_SIZE); + src += FSDEV_BUS_SIZE; + + uint16_t i; + for (i = 0; i < lin_odd; i++) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; } - // Copy rest of wrapped byte - if (wCnt) - dcd_read_packet_memory(info.ptr_wrap, src, wCnt); - } -#else - if ((cnt_lin & 0x01) && cnt_wrap) { - // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01); - src += cnt_lin & ~0x01; - - // Copy last linear byte & first wrapped byte - uint8_t tmp[2]; - dcd_read_packet_memory(tmp, src, 2); - src += 2; - - ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0]; - ((uint8_t *)info.ptr_wrap)[0] = tmp[1]; - - // Copy rest of wrapped byte - dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1); - } -#endif - else { - // Copy linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); - src += cnt_lin; - - if (info.len_wrap) { - // Copy wrapped byte - dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); + dst8 = (uint8_t *) info.ptr_wrap; + for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; } } - tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap); + // read the rest of the wrapped part + dcd_read_packet_memory(dst8, src, cnt_wrap); + tu_fifo_advance_write_pointer(ff, cnt_total); return true; } diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index f63a80d56..518197c47 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -54,44 +54,8 @@ #endif #define FSDEV_PMA_SIZE (512u) - -// volatile 32-bit aligned -#define _va32 volatile TU_ATTR_ALIGNED(4) - -typedef struct { - _va32 uint16_t EP0R; // 00: USB Endpoint 0 register - _va32 uint16_t EP1R; // 04: USB Endpoint 1 register - _va32 uint16_t EP2R; // 08: USB Endpoint 2 register - _va32 uint16_t EP3R; // 0C: USB Endpoint 3 register - _va32 uint16_t EP4R; // 10: USB Endpoint 4 register - _va32 uint16_t EP5R; // 14: USB Endpoint 5 register - _va32 uint16_t EP6R; // 18: USB Endpoint 6 register - _va32 uint16_t EP7R; // 1C: USB Endpoint 7 register - _va32 uint16_t RESERVED7[16]; // Reserved - _va32 uint16_t CNTR; // 40: Control register - _va32 uint16_t ISTR; // 44: Interrupt status register - _va32 uint16_t FNR; // 48: Frame number register - _va32 uint16_t DADDR; // 4C: Device address register - _va32 uint16_t BTABLE; // 50: Buffer Table address register -} USB_TypeDef; - -TU_VERIFY_STATIC(sizeof(USB_TypeDef) == 0x54, "Size is not correct"); -TU_VERIFY_STATIC(offsetof(USB_TypeDef, CNTR) == 0x40, "Wrong offset"); - -#define USB_BASE (APB1PERIPH_BASE + 0x00005C00UL) /*!< USB_IP Peripheral Registers base address */ -#define USB_PMAADDR (APB1PERIPH_BASE + 0x00006000UL) /*!< USB_IP Packet Memory Area base address */ -#define USB ((USB_TypeDef *)USB_BASE) - -/******************************************************************************/ -/* */ -/* USB Device General registers */ -/* */ -/******************************************************************************/ -#define USB_CNTR (USB_BASE + 0x40U) /*!< Control register */ -#define USB_ISTR (USB_BASE + 0x44U) /*!< Interrupt status register */ -#define USB_FNR (USB_BASE + 0x48U) /*!< Frame number register */ -#define USB_DADDR (USB_BASE + 0x4CU) /*!< Device address register */ -#define USB_BTABLE (USB_BASE + 0x50U) /*!< Buffer Table address register */ +#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL) +#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL) /**************************** ISTR interrupt events *************************/ #define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */ diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h deleted file mode 100644 index e8a6af8cb..000000000 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright(c) 2016 STMicroelectronics - * Copyright(c) N Conrad - * Copyright (c) 2024, hathach (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. - * - */ - -#ifndef TUSB_FSDEV_COMMON_H -#define TUSB_FSDEV_COMMON_H - -#ifdef __cplusplus - extern "C" { -#endif - -#include "stdint.h" - -// FSDEV_PMA_SIZE is PMA buffer size in bytes. -// On 512-byte devices, access with a stride of two words (use every other 16-bit address) -// On 1024-byte devices, access with a stride of one word (use every 16-bit address) - -// For purposes of accessing the packet -#if ((FSDEV_PMA_SIZE) == 512u) - #define FSDEV_PMA_STRIDE (2u) -#elif ((FSDEV_PMA_SIZE) == 1024u) - #define FSDEV_PMA_STRIDE (1u) -#endif - -// The fsdev_bus_t type can be used for both register and PMA access necessities -// For type-safety create a new macro for the volatile address of PMAADDR -// The compiler should warn us if we cast it to a non-volatile type? -#ifdef FSDEV_BUS_32BIT -typedef uint32_t fsdev_bus_t; -static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR; - -#else -typedef uint16_t fsdev_bus_t; -// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) -static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR; - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { - size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; - total_word_offset *= FSDEV_PMA_STRIDE; - return &(pma[total_word_offset]); -} - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); -} - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); -} -#endif - -/* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) { - /* The STM32 full speed USB peripheral supports only a limited set of - * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ - uint16_t blocksize = (size > 62) ? 32 : 2; - - // Round up while dividing requested size by blocksize - uint16_t numblocks = (size + blocksize - 1) / blocksize ; - - return numblocks * blocksize; -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - volatile uint32_t *reg = (volatile uint32_t *)(USB_DRD_BASE + bEpIdx*4); - *reg = wRegValue; -#else - volatile uint16_t *reg = (volatile uint16_t *)((&USBx->EP0R) + bEpIdx*2u); - *reg = (uint16_t)wRegValue; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - volatile const uint32_t *reg = (volatile const uint32_t *)(USB_DRD_BASE + bEpIdx*4); -#else - volatile const uint16_t *reg = (volatile const uint16_t *)((&USBx->EP0R) + bEpIdx*2u); -#endif - return *reg; -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= (uint32_t)USB_EP_T_MASK; - regVal |= wType; - regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EP_T_FIELD; - return regVal; -} - -/** - * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal &= ~USB_EP_CTR_RX; - regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal &= ~USB_EP_CTR_TX; - regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) - pcd_set_endpoint(USBx, bEpIdx,regVal); -} - -/** - * @brief gets counter of the tx buffer. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval Counter value - */ -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; -#else - volatile const uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); - return *regPtr & 0x3ffU; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; -#else - volatile const uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); - return *regPtr & 0x3ffU; -#endif -} - -#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt -#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt - -/** - * @brief Sets address in an endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param bAddr Address. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= bAddr; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx,regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return pma32[2*bEpIdx] & 0x0000FFFFu ; -#else - return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return pma32[2*bEpIdx + 1] & 0x0000FFFFu; -#else - return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); -#endif -} - -#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address -#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); -#else - *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); -#else - *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr; -#endif -} - -#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address -#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); -#else - volatile uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); - *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); -#endif -} - -#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); -#else - volatile uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); - *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, - uint32_t blocksize, uint32_t numblocks) { - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); -#else - volatile uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); - *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) { - wCount = pcd_aligned_buffer_size(wCount); - - /* We assume that the buffer size is already aligned to hardware requirements. */ - uint16_t blocksize = (wCount > 62) ? 1 : 0; - uint16_t numblocks = wCount / (blocksize ? 32 : 2); - - /* There should be no remainder in the above calculation */ - TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); - - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount); -} - -#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt - -/** - * @brief sets the status for tx transfer (bits STAT_TX[1:0]). - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param wState new state - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPTX_DTOGMASK; - regVal ^= wState; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -/** - * @brief sets the status for rx transfer (bits STAT_TX[1:0]) - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param wState new state - * @retval None - */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPRX_DTOGMASK; - regVal ^= wState; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - return (regVal & USB_EPRX_STAT) >> (12u); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_RX) != 0) { - pcd_rx_dtog(USBx,bEpIdx); - } -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_TX) != 0) { - pcd_tx_dtog(USBx,bEpIdx); - } -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal |= USB_EP_KIND; - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPKIND_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index a8f61a35f..99fe8d55f 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -35,6 +35,7 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" #define FSDEV_PMA_SIZE (1024u) + #define FSDEV_REG_BASE USB_BASE // F0x2 models are crystal-less // All have internal D+ pull-up // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support @@ -81,12 +82,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32G0 #include "stm32g0xx.h" - #define FSDEV_BUS_32BIT #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -99,7 +97,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -109,17 +106,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32H5 #include "stm32h5xx.h" - #define FSDEV_BUS_32BIT - - #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) - #define USB_DRD_BASE USB_DRD_FS_BASE - #endif - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -132,7 +121,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -143,9 +131,8 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32WB #include "stm32wbxx.h" #define FSDEV_PMA_SIZE (1024u) - /* ST provided header has incorrect value */ - #undef USB_PMAADDR - #define USB_PMAADDR USB1_PMAADDR + /* ST provided header has incorrect value of USB_PMAADDR */ + #define FSDEV_PMA_BASE USB1_PMAADDR #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" @@ -161,13 +148,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 #include "stm32u5xx.h" - #define FSDEV_BUS_32BIT - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -180,7 +163,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -193,6 +175,31 @@ // This includes U0 #endif +//--------------------------------------------------------------------+ +// Register and PMA Base Address +//--------------------------------------------------------------------+ +#ifndef FSDEV_REG_BASE +#if defined(USB_BASE) + #define FSDEV_REG_BASE USB_BASE +#elif defined(USB_DRD_BASE) + #define FSDEV_REG_BASE USB_DRD_BASE +#elif defined(USB_DRD_FS_BASE) + #define FSDEV_REG_BASE USB_DRD_FS_BASE +#else + #error "FSDEV_REG_BASE not defined" +#endif +#endif + +#ifndef FSDEV_PMA_BASE +#if defined(USB_PMAADDR) + #define FSDEV_PMA_BASE USB_PMAADDR +#elif defined(USB_DRD_PMAADDR) + #define FSDEV_PMA_BASE USB_DRD_PMAADDR +#else + #error "FSDEV_PMA_BASE not defined" +#endif +#endif + // This checks if the device has "LPM" #if defined(USB_ISTR_L1REQ) #define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_type.h new file mode 100644 index 000000000..cf36576bb --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_type.h @@ -0,0 +1,307 @@ +/* + * The MIT License (MIT) + * + * Copyright(c) N Conrad + * Copyright(c) 2024, hathach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_FSDEV_TYPE_H +#define TUSB_FSDEV_TYPE_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" + +// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it +// Both of these MUST be a multiple of 2, and are in byte units. +#ifndef FSDEV_BTABLE_BASE +#define FSDEV_BTABLE_BASE 0U +#endif + +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes"); + +// FSDEV_PMA_SIZE is PMA buffer size in bytes. +// - 512-byte devices, access with a stride of two words (use every other 16-bit address) +// - 1024-byte devices, access with a stride of one word (use every 16-bit address) +// - 2048-byte devices, access with 32-bit address + +// For purposes of accessing the packet +#if FSDEV_PMA_SIZE == 512 + // 1x16 bit / word access scheme + #define FSDEV_PMA_STRIDE 2 + #define pma_access_scheme TU_ATTR_ALIGNED(4) +#elif FSDEV_PMA_SIZE == 1024 + // 2x16 bit / word access scheme + #define FSDEV_PMA_STRIDE 1 + #define pma_access_scheme +#elif FSDEV_PMA_SIZE == 2048 + // 32 bit access scheme + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_STRIDE 1 + #define pma_access_scheme +#endif + +// The fsdev_bus_t type can be used for both register and PMA access necessities +#ifdef FSDEV_BUS_32BIT + typedef uint32_t fsdev_bus_t; + #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr) + #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value) +#else + typedef uint16_t fsdev_bus_t; + #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr) + #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value) +#endif + +enum { + FSDEV_BUS_SIZE = sizeof(fsdev_bus_t), +}; + +//--------------------------------------------------------------------+ +// BTable Typedef +//--------------------------------------------------------------------+ +enum { + BTABLE_BUF_TX = 0, + BTABLE_BUF_RX = 1 +}; + +// hardware limit endpoint +#define FSDEV_EP_COUNT 8 + +// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either +// 16-bit or 32-bit depending on FSDEV_BUS_32BIT. +// 0: TX (IN), 1: RX (OUT) +typedef union { + // data is strictly 16-bit access (address could be 32-bit aligned) + struct { + volatile pma_access_scheme uint16_t addr; + volatile pma_access_scheme uint16_t count; + } ep16[FSDEV_EP_COUNT][2]; + + // strictly 32-bit access + struct { + volatile uint32_t count_addr; + } ep32[FSDEV_EP_COUNT][2]; +} fsdev_btable_t; + +TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct"); +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); + +#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE))) + +typedef struct { + volatile pma_access_scheme fsdev_bus_t value; +} fsdev_pma_buf_t; + +#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr))) + +//--------------------------------------------------------------------+ +// Registers Typedef +//--------------------------------------------------------------------+ + +// volatile 32-bit aligned +#define _va32 volatile TU_ATTR_ALIGNED(4) + +typedef struct { + struct { + _va32 fsdev_bus_t reg; + }ep[FSDEV_EP_COUNT]; + + _va32 uint32_t RESERVED7[8]; // Reserved + _va32 fsdev_bus_t CNTR; // 40: Control register + _va32 fsdev_bus_t ISTR; // 44: Interrupt status register + _va32 fsdev_bus_t FNR; // 48: Frame number register + _va32 fsdev_bus_t DADDR; // 4C: Device address register + _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) + _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) + _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) +} fsdev_regs_t; + +TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset"); +TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct"); + +#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE) + + +#ifndef USB_EPTX_STAT +#define USB_EPTX_STAT 0x0030U +#endif + +#ifndef USB_EPRX_STAT +#define USB_EPRX_STAT 0x3000U +#endif + +#ifndef USB_EPTX_STAT_Pos +#define USB_EPTX_STAT_Pos 4u +#endif + +#ifndef USB_EP_DTOG_TX_Pos +#define USB_EP_DTOG_TX_Pos 6u +#endif + +#ifndef USB_EP_CTR_TX_Pos +#define USB_EP_CTR_TX_Pos 7u +#endif + +typedef enum { + EP_STAT_DISABLED = 0, + EP_STAT_STALL = 1, + EP_STAT_NAK = 2, + EP_STAT_VALID = 3 +}ep_stat_t; + +#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) + +//--------------------------------------------------------------------+ +// Endpoint Helper +// - CTR is write 0 to clear +// - DTOG and STAT are write 1 to toggle +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { + return FSDEV_REG->ep[ep_id].reg; +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value, bool need_exclusive) { + if (need_exclusive) { + dcd_int_disable(0); + } + + FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; + + if (need_exclusive) { + dcd_int_enable(0); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb_dir_t dir) { + uint32_t reg = FSDEV_REG->ep[ep_id].reg; + reg |= USB_EP_CTR_TX | USB_EP_CTR_RX; + reg &= USB_EPREG_MASK; + reg &= ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); + ep_write(ep_id, reg, false); +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) { + *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) { + *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) { + return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; +} + +//--------------------------------------------------------------------+ +// BTable Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) { +#ifdef FSDEV_BUS_32BIT + return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu; +#else + return FSDEV_BTABLE->ep16[ep_id][buf_id].addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, uint8_t buf_id) { + uint16_t count; +#ifdef FSDEV_BUS_32BIT + count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16); +#else + count = FSDEV_BTABLE->ep16[ep_id][buf_id].count; +#endif + return count & 0x3FFU; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; + cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); + FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt; +#endif +} + +/* Aligned buffer size according to hardware */ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t block_in_bytes; + if (size > 62) { + block_in_bytes = 32; + *blsize = 1; + *num_block = tu_div_ceil(size, 32); + } else { + block_in_bytes = 2; + *blsize = 0; + *num_block = tu_div_ceil(size, 2); + } + + return (*num_block) * block_in_bytes; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { + uint8_t blsize, num_block; + (void) pma_align_buffer_size(wCount, &blsize, &num_block); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); + if (bl_nb == 0) { + // zlp but 0 is invalid value, set blsize to 1 (32 bytes) + // Note: lower value can cause PMAOVR on setup with ch32v203 + bl_nb = 1 << 15; + } + +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; +#endif + +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 2871927be..12466e5ba 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -43,7 +43,7 @@ #if defined(TUP_USBIP_DWC2_STM32) #include "dwc2_stm32.h" -#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) +#elif defined(TUP_USBIP_DWC2_ESP32) #include "dwc2_esp32.h" #elif TU_CHECK_MCU(OPT_MCU_GD32VF103) #include "dwc2_gd32.h" @@ -732,12 +732,34 @@ void dcd_remote_wakeup(uint8_t rhport) { void dcd_connect(uint8_t rhport) { (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + +#ifdef TUP_USBIP_DWC2_ESP32 + usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; + conf.pad_pull_override = 0; + conf.dp_pullup = 0; + conf.dp_pulldown = 0; + conf.dm_pullup = 0; + conf.dm_pulldown = 0; + USB_WRAP.otg_conf = conf; +#endif + dwc2->dctl &= ~DCTL_SDIS; } void dcd_disconnect(uint8_t rhport) { (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + +#ifdef TUP_USBIP_DWC2_ESP32 + usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; + conf.pad_pull_override = 1; + conf.dp_pullup = 0; + conf.dp_pulldown = 1; + conf.dm_pullup = 0; + conf.dm_pulldown = 1; + USB_WRAP.otg_conf = conf; +#endif + dwc2->dctl |= DCTL_SDIS; } @@ -1299,25 +1321,13 @@ void dcd_int_handler(uint8_t rhport) { // } } -#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE - -bool dcd_check_test_mode_support(test_mode_t test_selector) { - // Check if test mode selector is unsupported - if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) { - return false; - } - - return true; -} - -void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) { - // Get port address... +#if CFG_TUD_TEST_MODE +void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Enable the test mode - dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos); + dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos); } - -#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */ +#endif #endif diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index 74b10aa9a..921cee29e 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -32,61 +32,53 @@ extern "C" { #endif +#include "freertos/task.h" + #include "esp_intr_alloc.h" #include "soc/periph_defs.h" -//#include "soc/usb_periph.h" -#include "freertos/task.h" +#include "soc/usb_wrap_struct.h" #define DWC2_REG_BASE 0x60080000UL #define DWC2_EP_MAX 7 #define DWC2_EP_IN_MAX 5 -static const dwc2_controller_t _dwc2_controller[] = -{ +static const dwc2_controller_t _dwc2_controller[] = { { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_in_count = DWC2_EP_IN_MAX, .ep_fifo_size = 1024 } }; static intr_handle_t usb_ih; -static void dcd_int_handler_wrap(void* arg) -{ - (void) arg; +static void dcd_int_handler_wrap(void* arg) { + (void)arg; dcd_int_handler(0); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_enable (uint8_t rhport) -{ - (void) rhport; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { + (void)rhport; esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_disable (uint8_t rhport) -{ - (void) rhport; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) { + (void)rhport; esp_intr_free(usb_ih); } -static inline void dwc2_remote_wakeup_delay(void) -{ +TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { vTaskDelay(pdMS_TO_TICKS(1)); } // MCU specific PHY init, called BEFORE core reset -static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - (void) dwc2; - (void) hs_phy_type; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + (void)dwc2; + (void)hs_phy_type; // nothing to do } // MCU specific PHY update, it is called AFTER init() and core reset -static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - (void) dwc2; - (void) hs_phy_type; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + (void)dwc2; + (void)hs_phy_type; // nothing to do } @@ -95,4 +87,4 @@ static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) } #endif -#endif /* _DWC2_ESP32_H_ */ +#endif diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 12d610bd6..25ee507c1 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -102,6 +102,22 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return false; } +// Allocate packet buffer used by ISO endpoints +// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +// Configure and enable an ISO endpoint according to descriptor +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 8005f5f7b..6b60bc657 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -332,6 +332,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index 58628a8bb..8f40e3349 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -436,6 +436,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/tusb.c b/src/tusb.c index 0092267a1..860e8ac35 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -398,7 +398,7 @@ static void dump_str_line(uint8_t const* buf, uint16_t count) { tu_printf(" |"); // each line is 16 bytes for (uint16_t i = 0; i < count; i++) { - const char ch = buf[i]; + int ch = buf[i]; tu_printf("%c", isprint(ch) ? ch : '.'); } tu_printf("|\r\n"); diff --git a/src/tusb_option.h b/src/tusb_option.h index 8990cf92b..fb0209023 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -188,6 +188,12 @@ #define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series #define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series +// Analog Devices +#define OPT_MCU_MAX32690 2400 ///< ADI MAX32690 +#define OPT_MCU_MAX32666 2401 ///< ADI MAX32666/5 +#define OPT_MCU_MAX32650 2402 ///< ADI MAX32650/1/2 +#define OPT_MCU_MAX78002 2403 ///< ADI MAX78002 + // Check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input #define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) @@ -381,7 +387,7 @@ #error "CFG_TUD_ENDPPOINT_MAX must be less than or equal to TUP_DCD_ENDPOINT_MAX" #endif -// USB 2.0 compliance test mode support +// USB 2.0 7.1.20: compliance test mode support #ifndef CFG_TUD_TEST_MODE #define CFG_TUD_TEST_MODE 0 #endif diff --git a/src/typec/tcd.h b/src/typec/tcd.h index 86499c951..bcbdab8ed 100644 --- a/src/typec/tcd.h +++ b/src/typec/tcd.h @@ -63,7 +63,7 @@ typedef struct TU_ATTR_PACKED { } xfer_complete; }; -} tcd_event_t;; +} tcd_event_t; //--------------------------------------------------------------------+ // diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index c2699cc6f..52ec5ae1d 100644 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -27,24 +27,21 @@ import argparse import os +import re import sys import time import serial import subprocess import json import glob -import platform +from multiprocessing import Pool +import fs -# for RPI double reset -if platform.machine() == 'aarch64': - try: - import gpiozero - except ImportError: - pass - - -ENUM_TIMEOUT = 10 +ENUM_TIMEOUT = 30 +STATUS_OK = "\033[32mOK\033[0m" +STATUS_FAILED = "\033[31mFailed\033[0m" +STATUS_SKIPPED = "\033[33mSkipped\033[0m" # get usb serial by id def get_serial_dev(id, vendor_str, product_str, ifnum): @@ -60,9 +57,8 @@ def get_serial_dev(id, vendor_str, product_str, ifnum): return port_list[0] -# Currently not used, left as reference +# get usb disk by id def get_disk_dev(id, vendor_str, lun): - # get usb disk by id return f'/dev/disk/by-id/usb-{vendor_str}_Mass_Storage_{id}-0:{lun}' @@ -79,34 +75,35 @@ def open_serial_dev(port): # slight delay since kernel may occupy the port briefly time.sleep(0.5) timeout = timeout - 0.5 - ser = serial.Serial(port, timeout=1) + ser = serial.Serial(port, timeout=5) break except serial.SerialException: pass time.sleep(0.5) timeout = timeout - 0.5 - assert timeout, 'Device not available or Cannot open port' + + assert timeout, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed' return ser -def read_disk_file(id, fname): - # on different self-hosted, the mount point is different - file_list = [ - f'/media/blkUSB_{id[-8:]}.02/{fname}', - f'/media/{os.getenv("USER")}/TinyUSB MSC/{fname}' - ] +def read_disk_file(uid, lun, fname): + # open_fs("fat://{dev}) require 'pip install pyfatfs' + dev = get_disk_dev(uid, 'TinyUSB', lun) timeout = ENUM_TIMEOUT while timeout: - for file in file_list: - if os.path.isfile(file): - with open(file, 'rb') as f: + if os.path.exists(dev): + fat = fs.open_fs(f'fat://{dev}?read_only=true') + try: + with fat.open(fname, 'rb') as f: data = f.read() - return data - + finally: + fat.close() + assert data, f'Cannot read file {fname} from {dev}' + return data time.sleep(1) - timeout = timeout - 1 + timeout -= 1 - assert timeout, 'Device not available' + assert timeout, f'Storage {dev} not existed' return None @@ -114,11 +111,11 @@ def read_disk_file(id, fname): # Flashing firmware # ------------------------------------------------------------- def run_cmd(cmd): - # print(cmd) + #print(cmd) r = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - title = 'command error' if r.returncode != 0: - # print build output if failed + title = f'COMMAND FAILED: {cmd}' + print() if os.getenv('CI'): print(f"::group::{title}") print(r.stdout.decode("utf-8")) @@ -131,10 +128,21 @@ def run_cmd(cmd): def flash_jlink(board, firmware): script = ['halt', 'r', f'loadfile {firmware}.elf', 'r', 'go', 'exit'] - with open('flash.jlink', 'w') as f: + f_jlink = f'{board["name"]}_{os.path.basename(firmware)}.jlink' + with open(f_jlink, 'w') as f: f.writelines(f'{s}\n' for s in script) - ret = run_cmd(f'JLinkExe -USB {board["flasher_sn"]} {board["flasher_args"]} -if swd -JTAGConf -1,-1 -speed auto -NoGui 1 -ExitOnError 1 -CommandFile flash.jlink') - os.remove('flash.jlink') + ret = run_cmd(f'JLinkExe -USB {board["flasher_sn"]} {board["flasher_args"]} -if swd -JTAGConf -1,-1 -speed auto -NoGui 1 -ExitOnError 1 -CommandFile {f_jlink}') + os.remove(f_jlink) + return ret + + +def flash_stlink(board, firmware): + ret = run_cmd(f'STM32_Programmer_CLI --connect port=swd sn={board["flasher_sn"]} --write {firmware}.elf --go') + return ret + + +def flash_stflash(board, firmware): + ret = run_cmd(f'st-flash --serial {board["flasher_sn"]} write {firmware}.bin 0x8000000') return ret @@ -143,6 +151,52 @@ def flash_openocd(board, firmware): return ret +def flash_openocd_wch(board, firmware): + # Content of the wch-riscv.cfg file + cfg_content = """ +adapter driver wlinke +adapter speed 6000 +transport select sdi + +wlink_set_address 0x00000000 +set _CHIPNAME wch_riscv +sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash + +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 + +echo "Ready for Remote Connections" +""" + f_wch = f"wch-riscv_{board['uid']}.cfg" + if not os.path.exists(f_wch): + with open(f_wch, 'w') as file: + file.write(cfg_content) + + ret = run_cmd(f'openocd_wch -c "adapter serial {board["flasher_sn"]}" -f {f_wch} ' + f'-c "program {firmware}.elf reset exit"') + return ret + + +def flash_openocd_adi(board, firmware): + openocd_adi_script_path = f'{os.getenv("HOME")}/app/openocd_adi/tcl' + if not os.path.exists(openocd_adi_script_path): + openocd_adi_script_path = '/home/pi/openocd_adi/tcl' + + ret = run_cmd(f'openocd_adi -c "adapter serial {board["flasher_sn"]}" -s {openocd_adi_script_path} ' + f'{board["flasher_args"]} -c "program {firmware}.elf reset exit"') + return ret + +def flash_wlink_rs(board, firmware): + # wlink use index for probe selection and lacking usb serial support + ret = run_cmd(f'wlink flash {firmware}.elf') + return ret + + def flash_esptool(board, firmware): port = get_serial_dev(board["flasher_sn"], None, None, 0) dir = os.path.dirname(f'{firmware}.bin') @@ -156,49 +210,48 @@ def flash_esptool(board, firmware): return ret -def doublereset_with_rpi_gpio(board): - # Off = 0 = Reset - led = gpiozero.LED(board["flasher_reset_pin"]) - - led.off() - time.sleep(0.1) - led.on() - time.sleep(0.1) - led.off() - time.sleep(0.1) - led.on() - - -def flash_bossac(board, firmware): - # double reset to enter bootloader - if platform.machine() == 'aarch64': - doublereset_with_rpi_gpio(board) - - port = get_serial_dev(board["uid"], board["flashser_vendor"], board["flasher_product"], 0) - timeout = ENUM_TIMEOUT - while timeout: - if os.path.exists(port): - break - else: - time.sleep(0.5) - timeout = timeout - 0.5 - assert timeout, 'bossac bootloader is not available' - # sleep a bit more for bootloader to be ready - time.sleep(0.5) - ret = run_cmd(f'bossac --port {port} {board["flasher_args"]} -U -i -R -e -w {firmware}.bin') +def flash_uniflash(board, firmware): + ret = run_cmd(f'dslite.sh {board["flasher_args"]} -f {firmware}.hex') return ret + # ------------------------------------------------------------- -# Tests +# Tests: dual # ------------------------------------------------------------- -def test_board_test(id): + +def test_dual_host_info_to_device_cdc(board): + uid = board['uid'] + declared_devs = [f'{d["vid_pid"]}_{d["serial"]}' for d in board['tests']['dual_attached']] + + port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0) + ser = open_serial_dev(port) + # read from cdc, first line should contain vid/pid and serial + data = ser.read(1000) + lines = data.decode('utf-8').splitlines() + enum_dev_sn = [] + for l in lines: + vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l) + if vid_pid_sn: + print(f'\r\n {l} ', end='') + enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}') + + assert(set(declared_devs) == set(enum_dev_sn)), \ + f'Enumerated devices {enum_dev_sn} not match with declared {declared_devs}' + return 0 + + +# ------------------------------------------------------------- +# Tests: device +# ------------------------------------------------------------- +def test_device_board_test(board): # Dummy test pass -def test_cdc_dual_ports(id): - port1 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0) - port2 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 2) +def test_device_cdc_dual_ports(board): + uid = board['uid'] + port1 = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0) + port2 = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 2) ser1 = open_serial_dev(port1) ser2 = open_serial_dev(port2) @@ -217,9 +270,10 @@ def test_cdc_dual_ports(id): assert ser2.read(100) == str2.upper(), 'Port2 wrong data' -def test_cdc_msc(id): +def test_device_cdc_msc(board): + uid = board['uid'] # Echo test - port = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0) + port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0) ser = open_serial_dev(port) str = b"test_str" @@ -228,7 +282,7 @@ def test_cdc_msc(id): assert ser.read(100) == str, 'CDC wrong data' # Block test - data = read_disk_file(id, 'README.TXT') + data = read_disk_file(uid,0,'README.TXT') readme = \ b"This is tinyusb's MassStorage Class demo.\r\n\r\n\ If you find any bugs or get any questions, feel free to file an\r\n\ @@ -237,57 +291,62 @@ issue at github.com/hathach/tinyusb" assert data == readme, 'MSC wrong data' -def test_cdc_msc_freertos(id): - test_cdc_msc(id) +def test_device_cdc_msc_freertos(board): + test_device_cdc_msc(board) -def test_dfu(id): +def test_device_dfu(board): + uid = board['uid'] + # Wait device enum timeout = ENUM_TIMEOUT while timeout: ret = subprocess.run(f'dfu-util -l', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout = ret.stdout.decode() - if f'serial="{id}"' in stdout and 'Found DFU: [cafe:4000]' in stdout: + if f'serial="{uid}"' in stdout and 'Found DFU: [cafe:4000]' in stdout: break time.sleep(1) timeout = timeout - 1 assert timeout, 'Device not available' + f_dfu0 = f'dfu0_{uid}' + f_dfu1 = f'dfu1_{uid}' + # Test upload try: - os.remove('dfu0') - os.remove('dfu1') + os.remove(f_dfu0) + os.remove(f_dfu1) except OSError: pass - ret = subprocess.run(f'dfu-util -S {id} -a 0 -U dfu0', - shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ret = run_cmd(f'dfu-util -S {uid} -a 0 -U {f_dfu0}') assert ret.returncode == 0, 'Upload failed' - ret = subprocess.run(f'dfu-util -S {id} -a 1 -U dfu1', - shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ret = run_cmd(f'dfu-util -S {uid} -a 1 -U {f_dfu1}') assert ret.returncode == 0, 'Upload failed' - with open('dfu0') as f: + with open(f_dfu0) as f: assert 'Hello world from TinyUSB DFU! - Partition 0' in f.read(), 'Wrong uploaded data' - with open('dfu1') as f: + with open(f_dfu1) as f: assert 'Hello world from TinyUSB DFU! - Partition 1' in f.read(), 'Wrong uploaded data' - os.remove('dfu0') - os.remove('dfu1') + os.remove(f_dfu0) + os.remove(f_dfu1) -def test_dfu_runtime(id): +def test_device_dfu_runtime(board): + uid = board['uid'] + # Wait device enum timeout = ENUM_TIMEOUT while timeout: ret = subprocess.run(f'dfu-util -l', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout = ret.stdout.decode() - if f'serial="{id}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout: + if f'serial="{uid}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout: break time.sleep(1) timeout = timeout - 1 @@ -295,10 +354,11 @@ def test_dfu_runtime(id): assert timeout, 'Device not available' -def test_hid_boot_interface(id): - kbd = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'event-kbd') - mouse1 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse') - mouse2 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse') +def test_device_hid_boot_interface(board): + uid = board['uid'] + kbd = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'event-kbd') + mouse1 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse') + mouse2 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse') # Wait device enum timeout = ENUM_TIMEOUT while timeout: @@ -307,10 +367,10 @@ def test_hid_boot_interface(id): time.sleep(1) timeout = timeout - 1 - assert timeout, 'Device not available' + assert timeout, 'HID device not available' -def test_hid_composite_freertos(id): +def test_device_hid_composite_freertos(id): # TODO implement later pass @@ -318,6 +378,71 @@ def test_hid_composite_freertos(id): # ------------------------------------------------------------- # Main # ------------------------------------------------------------- +# all possible tests: board_test is added last to disable board's usb +all_tests = [ + 'device/cdc_dual_ports', + 'device/cdc_msc', + 'device/dfu', + 'device/cdc_msc_freertos', # don't test 2 cdc_msc next to each other + 'device/dfu_runtime', + 'device/hid_boot_interface', + + 'dual/host_info_to_device_cdc', + 'device/board_test' +] + + +def test_board(board): + name = board['name'] + flasher = board['flasher'].lower() + + # default to all tests + test_list = list(all_tests) + + if 'tests' in board: + board_tests = board['tests'] + if 'only' in board_tests: + test_list = board_tests['only'] + ['device/board_test'] + if 'skip' in board_tests: + for skip in board_tests['skip']: + if skip in test_list: + test_list.remove(skip) + + err_count = 0 + for test in test_list: + fw_dir = f'cmake-build/cmake-build-{name}/{test}' + if not os.path.exists(fw_dir): + fw_dir = f'examples/cmake-build-{name}/{test}' + fw_name = f'{fw_dir}/{os.path.basename(test)}' + print(f'{name:25} {test:30} ... ', end='') + + if not os.path.exists(fw_dir): + print('Skip') + continue + + # flash firmware. It may fail randomly, retry a few times + for i in range(3): + ret = globals()[f'flash_{flasher}'](board, fw_name) + if ret.returncode == 0: + break + else: + print(f'Flashing failed, retry {i+1}') + time.sleep(1) + + if ret.returncode == 0: + try: + ret = globals()[f'test_{test.replace("/", "_")}'](board) + print('OK') + except Exception as e: + err_count += 1 + print(STATUS_FAILED) + print(f' {e}') + else: + err_count += 1 + print(f'Flash {STATUS_FAILED}') + return err_count + + def main(): """ Hardware test on specified boards @@ -330,59 +455,25 @@ def main(): config_file = args.config_file boards = args.board - config_file = os.path.join(os.path.dirname(__file__), config_file) + # if config file is not found, try to find it in the same directory as this script + if not os.path.exists(config_file): + config_file = os.path.join(os.path.dirname(__file__), config_file) with open(config_file) as f: config = json.load(f) - # all possible tests - all_tests = [ - 'cdc_dual_ports', 'cdc_msc', 'dfu', 'dfu_runtime', 'hid_boot_interface', - ] - if len(boards) == 0: config_boards = config['boards'] else: config_boards = [e for e in config['boards'] if e['name'] in boards] - for item in config_boards: - name = item['name'] - print(f'Testing board:{name}') - flasher = item['flasher'].lower() + with Pool(processes=os.cpu_count()) as pool: + err_count = sum(pool.map(test_board, config_boards)) - # default to all tests - if 'tests' in item: - test_list = item['tests'] - else: - test_list = all_tests - - # board_test is added last to disable board's usb - test_list.append('board_test') - - # remove skip_tests - if 'tests_skip' in item: - for skip in item['tests_skip']: - if skip in test_list: - test_list.remove(skip) - - for test in test_list: - fw_name = f'cmake-build/cmake-build-{name}/device/{test}/{test}' - print(f' {test} ...', end='') - - # flash firmware. It may fail randomly, retry a few times - for i in range(3): - ret = globals()[f'flash_{flasher}'](item, fw_name) - if ret.returncode == 0: - break - else: - print(f'Flashing failed, retry {i+1}') - time.sleep(1) - - assert ret.returncode == 0, 'Flash failed\n' + ret.stdout.decode() - - # run test - globals()[f'test_{test}'](item['uid']) - - print('OK') + print() + print("-" * 30) + print(f'Total failed: {err_count}') + print("-" * 30) + sys.exit(err_count) if __name__ == '__main__': diff --git a/test/hil/pi4.json b/test/hil/pi4.json deleted file mode 100644 index bdb8a5fa5..000000000 --- a/test/hil/pi4.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "boards": [ - { - "name": "raspberry_pi_pico", - "uid": "E6614C311B764A37", - "flasher": "openocd", - "flasher_sn": "E6614103E72C1D2F", - "flasher_args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"" - }, - { - "name": "feather_nrf52840_express", - "uid": "1F0479CD0F764471", - "flasher": "jlink", - "flasher_sn": "000682804350", - "flasher_args": "-device nrf52840_xxaa" - }, - { - "name": "itsybitsy_m4", - "uid": "D784B28C5338533335202020FF044726", - "flasher": "bossac", - "flashser_vendor": "Adafruit Industries", - "flasher_product": "ItsyBitsy M4 Express", - "flasher_reset_pin": "2", - "flasher_args": "--offset 0x4000" - }, - { - "name": "espressif_s3_devkitm", - "uid": "84F703C084E4", - "tests": [ - "cdc_msc_freertos", "hid_composite_freertos" - ], - "flasher": "esptool", - "flasher_sn": "3ea619acd1cdeb11a0a0b806e93fd3f1", - "flasher_args": "-b 1500000" - } - ] -} diff --git a/test/hil/rpi.json b/test/hil/rpi.json new file mode 100644 index 000000000..36376a873 --- /dev/null +++ b/test/hil/rpi.json @@ -0,0 +1,96 @@ +{ + "boards": [ + { + "name": "feather_nrf52840_express", + "uid": "1F0479CD0F764471", + "flasher": "jlink", + "flasher_sn": "000682804350", + "flasher_args": "-device nrf52840_xxaa" + }, + { + "name": "metro_m4_express", + "uid": "9995AD485337433231202020FF100A34", + "flasher": "jlink", + "flasher_sn": "123456", + "flasher_args": "-device ATSAMD51J19", + "tests": { + "dual_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}] + } + }, + { + "name": "max32666fthr", + "uid": "0C81464124010B20FF0A08CC2C", + "flasher": "openocd_adi", + "flasher_sn": "E6614C311B597D32", + "flasher_args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg" + }, + { + "name": "lpcxpresso11u37", + "uid": "17121919", + "flasher": "jlink", + "flasher_sn": "000724441579", + "flasher_args": "-device LPC11U37/401" + }, + { + "name": "ra4m1_ek", + "uid": "152E163038303131393346E46F26574B", + "tests": { + "skip": ["device/cdc_msc", "device/cdc_msc_freertos"] + }, + "comment": "MSC is slow to enumerated #2602", + "flasher": "jlink", + "flasher_sn": "000831174392", + "flasher_args": "-device R7FA4M1AB" + }, + { + "name": "raspberry_pi_pico", + "uid": "E6614C311B764A37", + "flasher": "openocd", + "flasher_sn": "E6614103E72C1D2F", + "flasher_args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"", + "tests": { + "dual_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}] + } + }, + { + "name": "stm32f072disco", + "uid": "3A001A001357364230353532", + "flasher": "jlink", + "flasher_sn": "779541626", + "flasher_args": "-device stm32f072rb" + }, + { + "name": "stm32g0b1nucleo", + "uid": "4D0038000450434E37343120", + "flasher": "openocd", + "flasher_sn": "066FFF495087534867063844", + "flasher_args": "-f interface/stlink.cfg -f target/stm32g0x.cfg" + } + ], + "boards-skip": [ + { + "name": "mimxrt1015_evk", + "uid": "DC28F865D2111D228D00B0543A70463C", + "flasher": "jlink", + "flasher_sn": "000726284213", + "flasher_args": "-device MIMXRT1015DAF5A" + }, + { + "name": "nanoch32v203", + "uid": "CDAB277B0FBC03E339E339E3", + "flasher": "openocd_wch", + "flasher_sn": "EBCA8F0670AF", + "flasher_args": "" + }, + { + "name": "espressif_s3_devkitm", + "uid": "84F703C084E4", + "tests": { + "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"] + }, + "flasher": "esptool", + "flasher_sn": "3ea619acd1cdeb11a0a0b806e93fd3f1", + "flasher_args": "-b 921600" + } + ] +} diff --git a/test/unit-test/vendor/ceedling/vendor/unity/src/unity_internals.h b/test/unit-test/vendor/ceedling/vendor/unity/src/unity_internals.h index 2c91b6db1..d66309f96 100644 --- a/test/unit-test/vendor/ceedling/vendor/unity/src/unity_internals.h +++ b/test/unit-test/vendor/ceedling/vendor/unity/src/unity_internals.h @@ -632,14 +632,14 @@ void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, const UNITY_FLAGS_T flags); #ifndef UNITY_EXCLUDE_SETJMP_H -UNITY_NORETURN void UnityFail(const char* message, const UNITY_LINE_TYPE line); -UNITY_NORETURN void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +UNITY_NORETURN void UnityFail(const char* msg, const UNITY_LINE_TYPE line); +UNITY_NORETURN void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line); #else -void UnityFail(const char* message, const UNITY_LINE_TYPE line); -void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +void UnityFail(const char* msg, const UNITY_LINE_TYPE line); +void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line); #endif -void UnityMessage(const char* message, const UNITY_LINE_TYPE line); +void UnityMessage(const char* msg, const UNITY_LINE_TYPE line); #ifndef UNITY_EXCLUDE_FLOAT void UnityAssertFloatsWithin(const UNITY_FLOAT delta, diff --git a/tools/build.py b/tools/build.py index b937a7342..f9ae68231 100644 --- a/tools/build.py +++ b/tools/build.py @@ -9,19 +9,29 @@ from multiprocessing import Pool import build_utils -SUCCEEDED = "\033[32msucceeded\033[0m" -FAILED = "\033[31mfailed\033[0m" +STATUS_OK = "\033[32mOK\033[0m" +STATUS_FAILED = "\033[31mFailed\033[0m" +STATUS_SKIPPED = "\033[33mSkipped\033[0m" -build_separator = '-' * 106 +RET_OK = 0 +RET_FAILED = 1 +RET_SKIPPED = 2 + +build_format = '| {:30} | {:40} | {:16} | {:5} |' +build_separator = '-' * 95 +build_status = [STATUS_OK, STATUS_FAILED, STATUS_SKIPPED] +# ----------------------------- +# Helper +# ----------------------------- def run_cmd(cmd): #print(cmd) r = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - title = 'command error' + title = f'Command Error: {cmd}' if r.returncode != 0: # print build output if failed - if os.getenv('CI'): + if os.getenv('GITHUB_ACTIONS'): print(f"::group::{title}") print(r.stdout.decode("utf-8")) print(f"::endgroup::") @@ -30,6 +40,7 @@ def run_cmd(cmd): print(r.stdout.decode("utf-8")) return r + def find_family(board): bsp_dir = Path("hw/bsp") for family_dir in bsp_dir.iterdir(): @@ -56,70 +67,91 @@ def get_examples(family): return all_examples -def build_board_cmake(board, toolchain): - start_time = time.monotonic() - ret = [0, 0, 0] +def print_build_result(board, example, status, duration): + if isinstance(duration, (int, float)): + duration = "{:.2f}s".format(duration) + print(build_format.format(board, example, build_status[status], duration)) +# ----------------------------- +# CMake +# ----------------------------- +def cmake_board(board, toolchain): + ret = [0, 0, 0] + start_time = time.monotonic() build_dir = f"cmake-build/cmake-build-{board}" family = find_family(board) if family == 'espressif': # for espressif, we have to build example individually all_examples = get_examples(family) for example in all_examples: - r = run_cmd(f'cmake examples/{example} -B {build_dir}/{example} -G "Ninja" -DBOARD={board} -DMAX3421_HOST=1') - if r.returncode == 0: - r = run_cmd(f'cmake --build {build_dir}/{example}') - if r.returncode == 0: - ret[0] += 1 - else: - ret[1] += 1 + rcmd = run_cmd(f'cmake examples/{example} -B {build_dir}/{example} -G "Ninja" -DBOARD={board} -DMAX3421_HOST=1') + if rcmd.returncode == 0: + rcmd = run_cmd(f'cmake --build {build_dir}/{example}') + ret[0 if rcmd.returncode == 0 else 1] += 1 else: - r = run_cmd(f'cmake examples -B {build_dir} -G "Ninja" -DBOARD={board} -DCMAKE_BUILD_TYPE=MinSizeRel -DTOOLCHAIN={toolchain}') - if r.returncode == 0: - r = run_cmd(f"cmake --build {build_dir}") - if r.returncode == 0: - ret[0] += 1 - else: - ret[1] += 1 + rcmd = run_cmd(f'cmake examples -B {build_dir} -G "Ninja" -DBOARD={board} -DCMAKE_BUILD_TYPE=MinSizeRel -DTOOLCHAIN={toolchain}') + if rcmd.returncode == 0: + rcmd = run_cmd(f"cmake --build {build_dir}") + ret[0 if rcmd.returncode == 0 else 1] += 1 - duration = time.monotonic() - start_time - - if ret[1] == 0: - status = SUCCEEDED - else: - status = FAILED - - flash_size = "-" - sram_size = "-" example = 'all' - title = build_utils.build_format.format(example, board, status, "{:.2f}s".format(duration), flash_size, sram_size) - print(title) + print_build_result(board, example, 0 if ret[1] == 0 else 1, time.monotonic() - start_time) return ret -def build_board_make_all_examples(board, toolchain, all_examples): +# ----------------------------- +# Make +# ----------------------------- +def make_one_example(example, board, make_option): + # Check if board is skipped + if build_utils.skip_example(example, board): + print_build_result(board, example, 2, '-') + r = 2 + else: + start_time = time.monotonic() + # skip -j for circleci + if not os.getenv('CIRCLECI'): + make_option += ' -j' + make_cmd = f"make -C examples/{example} BOARD={board} {make_option}" + # run_cmd(f"{make_cmd} clean") + build_result = run_cmd(f"{make_cmd} all") + r = 0 if build_result.returncode == 0 else 1 + print_build_result(board, example, r, time.monotonic() - start_time) + + ret = [0, 0, 0] + ret[r] = 1 + return ret + + +def make_board(board, toolchain): + print(build_separator) + all_examples = get_examples(find_family(board)) start_time = time.monotonic() ret = [0, 0, 0] - with Pool(processes=os.cpu_count()) as pool: pool_args = list((map(lambda e, b=board, o=f"TOOLCHAIN={toolchain}": [e, b, o], all_examples))) - r = pool.starmap(build_utils.build_example, pool_args) + r = pool.starmap(make_one_example, pool_args) # sum all element of same index (column sum) - rsum = list(map(sum, list(zip(*r)))) - ret[0] += rsum[0] - ret[1] += rsum[1] - ret[2] += rsum[2] - duration = time.monotonic() - start_time - if ret[1] == 0: - status = SUCCEEDED - else: - status = FAILED - - flash_size = "-" - sram_size = "-" + ret = list(map(sum, list(zip(*r)))) example = 'all' - title = build_utils.build_format.format(example, board, status, "{:.2f}s".format(duration), flash_size, sram_size) - print(title) + print_build_result(board, example, 0 if ret[1] == 0 else 1, time.monotonic() - start_time) + return ret + + +# ----------------------------- +# Build Family +# ----------------------------- +def build_boards_list(boards, toolchain, build_system): + ret = [0, 0, 0] + for b in boards: + r = [0, 0, 0] + if build_system == 'cmake': + r = cmake_board(b, toolchain) + elif build_system == 'make': + r = make_board(b, toolchain) + ret[0] += r[0] + ret[1] += r[1] + ret[2] += r[2] return ret @@ -131,7 +163,6 @@ def build_family(family, toolchain, build_system, one_per_family, boards): all_boards.sort() ret = [0, 0, 0] - # If only-one flag is set, select one random board if one_per_family: for b in boards: @@ -140,21 +171,13 @@ def build_family(family, toolchain, build_system, one_per_family, boards): return ret all_boards = [random.choice(all_boards)] - # success, failed, skipped - all_examples = get_examples(family) - for board in all_boards: - r = [0, 0, 0] - if build_system == 'cmake': - r = build_board_cmake(board, toolchain) - elif build_system == 'make': - r = build_board_make_all_examples(board, toolchain, all_examples) - ret[0] += r[0] - ret[1] += r[1] - ret[2] += r[2] - + ret = build_boards_list(all_boards, toolchain, build_system) return ret +# ----------------------------- +# Main +# ----------------------------- def main(): parser = argparse.ArgumentParser() parser.add_argument('families', nargs='*', default=[], help='Families to build') @@ -175,7 +198,7 @@ def main(): return 1 print(build_separator) - print(build_utils.build_format.format('Example', 'Board', '\033[39mResult\033[0m', 'Time', 'Flash', 'SRAM')) + print(build_format.format('Board', 'Example', '\033[39mResult\033[0m', 'Time')) total_time = time.monotonic() result = [0, 0, 0] @@ -189,28 +212,22 @@ def main(): all_families = list(families) all_families.sort() - # succeeded, failed + # succeeded, failed, skipped for f in all_families: - fret = build_family(f, toolchain, build_system, one_per_family, boards) - result[0] += fret[0] - result[1] += fret[1] - result[2] += fret[2] - - # build boards - for b in boards: - r = [0, 0, 0] - if build_system == 'cmake': - r = build_board_cmake(b, toolchain) - elif build_system == 'make': - all_examples = get_examples(find_family(b)) - r = build_board_make_all_examples(b, toolchain, all_examples) + r = build_family(f, toolchain, build_system, one_per_family, boards) result[0] += r[0] result[1] += r[1] result[2] += r[2] + # build boards + r = build_boards_list(boards, toolchain, build_system) + result[0] += r[0] + result[1] += r[1] + result[2] += r[2] + total_time = time.monotonic() - total_time print(build_separator) - print(f"Build Summary: {result[0]} {SUCCEEDED}, {result[1]} {FAILED} and took {total_time:.2f}s") + print(f"Build Summary: {result[0]} {STATUS_OK}, {result[1]} {STATUS_FAILED} and took {total_time:.2f}s") print(build_separator) return result[1] diff --git a/tools/build_utils.py b/tools/build_utils.py index b66b64b97..5f88db8a2 100644 --- a/tools/build_utils.py +++ b/tools/build_utils.py @@ -81,43 +81,6 @@ def skip_example(example, board): return False -def build_example(example, board, make_option): - start_time = time.monotonic() - flash_size = "-" - sram_size = "-" - - # succeeded, failed, skipped - ret = [0, 0, 0] - - make_cmd = "make -j -C examples/{} BOARD={} {}".format(example, board, make_option) - - # Check if board is skipped - if skip_example(example, board): - status = SKIPPED - ret[2] = 1 - print(build_format.format(example, board, status, '-', flash_size, sram_size)) - else: - #subprocess.run(make_cmd + " clean", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - build_result = subprocess.run(make_cmd + " all", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - - if build_result.returncode == 0: - status = SUCCEEDED - ret[0] = 1 - (flash_size, sram_size) = build_size(make_cmd) - #subprocess.run(make_cmd + " copy-artifact", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - else: - status = FAILED - ret[1] = 1 - - build_duration = time.monotonic() - start_time - print(build_format.format(example, board, status, "{:.2f}s".format(build_duration), flash_size, sram_size)) - - if build_result.returncode != 0: - print(build_result.stdout.decode("utf-8")) - - return ret - - def build_size(make_cmd): size_output = subprocess.run(make_cmd + ' size', shell=True, stdout=subprocess.PIPE).stdout.decode("utf-8").splitlines() for i, l in enumerate(size_output): diff --git a/tools/get_deps.py b/tools/get_deps.py index 92bfb86a2..06da54b41 100644 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -24,6 +24,9 @@ deps_optional = { 'hw/mcu/allwinner': ['https://github.com/hathach/allwinner_driver.git', '8e5e89e8e132c0fd90e72d5422e5d3d68232b756', 'fc100s'], + 'hw/mcu/analog/max32' : ['https://github.com/analogdevicesinc/msdk.git', + 'b20b398d3e5e2007594e54a74ba3d2a2e50ddd75', + 'max32650 max32666 max32690 max78002'], 'hw/mcu/bridgetek/ft9xx/ft90x-sdk': ['https://github.com/BRTSG-FOSS/ft90x-sdk.git', '91060164afe239fcb394122e8bf9eb24d3194eb1', 'brtmm90x'], @@ -49,13 +52,13 @@ deps_optional = { '2204191ec76283371419fbcec207da02e1bc22fa', 'nuc'], 'hw/mcu/nxp/lpcopen': ['https://github.com/hathach/nxp_lpcopen.git', - '04bfe7a5f6ee74a89a28ad618d3367dcfcfb7d83', + 'b41cf930e65c734d8ec6de04f1d57d46787c76ae', 'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43'], 'hw/mcu/nxp/mcux-sdk': ['https://github.com/hathach/mcux-sdk.git', '144f1eb7ea8c06512e12f12b27383601c0272410', 'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'], 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/sekigon-gonnoc/Pico-PIO-USB.git', - '0f747aaa0c16f750bdfa2ba37ec25d6c8e1bc117', + 'fe9133fc513b82cc3dc62c67cb51f2339cf29ef7', 'rp2040'], 'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git', 'd52e5a6a59b7c638da860c2bb309b6e78e752ff8', @@ -172,10 +175,10 @@ deps_optional = { '7578cae0b21f86dd053a1f781b2fc6ab99d0ec17', 'ch32v10x'], 'hw/mcu/wch/ch32v20x': ['https://github.com/openwch/ch32v20x.git', - 'de6d68c654340d7f27b00cebbfc9aa2740a1abc2', + 'c4c38f507e258a4e69b059ccc2dc27dde33cea1b', 'ch32v20x'], 'hw/mcu/wch/ch32v307': ['https://github.com/openwch/ch32v307.git', - '17761f5cf9dbbf2dcf665b7c04934188add20082', + '184f21b852cb95eed58e86e901837bc9fff68775', 'ch32v307'], 'hw/mcu/wch/ch32f20x': ['https://github.com/openwch/ch32f20x.git', '77c4095087e5ed2c548ec9058e655d0b8757663b',