Merge branch 'master' into dwc2-proper-attach-debouncing

Signed-off-by: HiFiPhile <admin@hifiphile.com>
This commit is contained in:
HiFiPhile 2025-04-18 14:54:20 +02:00
commit 4c6736c277
61 changed files with 1190 additions and 1051 deletions

View File

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

View File

@ -10,17 +10,7 @@ commands:
- run:
name: Set toolchain url and key
command: |
TOOLCHAIN_JSON='{
"aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
"arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
"arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz",
"msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
"riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
"rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run",
"arm-iar": "https://updates.iar.com/FileStore/STANDARD/001/003/322/cxarm-9.60.3.deb"
}'
toolchain_url=$(echo $TOOLCHAIN_JSON | jq -r '.["<< parameters.toolchain >>"]')
toolchain_url=$(jq -r '."<< parameters.toolchain >>"' .github/actions/setup_toolchain/toolchain.json)
# only cache if not a github link
if [[ $toolchain_url != "https://github.com"* ]]; then
echo "<< parameters.toolchain >>-$toolchain_url" > toolchain_key
@ -121,7 +111,6 @@ commands:
TOOLCHAIN_OPTION="--toolchain clang"
elif [ << parameters.toolchain >> == arm-iar ]; then
TOOLCHAIN_OPTION="--toolchain iar"
echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
iccarm --version
elif [ << parameters.toolchain >> == arm-gcc ]; then
TOOLCHAIN_OPTION="--toolchain gcc"

View File

@ -28,18 +28,10 @@ runs:
- name: Get Toolchain URL
if: >-
inputs.toolchain != 'arm-gcc' &&
inputs.toolchain != 'arm-iar' &&
inputs.toolchain != 'esp-idf'
id: set-toolchain-url
run: |
TOOLCHAIN_JSON='{
"aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
"arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
"msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
"riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
"rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run"
}'
TOOLCHAIN_URL=$(echo $TOOLCHAIN_JSON | jq -r '.["${{ inputs.toolchain }}"]')
TOOLCHAIN_URL=$(jq -r '."${{ inputs.toolchain }}"' .github/actions/setup_toolchain/toolchain.json)
echo "toolchain_url=$TOOLCHAIN_URL"
echo "toolchain_url=$TOOLCHAIN_URL" >> $GITHUB_OUTPUT
shell: bash
@ -47,7 +39,6 @@ runs:
- name: Download Toolchain
if: >-
inputs.toolchain != 'arm-gcc' &&
inputs.toolchain != 'arm-iar' &&
inputs.toolchain != 'esp-idf'
uses: ./.github/actions/setup_toolchain/download
with:

View File

@ -23,17 +23,25 @@ runs:
if: steps.cache-toolchain-download.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/${{ inputs.toolchain }}
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
if [[ ${{ inputs.toolchain }} == rx-gcc ]]; then
mv toolchain.tar.gz toolchain.run
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.run
chmod +x toolchain.run
./toolchain.run -p ~/cache/${{ inputs.toolchain }}/gnurx -y
elif [[ ${{ inputs.toolchain }} == arm-iar ]]; then
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O ~/cache/${{ inputs.toolchain }}/cxarm.deb
else
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
tar -C ~/cache/${{ inputs.toolchain }} -xaf toolchain.tar.gz
fi
shell: bash
- name: Set Toolchain Path
- name: Setup Toolchain
run: |
echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
if [[ ${{ inputs.toolchain }} == arm-iar ]]; then
sudo apt-get install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb
echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin"
else
echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
fi
shell: bash

View File

@ -0,0 +1,9 @@
{
"aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
"arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
"arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz",
"msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
"riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
"rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run",
"arm-iar": "https://netstorage.iar.com/FileStore/STANDARD/001/003/583/cxarm-9.60.4.deb"
}

View File

@ -85,7 +85,7 @@ jobs:
- 'msp430-gcc'
- 'riscv-gcc'
- 'rx-gcc'
- 'esp-idf' # build-system is ignored
- 'esp-idf'
with:
build-system: 'make'
toolchain: ${{ matrix.toolchain }}
@ -110,37 +110,26 @@ jobs:
one-per-family: true
# ---------------------------------------
# Build IAR on HFP self-hosted
# Since IAR Token secret is not passed to forked PR, only build on PR from the same repo
# Build IAR
# Since IAR Token secret is not passed to forked PR, only build non-forked PR with make.
# cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family
# ---------------------------------------
arm-iar:
if: github.repository_owner == 'hathach' && github.event_name == 'push'
if: false # disable for now since we got reach capacity limit too often
#if: github.event_name == 'push' && github.repository_owner == 'hathach'
needs: set-matrix
runs-on: [self-hosted, Linux, X64, hifiphile]
env:
BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }}
IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }}
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Toolchain version
run: |
echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
iccarm --version
- name: Checkout TinyUSB
uses: actions/checkout@v4
- name: Get Dependencies
run: python3 tools/get_deps.py $BUILD_ARGS
- name: Build
run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS
uses: ./.github/workflows/build_util.yml
secrets: inherit
strategy:
fail-fast: false
matrix:
build-system:
- 'make'
with:
build-system: ${{ matrix.build-system }}
toolchain: 'arm-iar'
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }}
one-per-family: true
# ---------------------------------------
# Zephyr

View File

@ -58,6 +58,8 @@ jobs:
shell: bash
- name: Build
env:
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
run: |
if [ "${{ inputs.toolchain }}" == "esp-idf" ]; then
docker run --rm -v $PWD:/project -w /project espressif/idf:tinyusb python tools/build.py ${{ matrix.arg }}

View File

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

View File

@ -90,13 +90,12 @@ jobs:
# ---------------------------------------
# Hardware in the loop (HIL)
# self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
# Since IAR Token secret is not passed to forked PR, only build on PR from the same repo
# Since IAR Token secret is not passed to forked PR, only build non-forked PR
# ---------------------------------------
hil-hfp:
if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false
runs-on: [self-hosted, Linux, X64, hifiphile]
env:
IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }}
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
steps:
- name: Clean workspace
@ -107,7 +106,6 @@ jobs:
- name: Toolchain version
run: |
echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
iccarm --version
- name: Checkout TinyUSB

View File

@ -12,8 +12,8 @@ else ifeq ($(TOOLCHAIN),clang)
-mfpu=fpv4-sp-d16 \
else ifeq ($(TOOLCHAIN),iar)
CFLAGS += --cpu cortex-m4 --fpu VFPv4
ASFLAGS += --cpu cortex-m4 --fpu VFPv4
CFLAGS += --cpu cortex-m4 --fpu VFPv4-SP
ASFLAGS += --cpu cortex-m4 --fpu VFPv4-SP
else
$(error "TOOLCHAIN is not supported")

View File

@ -40,17 +40,15 @@ static bool ejected = false;
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
enum {
DISK_BLOCK_NUM = 16,// 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
@ -59,60 +57,59 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U',
'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F// // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
{
// first entry is volume label
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00// readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
@ -121,23 +118,21 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(vendor_id, vid, strlen(vid));
memcpy(product_id, pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
(void) lun;
// RAM disk is ready until ejected
@ -152,29 +147,24 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun)
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
if (load_eject) {
if (start) {
// load disk storage
}else
{
} else {
// unload disk storage
ejected = true;
}
@ -185,52 +175,51 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) {
if (lba >= DISK_BLOCK_NUM) {
return -1;
}
// Check for overflow of offset + bufsize
if ( offset + bufsize > DISK_BLOCK_SIZE ) {
if (offset + bufsize > DISK_BLOCK_SIZE) {
return -1;
}
uint8_t const* addr = msc_disk[lba] + offset;
uint8_t const *addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t) bufsize;
}
bool tud_msc_is_writable_cb (uint8_t lun)
{
bool tud_msc_is_writable_cb(uint8_t lun) {
(void) lun;
#ifdef CFG_EXAMPLE_MSC_READONLY
#ifdef CFG_EXAMPLE_MSC_READONLY
return false;
#else
#else
return true;
#endif
#endif
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
if (lba >= DISK_BLOCK_NUM) return -1;
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void) lba; (void) offset; (void) buffer;
#endif
#else
(void) lba;
(void) offset;
(void) buffer;
#endif
return (int32_t) bufsize;
}
@ -238,42 +227,18 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
(void) buffer;
(void) bufsize;
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
switch (scsi_cmd[0]) {
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
return -1;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, (size_t) resplen);
}else
{
// SCSI output
}
}
return (int32_t) resplen;
}
#endif

View File

@ -55,8 +55,7 @@ If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
@ -283,9 +282,11 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
// out of ramdisk
if (lba >= DISK_BLOCK_NUM) return -1;
if (lba >= DISK_BLOCK_NUM) {
return -1;
}
#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
(void) lun;
(void) lba;
(void) offset;
@ -302,11 +303,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks (MUST not be handled here)
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
(void) buffer;
(void) bufsize;
switch (scsi_cmd[0]) {
default:
@ -316,19 +314,6 @@ int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, u
// negative means error -> tinyusb could stall and/or response with failed status
return -1;
}
// return resplen must not larger than bufsize
if (resplen > bufsize) resplen = bufsize;
if (response && (resplen > 0)) {
if (in_xfer) {
memcpy(buffer, response, (size_t) resplen);
} else {
// SCSI output
}
}
return resplen;
}
#endif

View File

@ -22,6 +22,6 @@ SRC_C += \
$(FATFS_PATH)/ffunicode.c \
# suppress warning caused by fatfs
CFLAGS += -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=cast-qual
include ../../build_system/make/rules.mk

View File

@ -12,21 +12,31 @@
"BOARD": "${presetName}"
}
},
{
"name": "default single",
"hidden": true,
"description": "Configure preset for the ${presetName} board",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"BOARD": "${presetName}"
}
},
{
"name": "adafruit_clue",
"inherits": "default"
},
{
"name": "adafruit_feather_esp32_v2",
"inherits": "default"
"inherits": "default single"
},
{
"name": "adafruit_feather_esp32s2",
"inherits": "default"
"inherits": "default single"
},
{
"name": "adafruit_feather_esp32s3",
"inherits": "default"
"inherits": "default single"
},
{
"name": "adafruit_magtag_29gray",
@ -34,7 +44,7 @@
},
{
"name": "adafruit_metro_esp32s2",
"inherits": "default"
"inherits": "default single"
},
{
"name": "apard32690",
@ -130,39 +140,39 @@
},
{
"name": "espressif_addax_1",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_c3_devkitc",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_c6_devkitc",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_kaluga_1",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_p4_function_ev",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_s2_devkitc",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_s3_devkitc",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_s3_devkitm",
"inherits": "default"
"inherits": "default single"
},
{
"name": "espressif_saola_1",
"inherits": "default"
"inherits": "default single"
},
{
"name": "f1c100s",

View File

@ -15,7 +15,7 @@ CFLAGS += \
CROSS_COMPILE = arm-none-eabi-
# mcu driver cause following warnings
CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls
SRC_C += \
src/portable/synopsys/dwc2/dcd_dwc2.c \

View File

@ -14,7 +14,7 @@ CFLAGS += \
CROSS_COMPILE = aarch64-none-elf-
# mcu driver cause following warnings
CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls
SRC_C += \
src/portable/synopsys/dwc2/dcd_dwc2.c \

View File

@ -41,9 +41,10 @@
#define BUTTON_PIN 35
#define BUTTON_STATE_ACTIVE 0
// For CI hardware test, to test both device and host on the same HS port with help of
#define HIL_DEVICE_HOST_MUX_PIN 47
#define HIL_DEVICE_STATE 1
// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30
// https://www.adafruit.com/product/5871
#define HIL_TS3USB30_MODE_PIN 47
#define HIL_TS3USB30_MODE_DEVICE 1
#ifdef __cplusplus
}

View File

@ -36,13 +36,19 @@
extern "C" {
#endif
// Note: On the production version (v1.2) WS2812 is connected to GPIO 18,
// however earlier revision v1.1 WS2812 is connected to GPIO 17
#define NEOPIXEL_PIN 18
#define BUTTON_PIN 0
#define BUTTON_STATE_ACTIVE 0
// SPI for USB host shield
#define MAX3421_SPI_HOST SPI2_HOST
#define MAX3421_SCK_PIN 36
#define MAX3421_MOSI_PIN 35
#define MAX3421_MISO_PIN 37
#define MAX3421_CS_PIN 15
#define MAX3421_INTR_PIN 14
#ifdef __cplusplus
}
#endif

View File

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

View File

@ -49,6 +49,11 @@
#define MAX3421_CS_PIN 15
#define MAX3421_INTR_PIN 14
// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30
// https://www.adafruit.com/product/5871
#define HIL_TS3USB30_MODE_PIN 47
#define HIL_TS3USB30_MODE_DEVICE 1
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

@ -3,7 +3,7 @@ MCU = K32L2A41A
CFLAGS += -DCPU_K32L2A41VLH1A
# mcu driver cause following warnings
CFLAGS += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual
# All source paths should be relative to the top level.
LD_FILE = $(MCU_DIR)/gcc/K32L2A41xxxxA_flash.ld

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,70 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2025 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
/* metadata:
name: Pico
url: https://www.raspberrypi.com/products/raspberry-pi-pico/
*/
#ifndef TUSB_BOARD_H
#define TUSB_BOARD_H
#ifdef __cplusplus
extern "C" {
#endif
// UART and LED are already defined in pico-sdk board
//--------------------------------------------------------------------+
// PIO_USB
//--------------------------------------------------------------------+
// default to pico brain tester
#define PICO_DEFAULT_PIO_USB_DP_PIN 20
#define PICO_DEFAULT_PIO_USB_VBUSEN_PIN 22
#define PICO_DEFAULT_PIO_USB_VBUSEN_STATE 1
//--------------------------------------------------------------------
// USB Host MAX3421E
//--------------------------------------------------------------------
#ifdef PICO_DEFAULT_SPI
#define MAX3421_SPI PICO_DEFAULT_SPI // sdk v2
#else
#define MAX3421_SPI PICO_DEFAULT_SPI_INSTANCE // sdk v1
#endif
#define MAX3421_SCK_PIN PICO_DEFAULT_SPI_SCK_PIN
#define MAX3421_MOSI_PIN PICO_DEFAULT_SPI_TX_PIN
#define MAX3421_MISO_PIN PICO_DEFAULT_SPI_RX_PIN
#define MAX3421_CS_PIN 10
#define MAX3421_INTR_PIN 9
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,7 @@
# boards in this files are skipped when running CI with this family
adafruit_feather_rp2040_usb_host
adafruit_fruit_jam
adafruit_metro_rp2350
feather_rp2040_max3421
pico_sdk
raspberry_pi_pico_w

View File

@ -1,12 +1,9 @@
CFLAGS += \
-DSTM32F207xx \
MCU_VARIANT = stm32f207xx
CFLAGS += -DSTM32F207xx
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32F207ZGTx_FLASH.ld
SRC_S += \
$(ST_CMSIS)/Source/Templates/gcc/startup_stm32f207xx.s
# For flash-jlink target
JLINK_DEVICE = stm32f207zg

View File

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

View File

@ -1,12 +1,10 @@
MCU_VARIANT = stm32f303xc
CFLAGS += \
-DSTM32F303xC \
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32F303VCTx_FLASH.ld
SRC_S += \
$(ST_CMSIS)/Source/Templates/gcc/startup_stm32f303xc.s
# For flash-jlink target
JLINK_DEVICE = stm32f303vc

View File

@ -1,22 +1,17 @@
ST_FAMILY = f3
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
DEPS_SUBMODULES += \
lib/CMSIS_5 \
$(ST_CMSIS) \
$(ST_HAL_DRIVER)
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
-flto \
-DCFG_TUSB_MCU=OPT_MCU_STM32F3
# mcu driver cause following warnings
CFLAGS += -Wno-error=unused-parameter
CFLAGS_GCC += \
-flto \
-Wno-error=unused-parameter
LDFLAGS_GCC += \
-nostdlib -nostartfiles \
@ -36,3 +31,10 @@ INC += \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
# Startup
SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
# Linker
LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf

View File

@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x57755a57
ST_FAMILY = f4
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@ -184,7 +184,7 @@ static MFXSTM32L152_Object_t mfx_obj = { 0 };
static MFXSTM32L152_IO_Mode_t* mfx_io = NULL;
static uint32_t mfx_vbus_pin[2] = { MFXSTM32L152_GPIO_PIN_7, MFXSTM32L152_GPIO_PIN_9 };
int32_t board_i2c_init(void) {
static int32_t board_i2c_init(void) {
__HAL_RCC_I2C1_CLK_ENABLE();
__HAL_RCC_I2C1_FORCE_RESET();
__HAL_RCC_I2C1_RELEASE_RESET();
@ -200,16 +200,16 @@ int32_t board_i2c_init(void) {
return 0;
}
int32_t board_i2c_deinit(void) {
static int32_t board_i2c_deinit(void) {
return 0;
}
int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
static int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
return 0;
}
int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
static int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
return 0;
}
@ -249,7 +249,7 @@ static inline void board_init2(void) {
}
// VBUS1 is actually controlled by USB3320C PHY (using dwc2 drivebus signal)
void board_vbus_set(uint8_t rhport, bool state) {
static void TU_ATTR_UNUSED board_vbus_set(uint8_t rhport, bool state) {
if (mfx_io) {
mfx_io->IO_WritePin(&mfx_obj, mfx_vbus_pin[rhport], state);
}

View File

@ -80,7 +80,7 @@ void OTG_HS_IRQHandler(void) {
}
#ifdef TRACE_ETM
void trace_etm_init(void) {
static void trace_etm_init(void) {
// H7 trace pin is PE2 to PE6
GPIO_InitTypeDef gpio_init;
gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
@ -94,7 +94,7 @@ void trace_etm_init(void) {
DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN;
}
#else
#define trace_etm_init()
#define trace_etm_init()
#endif
void board_init(void) {

View File

@ -45,11 +45,9 @@ CFLAGS += \
-DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
# GCC Flags
CFLAGS_GCC += \
-flto \
# suppress warning caused by vendor mcu driver
CFLAGS_GCC += \
-flto \
-Wno-error=cast-align \
-Wno-error=unused-parameter \

View File

@ -1,10 +1,9 @@
MCU_VARIANT = stm32l052xx
CFLAGS += \
-DSTM32L052xx
LD_FILE = $(BOARD_PATH)/STM32L052K8Ux_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32l052xx.s
# For flash-jlink target
JLINK_DEVICE = stm32l052k8

View File

@ -1,12 +1,10 @@
MCU_VARIANT = stm32l053xx
CFLAGS += \
-DSTM32L053xx
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32L053C8Tx_FLASH.ld
SRC_S += \
$(ST_CMSIS)/Source/Templates/gcc/startup_stm32l053xx.s
# For flash-jlink target
JLINK_DEVICE = STM32L053R8

View File

@ -1,9 +1,4 @@
ST_FAMILY = l0
DEPS_SUBMODULES += \
lib/CMSIS_5 \
hw/mcu/st/cmsis_device_$(ST_FAMILY) \
hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
@ -11,20 +6,17 @@ include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m0plus
CFLAGS += \
-flto \
-DCFG_EXAMPLE_MSC_READONLY \
-DCFG_EXAMPLE_VIDEO_READONLY \
-DCFG_TUSB_MCU=OPT_MCU_STM32L0
# mcu driver cause following warnings
CFLAGS_GCC += \
-flto \
-Wno-error=unused-parameter \
-Wno-error=redundant-decls \
-Wno-error=cast-align \
ifeq ($(TOOLCHAIN),gcc)
CFLAGS_GCC += -Wno-error=maybe-uninitialized
endif
-Wno-error=maybe-uninitialized \
CFLAGS_CLANG += \
-Wno-error=parentheses-equality
@ -48,3 +40,10 @@ INC += \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc
# Startup
SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
# Linker
LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf

View File

@ -1,11 +1,9 @@
MCU_VARIANT = stm32u585xx
CFLAGS += \
-DSTM32U585xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
MCU_VARIANT = stm32u585xx
# For flash-jlink target
JLINK_DEVICE = stm32u585zi

View File

@ -1,11 +1,9 @@
MCU_VARIANT = stm32u545xx
CFLAGS += \
-DSTM32U545xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U545xx_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u545xx.s
MCU_VARIANT = stm32u545xx
# For flash-jlink target
JLINK_DEVICE = stm32u545re

View File

@ -1,11 +1,9 @@
MCU_VARIANT = stm32u575xx
CFLAGS += \
-DSTM32U575xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
MCU_VARIANT = stm32u575xx
# For flash-jlink target
JLINK_DEVICE = stm32u575ai

View File

@ -1,11 +1,9 @@
MCU_VARIANT = stm32u575xx
CFLAGS += \
-DSTM32U575xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
MCU_VARIANT = stm32u575xx
# For flash-jlink target
JLINK_DEVICE = stm32u575zi

View File

@ -1,3 +1,4 @@
MCU_VARIANT = stm32u5a5xx
CFLAGS += \
-DSTM32U5A5xx \
-DHSE_VALUE=16000000UL \
@ -5,8 +6,5 @@ CFLAGS += \
# All source paths should be relative to the top level.
LD_FILE = ${BOARD_PATH}/STM32U5A5ZJTXQ_FLASH.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u5a5xx.s
MCU_VARIANT = stm32u5a5xx
# For flash-jlink target
JLINK_DEVICE = stm32u575zi

View File

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

View File

@ -9,14 +9,12 @@ include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
-flto \
-nostdlib -nostartfiles \
-DCFG_TUSB_MCU=OPT_MCU_STM32WB
# suppress warning caused by vendor mcu driver
CFLAGS += -Wno-error=cast-align -Wno-unused-parameter
LD_FILE ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld
CFLAGS_GCC += \
-flto \
-nostdlib -nostartfiles \
-Wno-error=cast-align -Wno-unused-parameter
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
@ -25,19 +23,26 @@ SRC_C += \
$(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr_ex.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc_ex.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}_cm4.s
INC += \
$(TOP)/$(BOARD_PATH) \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc
# Startup
SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT)_cm4.s
SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT)_cm4.s
# Linker
LD_FILE_GCC ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld
LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash_cm4.icf
# flash target using on-board stlink
flash: flash-stlink

View File

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

View File

@ -108,15 +108,13 @@ typedef struct {
} tu_lookup_table_t;
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) {
tu_static char not_found[11];
for(uint16_t i=0; i<p_table->count; i++) {
if (p_table->items[i].key == key) return p_table->items[i].data;
if (p_table->items[i].key == key) { return p_table->items[i].data; }
}
// not found return the key value in hex
static char not_found[11];
snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
return not_found;
}

View File

@ -1372,9 +1372,13 @@ enum {
ENUM_HUB_CLEAR_RESET_2,
ENUM_SET_ADDR,
ENUM_GET_DEVICE_DESC,
ENUM_GET_STRING_LANGUAGE_ID_LEN,
ENUM_GET_STRING_LANGUAGE_ID,
ENUM_GET_STRING_MANUFACTURER_LEN,
ENUM_GET_STRING_MANUFACTURER,
ENUM_GET_STRING_PRODUCT_LEN,
ENUM_GET_STRING_PRODUCT,
ENUM_GET_STRING_SERIAL_LEN,
ENUM_GET_STRING_SERIAL,
ENUM_GET_9BYTE_CONFIG_DESC,
ENUM_GET_FULL_CONFIG_DESC,
@ -1416,6 +1420,9 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const daddr = xfer->daddr;
uintptr_t const state = xfer->user_data;
usbh_device_t* dev = get_device(daddr);
if (daddr > 0) {
TU_ASSERT(dev,);
}
uint16_t langid = 0x0409; // default is English
switch (state) {
@ -1474,30 +1481,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
break;
}
#if 0
case ENUM_RESET_2:
// TODO not used by now, but may be needed for some devices !?
// Reset device again before Set Address
TU_LOG_USBH("Port reset2 \r\n");
if (_dev0.hub_addr == 0) {
// connected directly to roothub
hcd_port_reset( _dev0.rhport );
tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
// sof of controller may not running while resetting
hcd_port_reset_end(_dev0.rhport);
// TODO: fall through to SET ADDRESS, refactor later
}
#if CFG_TUH_HUB
else {
// after RESET_DELAY the hub_port_reset() already complete
TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port,
process_enumeration, ENUM_HUB_GET_STATUS_2), );
break;
}
#endif
TU_ATTR_FALLTHROUGH;
#endif
case ENUM_SET_ADDR:
enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl);
break;
@ -1520,14 +1503,15 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// Get full device descriptor
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),);
process_enumeration, ENUM_GET_STRING_LANGUAGE_ID_LEN),);
break;
}
case ENUM_GET_STRING_LANGUAGE_ID: {
// For string descriptor (langid, manufacturer, product, serila): always get the first 2 bytes
// to determine the length first. otherwise, some device may have buffer overflow.
case ENUM_GET_STRING_LANGUAGE_ID_LEN: {
// save the received device descriptor
TU_ASSERT(dev,);
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl;
dev->vid = desc_device->idVendor;
dev->pid = desc_device->idProduct;
dev->i_manufacturer = desc_device->iManufacturer;
@ -1535,50 +1519,88 @@ static void process_enumeration(tuh_xfer_t* xfer) {
dev->i_serial = desc_device->iSerialNumber;
dev->bNumConfigurations = desc_device->bNumConfigurations;
tuh_enum_descriptor_device_cb(daddr, desc_device); // callback
tuh_enum_descriptor_device_cb(daddr, desc_device);// callback
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_LANGUAGE_ID);
break;
}
case ENUM_GET_STRING_MANUFACTURER: {
TU_ASSERT(dev,);
const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl;
case ENUM_GET_STRING_LANGUAGE_ID: {
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN);
break;
}
case ENUM_GET_STRING_MANUFACTURER_LEN: {
const tusb_desc_string_t* desc_langid = (const tusb_desc_string_t *) _usbh_epbuf.ctrl;
if (desc_langid->bLength >= 4) {
langid = tu_le16toh(desc_langid->utf16le[0]);
langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid
}
if (dev->i_manufacturer != 0) {
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
break;
}else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_MANUFACTURER: {
if (dev->i_manufacturer != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_PRODUCT_LEN);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_PRODUCT_LEN:
if (dev->i_product != 0) {
if (state == ENUM_GET_STRING_PRODUCT_LEN) {
langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_PRODUCT);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_PRODUCT: {
TU_ASSERT(dev,);
if (state == ENUM_GET_STRING_PRODUCT) {
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
}
if (dev->i_product != 0) {
tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
process_enumeration, ENUM_GET_STRING_SERIAL);
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_SERIAL_LEN);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_SERIAL: {
TU_ASSERT(dev,);
if (state == ENUM_GET_STRING_SERIAL) {
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
}
case ENUM_GET_STRING_SERIAL_LEN:
if (dev->i_serial != 0) {
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
if (state == ENUM_GET_STRING_SERIAL_LEN) {
langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_SERIAL);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
case ENUM_GET_STRING_SERIAL: {
if (dev->i_serial != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
break;
} else {
TU_ATTR_FALLTHROUGH;
@ -1627,8 +1649,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n");
TU_ASSERT(dev,);
dev->configured = 1;
// Parse configuration & set up drivers

View File

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

View File

@ -88,11 +88,13 @@ static void phy_fs_init(dwc2_regs_t* dwc2) {
static void phy_hs_init(dwc2_regs_t* dwc2) {
uint32_t gusbcfg = dwc2->gusbcfg;
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4};
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n");
// Select ULPI PHY (external)
@ -116,7 +118,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
// Set 16-bit interface if supported
if (dwc2->ghwcfg4_bm.phy_data_width) {
if (ghwcfg4.phy_data_width) {
gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
} else {
gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
@ -127,7 +129,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
dwc2->gusbcfg = gusbcfg;
// mcu specific phy init
dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
dwc2_phy_init(dwc2, ghwcfg2.hs_phy_type);
// Reset core after selecting PHY
reset_core(dwc2);
@ -136,11 +138,11 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// - 9 if using 8-bit PHY interface
// - 5 if using 16-bit PHY interface
gusbcfg &= ~GUSBCFG_TRDT_Msk;
gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
gusbcfg |= (ghwcfg4.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
dwc2->gusbcfg = gusbcfg;
// MCU specific PHY update post reset
dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
dwc2_phy_update(dwc2, ghwcfg2.hs_phy_type);
}
static bool check_dwc2(dwc2_regs_t* dwc2) {
@ -171,7 +173,6 @@ static bool check_dwc2(dwc2_regs_t* dwc2) {
//--------------------------------------------------------------------
bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
(void)dwc2;
#if CFG_TUD_ENABLED
if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) {
return false;
@ -183,7 +184,8 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
}
#endif
return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return ghwcfg2.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
}
/* dwc2 has several PHYs option

File diff suppressed because it is too large Load Diff

View File

@ -44,8 +44,6 @@
#endif
#define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count
#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX)
TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
enum {
@ -97,7 +95,6 @@ typedef struct {
uint8_t err_count : 3;
uint8_t period_split_nyet_count : 3;
uint8_t halted_nyet : 1;
uint8_t halted_sof_schedule : 1;
};
uint8_t result;
@ -117,9 +114,15 @@ hcd_data_t _hcd_data;
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_channel_count(const dwc2_regs_t* dwc2) {
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) {
tusb_speed_t speed;
switch(dwc2->hprt_bm.speed) {
const dwc2_hprt_t hprt = {.value = dwc2->hprt};
switch(hprt.speed) {
case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
@ -134,7 +137,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc
TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) {
(void) dwc2;
// Internal DMA only
return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
#if CFG_TUH_MEM_DCACHE_ENABLE
@ -156,7 +160,7 @@ bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
// Allocate a channel for new transfer
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
if (!xfer->allocated) {
@ -169,15 +173,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
}
// Check if is periodic (interrupt/isochronous)
TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) {
return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) {
const dwc2_channel_char_t hcchar_bm = {.value = hcchar};
return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) {
if (is_period) {
return dwc2->hptxsts_bm.req_queue_available;
const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts};
return hptxsts.req_queue_available;
} else {
return dwc2->hnptxsts_bm.req_queue_available;
const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts};
return hnptxsts.req_queue_available;
}
}
@ -189,7 +196,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint
TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
// disable also require request queue
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcintmsk |= HCINT_HALTED;
channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA
return true;
@ -197,18 +204,18 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2
// attempt to send IN token to receive data
TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcchar |= HCCHAR_CHENA;
return true;
}
// Find currently enabled channel. Note: EP0 is bidirectional
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (_hcd_data.xfer[ch_id].allocated) {
const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm;
if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) {
const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar};
if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) {
return ch_id;
}
}
@ -305,12 +312,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa
static void dfifo_host_init(uint8_t rhport) {
const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
// Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel
const bool is_dma = dma_host_enabled(dwc2);
uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4;
if (is_dma) {
dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch;
dfifo_top -= ghwcfg2.num_host_ch;
}
// fixed allocation for now, improve later:
@ -320,7 +328,7 @@ static void dfifo_host_init(uint8_t rhport) {
uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4;
uint16_t nptxfsiz = 2 * nptx_largest;
uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch;
uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch;
TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),);
uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz);
@ -382,7 +390,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
dwc2->hprt = HPRT_POWER; // turn on VBUS
// Enable required interrupts
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT;
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT | GINTSTS_DISCINT;
// NPTX can hold at least 2 packet, change interrupt level to half-empty
uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL;
@ -520,10 +528,11 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
// clean up channel after part of transfer is done but the whole urb is not complete
static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
const dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
edpt->next_pid = hctsiz.pid; // save PID
/* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB)
* For IN: we can use hctsiz.xfersize as remaining bytes.
@ -531,9 +540,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
* number of packets that have been transferred via the USB. This is always an integral number of packets if the
* transfer was halted before its normal completion.
*/
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size);
const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size;
const uint16_t remain_packets = hctsiz.packet_count;
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size);
const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size;
xfer->fifo_bytes = 0;
xfer->xferred_bytes += actual_bytes;
@ -546,7 +556,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
dwc2_channel_t* channel = &dwc2->channel[ch_id];
bool const is_period = edpt_is_periodic(hcchar_bm->ep_type);
bool const is_period = channel_is_periodic(edpt->hcchar);
// clear previous state
xfer->fifo_bytes = 0;
@ -559,12 +569,15 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
// hctsiz: zero length packet still count as 1
const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size);
uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen;
dwc2_channel_tsize_t hctsiz = {.value = 0};
hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt
hctsiz.packet_count = packet_count;
hctsiz.xfer_size = edpt->buflen;
if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH &&
edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) {
hctsiz |= HCTSIZ_DOPING;
hctsiz.do_ping = 1;
}
channel->hctsiz = hctsiz;
channel->hctsiz = hctsiz.value;
edpt->do_ping = 0;
// pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
@ -705,18 +718,23 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
//--------------------------------------------------------------------
// HCD Event Handler
//--------------------------------------------------------------------
// retry an IN transfer, channel must be halted
static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
if (edpt_is_periodic(channel->hcchar_bm.ep_type)){
if (channel_is_periodic(hcchar.value)){
const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
// retry immediately for periodic split NYET if we haven't reach max retry
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
xfer->period_split_nyet_count++;
xfer->halted_nyet = 0;
if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) {
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
channel->hcchar = hcchar.value;
channel_send_in_token(dwc2, channel);
return;
} else {
@ -725,18 +743,20 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
}
}
// for periodic, de-allocate channel, enable SOF set frame counter for later transfer
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
edpt->uframe_countdown = edpt->uframe_interval;
dwc2->gintmsk |= GINTSTS_SOF;
if (hcint & HCINT_HALTED) {
const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8);
if (edpt->uframe_interval == ucount) {
// retry on next frame if bInterval is 1
hcchar.odd_frame = 1 - (dwc2->hfnum & 1);
channel->hcchar = hcchar.value;
channel_send_in_token(dwc2, channel);
} else {
// otherwise, de-allocate channel, enable SOF set frame counter for later transfer
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
edpt->next_pid = hctsiz.pid; // save PID
edpt->uframe_countdown = edpt->uframe_interval - ucount;
dwc2->gintmsk |= GINTSTS_SOF;
// already halted, de-allocate channel (called from DMA isr)
channel_dealloc(dwc2, ch_id);
} else {
// disable channel first if not halted (called slave isr)
xfer->halted_sof_schedule = 1;
channel_disable(dwc2, channel);
}
} else {
// for control/bulk: retry immediately
@ -767,13 +787,13 @@ static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
// Pop control word off FIFO
const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
const uint8_t ch_id = grxstsp_bm.ep_ch_num;
const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp};
const uint8_t ch_id = grxstsp.ep_ch_num;
switch (grxstsp_bm.packet_status) {
switch (grxstsp.packet_status) {
case GRXSTS_PKTSTS_RX_DATA: {
// In packet received, pop this entry --> ACK interrupt
const uint16_t byte_count = grxstsp_bm.byte_count;
const uint16_t byte_count = grxstsp.byte_count;
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
@ -807,25 +827,26 @@ static void handle_rxflvl_irq(uint8_t rhport) {
// return true if there is still pending data and need more ISR
static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
// Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough)
volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts);
const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)};
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
// skip writing to FIFO if channel is expecting halted.
if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) {
if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
const uint16_t remain_packets = hctsiz.packet_count;
for (uint16_t i = 0; i < remain_packets; i++) {
const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes;
const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size);
const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size);
// skip if there is not enough space in FIFO and RequestQueue.
// Packet's last word written to FIFO will trigger a request queue
if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) {
if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) {
return true;
}
@ -842,23 +863,26 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
// if (channel->hcsplt_bm.split_en) {
// if (hcsplt.split_en) {
// if (edpt->hcchar_bm.ep_num == 1) {
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint);
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint);
// print_hcint(hcint);
// }
if (hcint & HCINT_XFER_COMPLETE) {
if (edpt->hcchar_bm.ep_num != 0) {
edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled)
edpt->next_pid = hctsiz.pid; // save pid (already toggled)
}
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
const uint16_t remain_packets = hctsiz.packet_count;
if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
} else {
xfer->result = XFER_RESULT_SUCCESS;
}
@ -877,43 +901,44 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
// restart complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
xfer->halted_nyet = 1;
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NAK) {
// NAK received, re-enable channel if request queue is available
if (channel->hcsplt_bm.split_en) {
channel->hcsplt_bm.split_compl = 0; // restart with start-split
// NAK received, disable channel to flush all posted request and try again
if (hcsplt.split_en) {
hcsplt.split_compl = 0; // restart with start-split
channel->hcsplt = hcsplt.value;
}
channel_disable(dwc2, channel);
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en) {
if (!channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en) {
if (!hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcintmsk |= HCINT_NYET;
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
} else {
// do nothing for complete split with DATA, this will trigger XferComplete and handled there
}
} else {
// ACK with data
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t remain_packets = hctsiz.packet_count;
if (remain_packets) {
// still more packet to receive, also reset to start split
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
}
}
} else if (hcint & HCINT_HALTED) {
channel->hcintmsk &= ~HCINT_HALTED;
if (xfer->halted_sof_schedule) {
// de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt
channel_dealloc(dwc2, ch_id);
} else if (xfer->result != XFER_RESULT_INVALID) {
if (xfer->result != XFER_RESULT_INVALID) {
is_done = true;
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
xfer->result = XFER_RESULT_FAILED;
@ -933,6 +958,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
if (hcint & HCINT_XFER_COMPLETE) {
@ -944,9 +970,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
} else {
edpt->do_ping = 1;
@ -979,9 +1006,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en && !hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
}
@ -1000,6 +1028,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
@ -1007,8 +1038,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
if (hcint & HCINT_HALTED) {
if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) {
const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size;
const uint16_t remain_packets = hctsiz.packet_count;
const uint16_t actual_len = edpt->buflen - remain_bytes;
xfer->xferred_bytes += actual_len;
@ -1018,13 +1049,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_STALLED;
} else if (hcint & HCINT_BABBLE_ERR) {
xfer->result = XFER_RESULT_FAILED;
} else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) {
} else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
is_done = false;
edpt->buffer += actual_len;
edpt->buflen -= actual_len;
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else {
xfer->result = XFER_RESULT_SUCCESS;
@ -1039,33 +1071,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_FAILED;
} else {
channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR;
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_NYET) {
// Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL
// OUT that started with a PING. The nyet takes precedence.
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// split not yet mean hub has no data, retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// start split is ACK --> do complete split
// TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe)
channel->hcsplt_bm.split_compl = 1;
if (edpt_is_periodic(channel->hcchar_bm.ep_type)) {
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
if (channel_is_periodic(channel->hcchar)) {
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
channel->hcchar = hcchar.value;
}
channel_send_in_token(dwc2, channel);
}
} else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) {
xfer->err_count = 0;
channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR);
channel->hcsplt_bm.split_compl = 0; // restart with start-split
hcsplt.split_compl = 0; // restart with start-split
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else if (hcint & HCINT_FARME_OVERRUN) {
// retry start-split in next binterval
@ -1080,6 +1117,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
@ -1115,16 +1154,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
}
}
} else if (hcint & HCINT_NYET) {
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en && hcsplt.split_compl) {
// split not yet mean hub has no data, retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en && !hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
}
@ -1140,14 +1181,14 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
static void handle_channel_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_host_enabled(dwc2);
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (tu_bit_test(dwc2->haint, ch_id)) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint32_t hcint = channel->hcint;
channel->hcint = hcint; // clear interrupt
@ -1155,7 +1196,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
bool is_done = false;
if (is_dma) {
#if CFG_TUH_DWC2_DMA_ENABLE
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_dma(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_dma(dwc2, ch_id, hcint);
@ -1167,7 +1208,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
#endif
} else {
#if CFG_TUH_DWC2_SLAVE_ENABLE
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_slave(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_slave(dwc2, ch_id, hcint);
@ -1176,8 +1217,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
}
if (is_done) {
const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr);
const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir);
hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr);
channel_dealloc(dwc2, ch_id);
}
}
@ -1197,7 +1238,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) {
if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) {
edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown);
if (edpt->uframe_countdown == 0) {
if (!edpt_xfer_kickoff(dwc2, ep_id)) {
@ -1216,10 +1257,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg};
uint32_t phy_clock;
if (gusbcfg_bm.phy_sel) {
if (gusbcfg.phy_sel) {
phy_clock = 48; // dedicated FS is 48Mhz
if (speed == TUSB_SPEED_LOW) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ;
@ -1227,11 +1268,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
}
} else {
if (gusbcfg_bm.ulpi_utmi_sel) {
if (gusbcfg.ulpi_utmi_sel) {
phy_clock = 60; // ULPI 8-bit is 60Mhz
} else {
// UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz
phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60;
phy_clock = gusbcfg.phy_if16 ? 30 : 60;
// Enable UTMI+ low power mode 48Mhz external clock if not highspeed
if (speed == TUSB_SPEED_HIGH) {
@ -1248,9 +1289,9 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
if (speed == TUSB_SPEED_HIGH) {
hfir |= 125*phy_clock;
hfir |= 125*phy_clock - 1; // The "- 1" is the correct value. The Synopsys databook was corrected in 3.30a
} else {
hfir |= 1000*phy_clock;
hfir |= 1000*phy_clock - 1;
}
dwc2->hfir = hfir;
@ -1263,10 +1304,10 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
*/
static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
const dwc2_hprt_t hprt_bm = {.value = dwc2->hprt};
uint32_t hprt = hprt_bm.value & ~HPRT_W1_MASK;
if (dwc2->hprt & HPRT_CONN_DETECT) {
if (hprt_bm.conn_detected) {
// Port Connect Detect
hprt |= HPRT_CONN_DETECT;
@ -1278,7 +1319,7 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
}
}
if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
if (hprt_bm.enable_change) {
// Port enable change
hprt |= HPRT_ENABLE_CHANGE;

View File

@ -106,6 +106,11 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport; (void) dev_addr; (void) ep_desc;
// NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open()
// You need to copy the data into a local variable who maintains the state of the endpoint and transfer.
// Check _hcd_data in hcd_dwc2.c for example.
return false;
}

View File

@ -35,7 +35,7 @@
#define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION)
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
#define TUSB_VERSION_STRING TU_XSTRING(TUSB_VERSION_MAJOR) "." TU_XSTRING(TUSB_VERSION_MINOR) "." TU_XSTRING(TUSB_VERSION_REVISION)
//--------------------------------------------------------------------+
// Supported MCUs

View File

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

View File

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

View File

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