diff options
| author | hathach <[email protected]> | 2026-01-12 13:52:29 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-01-12 13:52:29 +0700 |
| commit | 34035bb87cb90a2eb413633e30783d5e72d119a6 (patch) | |
| tree | 1f5916e55da448947f5b26ff6b9e8a2fb34104a6 | |
| parent | 237e9f21fd2f5211abd3784954b72fa900fff7ea (diff) | |
| parent | 085ec06874f5680604a75e3a721a51f962d66973 (diff) | |
Merge branch 'refs/heads/master' into mtp_zlp
75 files changed, 3214 insertions, 1801 deletions
diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py index c276d5253..237a34b9f 100755 --- a/.github/workflows/ci_set_matrix.py +++ b/.github/workflows/ci_set_matrix.py @@ -15,7 +15,8 @@ toolchain_list = [ # family: [supported toolchain] family_list = { - "at32f402_405 at32f403a_407 at32f413 at32f415 at32f423 at32f425 at32f435_437 broadcom_32bit da1469x": ["arm-gcc"], + "at32f45x at32f402_405 at32f403a_407 at32f413 at32f415 at32f423 at32f425 at32f435_437 broadcom_32bit da1469x": [ + "arm-gcc"], "broadcom_64bit": ["aarch64-gcc"], "ch32v10x ch32v20x ch32v30x fomu gd32vf103 hpmicro": ["riscv-gcc"], "imxrt": ["arm-gcc", "arm-clang"], diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 0754253ad..cc73ca8fc 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -103,6 +103,8 @@ <configuration PROFILE_NAME="metro m7 1011 sd" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011_sd -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" /> <configuration PROFILE_NAME="metro_m7_1011" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011 -DLOG=1 -DLOGGER=RTT" /> <configuration PROFILE_NAME="rt1010 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1010_evk -DLOG=1 -DLOGGER=RTT" /> + <configuration PROFILE_NAME="rt1024 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1024_evk -DLOG=1 -DLOGGER=RTT" /> + <configuration PROFILE_NAME="rt1050 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1050_evkb -DLOG=1 -DLOGGER=RTT" /> <configuration PROFILE_NAME="mimxrt1060_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1060_evk -DLOG=1" /> <configuration PROFILE_NAME="mimxrt1064_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1064_evk" /> <configuration PROFILE_NAME="rt1170 evkb" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1170_evkb -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" /> @@ -126,6 +128,7 @@ <configuration PROFILE_NAME="stm32h743eval_host1" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DRHPORT_HOST=1 -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" /> <configuration PROFILE_NAME="stm32h743eval IAR" ENABLED="false" CONFIG_NAME="Debug" TOOLCHAIN_NAME="iccarm" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1 -DIAR_CSTAT=1" /> <configuration PROFILE_NAME="stm32h743nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743nucleo -DLOG=1" /> + <configuration PROFILE_NAME="stm32h7s3nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h7s3nucleo -DLOG=1" /> <configuration PROFILE_NAME="stm32l0538disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l0538disco -DLOG=0 -DLOGGER=RTT" /> <configuration PROFILE_NAME="stm32l476disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l476disco -DLOG=1 -DLOGGER=RTT" /> <configuration PROFILE_NAME="stm32u575nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u575nucleo -DLOG=1 -DLOGGER=RTT" /> diff --git a/.idea/debugServers/ST_LINK.xml b/.idea/debugServers/ST_LINK.xml index 7c21d3879..c4dadd5bb 100644 --- a/.idea/debugServers/ST_LINK.xml +++ b/.idea/debugServers/ST_LINK.xml @@ -1,10 +1,10 @@ <component name="DebugServers"> - <stlink-debug-target name="ST-LINK" uniqueID="300d1a6f-85c0-4eb3-9753-f033d01e2eff"> + <stlink-debug-target name="ST-LINK" uniqueID="cf98f5f4-9c5b-4340-ab06-16ddd7f07062"> <debugger version="1"> <debugger kind="GDB" isBundled="true" /> <env /> </debugger> - <gdbserver exe="$USER_HOME$/st/stm32cubeide_1.16.1/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.400.202404281720/tools/bin/ST-LINK_gdbserver" programmer="$USER_HOME$/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" /> + <gdbserver exe="/opt/st/stm32cubeclt_1.20.0/STLink-gdb-server/bin/ST-LINK_gdbserver" programmer="/opt/st/stm32cubeclt_1.20.0/STM32CubeProgrammer/bin" /> <st-link /> <device interface="SWD" /> <connection port="61234" warmup-ms="500" /> diff --git a/.idea/debugServers/mcxa153.xml b/.idea/debugServers/mcxa153.xml new file mode 100644 index 000000000..0e493cbd5 --- /dev/null +++ b/.idea/debugServers/mcxa153.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="mcxa153" uniqueID="6a023429-69e6-4f8c-a592-4995cdf255db"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="MCXA153" reset-before="false" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/ra6m1.xml b/.idea/debugServers/ra6m1.xml new file mode 100644 index 000000000..17c902ec4 --- /dev/null +++ b/.idea/debugServers/ra6m1.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="ra6m1" uniqueID="c8cdc79a-939b-4342-92b1-d24da72d12fe"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="R7FA6M1AD" reset-before="false" frequency="16000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/ra6m5.xml b/.idea/debugServers/ra6m5.xml new file mode 100644 index 000000000..d8dfbdeeb --- /dev/null +++ b/.idea/debugServers/ra6m5.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="ra6m5" uniqueID="19100d9f-7329-47da-b566-f9faf297f47c"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="R7FA6M5BH" reset-before="false" frequency="16000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/rt1011.xml b/.idea/debugServers/rt1011.xml new file mode 100644 index 000000000..b4be501bd --- /dev/null +++ b/.idea/debugServers/rt1011.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="rt1011" uniqueID="e10c53c4-acf5-4a6f-a05d-32b7b042d70a"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="MIMXRT1011xxx5A" reset-before="false" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/rt1170.xml b/.idea/debugServers/rt1170.xml new file mode 100644 index 000000000..9a564ed57 --- /dev/null +++ b/.idea/debugServers/rt1170.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="rt1170" uniqueID="cfc772e4-782e-49a3-99fb-b6f726e14f9d"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="MIMXRT1176xxxA_M7" reset-before="false" frequency="16000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/stm32f072.xml b/.idea/debugServers/stm32f072.xml new file mode 100644 index 000000000..c56f5a8fb --- /dev/null +++ b/.idea/debugServers/stm32f072.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="stm32f072" uniqueID="f5c65701-0f8d-4923-a7ea-3ee2547147ae"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="STM32F072RB" reset-before="false" frequency="12000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/stm32f303.xml b/.idea/debugServers/stm32f303.xml new file mode 100644 index 000000000..84aafc1e3 --- /dev/null +++ b/.idea/debugServers/stm32f303.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="stm32f303" uniqueID="1cdd63e5-1736-42be-bff3-4c48e1f169fa"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="STM32F303VC" reset-before="false" frequency="12000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/.idea/debugServers/stm32l053.xml b/.idea/debugServers/stm32l053.xml new file mode 100644 index 000000000..5365189cc --- /dev/null +++ b/.idea/debugServers/stm32l053.xml @@ -0,0 +1,13 @@ +<component name="DebugServers"> + <jlink-debug-target name="stm32l053" uniqueID="51d156d7-86a6-4006-814a-ed14981d7b49"> + <debugger version="1"> + <debugger kind="GDB" isBundled="true" /> + <env /> + </debugger> + <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" /> + <console port="19021" /> + <target device="STM32L053R8" reset-before="false" frequency="12000" /> + <connection extended-remote="false" port="4444" warmup-ms="500" /> + <swo /> + </jlink-debug-target> +</component>
\ No newline at end of file diff --git a/README.rst b/README.rst index 178a084ce..e439a3137 100644 --- a/README.rst +++ b/README.rst @@ -139,9 +139,10 @@ Supported CPUs | | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | | | MAX78002 | | | | | | +--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ -| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | Packet SRAM 512 | +| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | 512 USB RAM | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ -| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | | +| | F415, F435_437, F423, | ✔ | ✔ | | dwc2 | | +| | F425, F45x | | | | | | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ | | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS | +--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ @@ -225,25 +226,25 @@ Supported CPUs +--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ | ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | | +----+------------------------+--------+------+-----------+------------------------+--------------------+ -| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 512 | +| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | 512 USB RAM | | | +------------------------+--------+------+-----------+------------------------+--------------------+ | | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | | | +----+------------------------+--------+------+-----------+------------------------+--------------------+ | | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ -| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB | +| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ -| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM | | +----+------------------------+--------+------+-----------+------------------------+--------------------+ -| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM | | | +------------------------+--------+------+-----------+------------------------+--------------------+ | | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | | | +----+------------------------+--------+------+-----------+------------------------+--------------------+ | | N6 | ✔ | ✔ | ✔ | dwc2 | | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ -| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM | | +----+------------------------+--------+------+-----------+------------------------+--------------------+ -| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB | +| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM | | | +------------------------+--------+------+-----------+------------------------+--------------------+ | | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | | | +------------------------+--------+------+-----------+------------------------+--------------------+ diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst index 12da5c90b..cacf52e1a 100644 --- a/docs/reference/boards.rst +++ b/docs/reference/boards.rst @@ -44,6 +44,9 @@ at_start_f423 AT-START-F423 at32f423 https:/ at_start_f425 AT-START-F425 at32f425 https://www.arterychip.com/en/product/AT32F425.jsp at_start_f435 AT-START-F435 at32f435_437 https://www.arterychip.com/en/product/AT32F435.jsp at_start_f437 AT-START-F437 at32f435_437 https://www.arterychip.com/en/product/AT32F437.jsp +at_start_f455 AT-START-F455 at32f45x https://www.arterychip.com/en/product/AT32F455.jsp +at_start_f456 AT-START-F456 at32f45x https://www.arterychip.com/en/product/AT32F456.jsp +at_start_f457 AT-START-F457 at32f45x https://www.arterychip.com/en/product/AT32F457.jsp ========================= ============================= ============= ==================================================== ====== Bridgetek diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst index de1603383..ce5f265d5 100644 --- a/docs/reference/dependencies.rst +++ b/docs/reference/dependencies.rst @@ -16,6 +16,7 @@ hw/mcu/artery/at32f415 https://github.com/ArteryTek/AT32F415_ hw/mcu/artery/at32f423 https://github.com/ArteryTek/AT32F423_Firmware_Library.git 2afa7f12852e57a9e8aab3a892c641e1a8635a18 at32f423 hw/mcu/artery/at32f425 https://github.com/ArteryTek/AT32F425_Firmware_Library.git 620233e1357d5c1b7e2bde6b9dd5196822b91817 at32f425 hw/mcu/artery/at32f435_437 https://github.com/ArteryTek/AT32F435_437_Firmware_Library.git 25439cc6650a8ae0345934e8707a5f38c7ae41f8 at32f435_437 +hw/mcu/artery/at32f45x https://github.com/ArteryTek/AT32F45x_Firmware_Library.git 3d4a1b38be8ebac292e2350ca53bc4bfa4430233 at32f45x hw/mcu/bridgetek/ft9xx/ft90x-sdk https://github.com/BRTSG-FOSS/ft90x-sdk.git 91060164afe239fcb394122e8bf9eb24d3194eb1 brtmm90x hw/mcu/broadcom https://github.com/adafruit/broadcom-peripherals.git 08370086080759ed54ac1136d62d2ad24c6fa267 broadcom_32bit broadcom_64bit hw/mcu/gd/nuclei-sdk https://github.com/Nuclei-Software/nuclei-sdk.git 7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7 gd32vf103 diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c index 00d059b66..fffb54d58 100644 --- a/examples/dual/host_info_to_device_cdc/src/main.c +++ b/examples/dual/host_info_to_device_cdc/src/main.c @@ -246,10 +246,9 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device->idVendor, desc_device->idProduct); uint8_t xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial)); if (XFER_RESULT_SUCCESS != xfer_result) { - serial[0] = 'n'; - serial[1] = '/'; - serial[2] = 'a'; - serial[3] = 0; + serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2)); + serial[1] = '0'; + serial[2] = 0; } print_utf16(serial, TU_ARRAY_SIZE(serial)); cdc_printf("\r\n"); diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c index 5b914a2ee..ab617e989 100644 --- a/examples/host/device_info/src/main.c +++ b/examples/host/device_info/src/main.c @@ -130,11 +130,10 @@ void tuh_mount_cb(uint8_t daddr) { } if (XFER_RESULT_SUCCESS != xfer_result) { uint16_t* serial = (uint16_t*)(uintptr_t) desc.serial; - serial[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * 3 + 2)); - serial[1] = 'n'; - serial[2] = '/'; - serial[3] = 'a'; - serial[4] = 0; + + serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2)); + serial[1] = '0'; // simply 0 + serial[2] = 0; } print_utf16((uint16_t*)(uintptr_t) desc.serial, sizeof(desc.serial)/2); printf("\r\n"); diff --git a/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..c5b89452e --- /dev/null +++ b/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,176 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ +// Include MCU header + #include "at32f45x.h" +#endif + +/* Cortex-M4 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ system_core_clock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +#ifdef __RX__ +/* Renesas RX series */ +#define vSoftwareInterruptISR INT_Excep_ICU_SWINT +#define vTickISR INT_Excep_CMT0_CMI0 +#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2) +#define configKERNEL_INTERRUPT_PRIORITY 1 +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4 + +#else + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ +#if defined(__NVIC_PRIO_BITS) + // For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h + #define configPRIO_BITS __NVIC_PRIO_BITS + +#elif defined(__ECLIC_INTCTLBITS) + // RISC-V Bumblebee core from nuclei + #define configPRIO_BITS __ECLIC_INTCTLBITS + +#elif defined(__IASMARM__) + // FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS. + // Therefore we will hard coded it to minimum value of 2 to get pass ci build. + // IAR user must update this to correct value of the target MCU + #message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU" + #define configPRIO_BITS 2 + +#else + #error "FreeRTOS configPRIO_BITS to be defined" +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1) + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + +#endif + +#endif /* __FREERTOS_CONFIG__H */ diff --git a/hw/bsp/at32f45x/at32f45x_clock.c b/hw/bsp/at32f45x/at32f45x_clock.c new file mode 100644 index 000000000..a66a8b1aa --- /dev/null +++ b/hw/bsp/at32f45x/at32f45x_clock.c @@ -0,0 +1,114 @@ +/** + ************************************************************************** + * @file at32f45x_clock.c + * @brief system clock config program + ************************************************************************** + * + * Copyright (c) 2025, Artery Technology, All rights reserved. + * + * The software Board Support Package (BSP) that is made available to + * download from Artery official website is the copyrighted work of Artery. + * Artery authorizes customers to use, copy, and distribute the BSP + * software and its related documentation for the purpose of design and + * development in conjunction with Artery microcontrollers. Use of the + * software is governed by this copyright notice and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, + * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, + * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR + * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, + * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * + ************************************************************************** + */ + +/* includes ------------------------------------------------------------------*/ +#include "at32f45x_clock.h" + +/** + * @brief system clock config program + * @note the system clock is configured as follow: + * - system clock = (hext * pll_ns)/(pll_ms * pll_fp) + * - system clock source = pll (hext) + * - hext = 8000000 + * - sclk = 192000000 + * - ahbdiv = 1 + * - ahbclk = 192000000 + * - apb2div = 1 + * - apb2clk = 192000000 + * - apb1div = 1 + * - apb1clk = 192000000 + * - pll_ns = 96 + * - pll_ms = 1 + * - pll_fp = 4 + * @param none + * @retval none + */ +void system_clock_config(void) +{ + /* reset crm */ + crm_reset(); + + /* set the flash clock divider */ + flash_psr_set(FLASH_WAIT_CYCLE_5); + + /* enable pwc periph clock */ + crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); + + /* config ldo voltage */ + pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V3); + + crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE); + + /* wait till hext is ready */ + while(crm_hext_stable_wait() == ERROR) + { + } + + /* config pll clock resource */ + crm_pll_config(CRM_PLL_SOURCE_HEXT, 96, 1, CRM_PLL_FP_4); + + /* config pllu divider */ + crm_pllu_div_set(CRM_PLL_FU_16); + + /* pllu enable */ + crm_pllu_output_set(TRUE); + + /* enable pll */ + crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE); + + /* wait till pll is ready */ + while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET) + { + } + + /* config ahbclk */ + crm_ahb_div_set(CRM_AHB_DIV_1); + + /* config apb3clk, the maximum frequency of APB3 clock is 90 MHz */ + crm_apb3_div_set(CRM_APB3_DIV_4); + + /* config apb2clk, the maximum frequency of APB2 clock is 192 MHz */ + crm_apb2_div_set(CRM_APB2_DIV_1); + + /* config apb1clk, the maximum frequency of APB1 clock is 192 MHz */ + crm_apb1_div_set(CRM_APB1_DIV_1); + + /* enable auto step mode */ + crm_auto_step_mode_enable(TRUE); + + /* select pll as system clock source */ + crm_sysclk_switch(CRM_SCLK_PLL); + + /* wait till pll is used as system clock source */ + while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL) + { + } + + /* disable auto step mode */ + crm_auto_step_mode_enable(FALSE); + + /* update system_core_clock global variable */ + system_core_clock_update(); +} diff --git a/hw/bsp/at32f45x/at32f45x_clock.h b/hw/bsp/at32f45x/at32f45x_clock.h new file mode 100644 index 000000000..a372a605b --- /dev/null +++ b/hw/bsp/at32f45x/at32f45x_clock.h @@ -0,0 +1,44 @@ +/** + ************************************************************************** + * @file at32f45x_clock.h + * @brief header file of clock program + ************************************************************************** + * + * Copyright (c) 2025, Artery Technology, All rights reserved. + * + * The software Board Support Package (BSP) that is made available to + * download from Artery official website is the copyrighted work of Artery. + * Artery authorizes customers to use, copy, and distribute the BSP + * software and its related documentation for the purpose of design and + * development in conjunction with Artery microcontrollers. Use of the + * software is governed by this copyright notice and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, + * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, + * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR + * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, + * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * + ************************************************************************** + */ + +/* define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AT32F45x_CLOCK_H +#define __AT32F45x_CLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* includes ------------------------------------------------------------------*/ +#include "at32f45x.h" + +/* exported functions ------------------------------------------------------- */ +void system_clock_config(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/at32f45x/at32f45x_conf.h b/hw/bsp/at32f45x/at32f45x_conf.h new file mode 100644 index 000000000..90182437f --- /dev/null +++ b/hw/bsp/at32f45x/at32f45x_conf.h @@ -0,0 +1,174 @@ +/** + ************************************************************************** + * @file at32f45x_conf.h + * @brief at32f45x config header file + ************************************************************************** + * + * Copyright (c) 2025, Artery Technology, All rights reserved. + * + * The software Board Support Package (BSP) that is made available to + * download from Artery official website is the copyrighted work of Artery. + * Artery authorizes customers to use, copy, and distribute the BSP + * software and its related documentation for the purpose of design and + * development in conjunction with Artery microcontrollers. Use of the + * software is governed by this copyright notice and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, + * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, + * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR + * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, + * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * + ************************************************************************** + */ + +/* define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AT32F45x_CONF_H +#define __AT32F45x_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief in the following line adjust the value of high speed external crystal (hext) + * used in your application + * + * tip: to avoid modifying this file each time you need to use different hext, you + * can define the hext value in your toolchain compiler preprocessor. + * + */ +#if !defined HEXT_VALUE +#define HEXT_VALUE ((uint32_t)8000000) /*!< value of the high speed external crystal in hz */ +#endif + +/** + * @brief in the following line adjust the high speed external crystal (hext) startup + * timeout value + */ +#define HEXT_STARTUP_TIMEOUT ((uint16_t)0x3000) /*!< time out for hext start up */ +#define HICK_VALUE ((uint32_t)8000000) /*!< value of the high speed internal clock in hz */ +#define LEXT_VALUE ((uint32_t)32768) /*!< value of the low speed external clock in hz */ + +/* module define -------------------------------------------------------------*/ +#define ACC_MODULE_ENABLED +#define ADC_MODULE_ENABLED +#define AES_MODULE_ENABLED +#define CAN_MODULE_ENABLED +#define CRC_MODULE_ENABLED +#define CRM_MODULE_ENABLED +#define DAC_MODULE_ENABLED +#define DEBUG_MODULE_ENABLED +#define DMA_MODULE_ENABLED +#define EMAC_MODULE_ENABLED +#define ERTC_MODULE_ENABLED +#define EXINT_MODULE_ENABLED +#define FLASH_MODULE_ENABLED +#define GPIO_MODULE_ENABLED +#define I2C_MODULE_ENABLED +#define MISC_MODULE_ENABLED +#define PWC_MODULE_ENABLED +#define QSPI_MODULE_ENABLED +#define SCFG_MODULE_ENABLED +#define SDIO_MODULE_ENABLED +#define SPI_MODULE_ENABLED +#define TMR_MODULE_ENABLED +#define TRNG_MODULE_ENABLED +#define USART_MODULE_ENABLED +#define USB_MODULE_ENABLED +#define WWDT_MODULE_ENABLED +#define WDT_MODULE_ENABLED +#define XMC_MODULE_ENABLED + +/* includes ------------------------------------------------------------------*/ +#ifdef ACC_MODULE_ENABLED +#include "at32f45x_acc.h" +#endif +#ifdef ADC_MODULE_ENABLED +#include "at32f45x_adc.h" +#endif +#ifdef AES_MODULE_ENABLED +#include "at32f45x_aes.h" +#endif +#ifdef CAN_MODULE_ENABLED +#include "at32f45x_can.h" +#endif +#ifdef CRC_MODULE_ENABLED +#include "at32f45x_crc.h" +#endif +#ifdef CRM_MODULE_ENABLED +#include "at32f45x_crm.h" +#endif +#ifdef DAC_MODULE_ENABLED +#include "at32f45x_dac.h" +#endif +#ifdef DEBUG_MODULE_ENABLED +#include "at32f45x_debug.h" +#endif +#ifdef DMA_MODULE_ENABLED +#include "at32f45x_dma.h" +#endif +#ifdef EMAC_MODULE_ENABLED +#include "at32f45x_emac.h" +#endif +#ifdef ERTC_MODULE_ENABLED +#include "at32f45x_ertc.h" +#endif +#ifdef EXINT_MODULE_ENABLED +#include "at32f45x_exint.h" +#endif +#ifdef FLASH_MODULE_ENABLED +#include "at32f45x_flash.h" +#endif +#ifdef GPIO_MODULE_ENABLED +#include "at32f45x_gpio.h" +#endif +#ifdef I2C_MODULE_ENABLED +#include "at32f45x_i2c.h" +#endif +#ifdef MISC_MODULE_ENABLED +#include "at32f45x_misc.h" +#endif +#ifdef PWC_MODULE_ENABLED +#include "at32f45x_pwc.h" +#endif +#ifdef QSPI_MODULE_ENABLED +#include "at32f45x_qspi.h" +#endif +#ifdef SCFG_MODULE_ENABLED +#include "at32f45x_scfg.h" +#endif +#ifdef SDIO_MODULE_ENABLED +#include "at32f45x_sdio.h" +#endif +#ifdef SPI_MODULE_ENABLED +#include "at32f45x_spi.h" +#endif +#ifdef TMR_MODULE_ENABLED +#include "at32f45x_tmr.h" +#endif +#ifdef TRNG_MODULE_ENABLED +#include "at32f45x_trng.h" +#endif +#ifdef USART_MODULE_ENABLED +#include "at32f45x_usart.h" +#endif +#ifdef USB_MODULE_ENABLED +#include "at32f45x_usb.h" +#endif +#ifdef WDT_MODULE_ENABLED +#include "at32f45x_wdt.h" +#endif +#ifdef WWDT_MODULE_ENABLED +#include "at32f45x_wwdt.h" +#endif +#ifdef XMC_MODULE_ENABLED +#include "at32f45x_xmc.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/at32f45x/at32f45x_int.c b/hw/bsp/at32f45x/at32f45x_int.c new file mode 100644 index 000000000..b3ba6ad9c --- /dev/null +++ b/hw/bsp/at32f45x/at32f45x_int.c @@ -0,0 +1,100 @@ +/** + ************************************************************************** + * @file at32f45x_int.c + * @brief main interrupt service routines. + ************************************************************************** + * + * Copyright (c) 2025, Artery Technology, All rights reserved. + * + * The software Board Support Package (BSP) that is made available to + * download from Artery official website is the copyrighted work of Artery. + * Artery authorizes customers to use, copy, and distribute the BSP + * software and its related documentation for the purpose of design and + * development in conjunction with Artery microcontrollers. Use of the + * software is governed by this copyright notice and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, + * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, + * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR + * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, + * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * + ************************************************************************** + */ + +/* includes ------------------------------------------------------------------*/ +#include "at32f45x_int.h" + +/** @addtogroup AT32F45X_BSP + * @{ + */ + +/** @addtogroup AT32F45X_USB_Device_Keyboard + * @{ + */ + +/** + * @brief this function handles nmi exception. + * @param none + * @retval none + */ +void NMI_Handler(void) +{ +} + +/** + * @brief this function handles memory manage exception. + * @param none + * @retval none + */ +void MemManage_Handler(void) +{ + /* go to infinite loop when memory manage exception occurs */ + while(1) + { + } +} + +/** + * @brief this function handles bus fault exception. + * @param none + * @retval none + */ +void BusFault_Handler(void) +{ + /* go to infinite loop when bus fault exception occurs */ + while(1) + { + } +} + +/** + * @brief this function handles usage fault exception. + * @param none + * @retval none + */ +void UsageFault_Handler(void) +{ + /* go to infinite loop when usage fault exception occurs */ + while(1) + { + } +} + +/** + * @brief this function handles debug monitor exception. + * @param none + * @retval none + */ +void DebugMon_Handler(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ diff --git a/hw/bsp/at32f45x/at32f45x_int.h b/hw/bsp/at32f45x/at32f45x_int.h new file mode 100644 index 000000000..3a2667e9d --- /dev/null +++ b/hw/bsp/at32f45x/at32f45x_int.h @@ -0,0 +1,59 @@ +/** + ************************************************************************** + * @file at32f45x_int.h + * @brief header file of main interrupt service routines. + ************************************************************************** + * + * Copyright (c) 2025, Artery Technology, All rights reserved. + * + * The software Board Support Package (BSP) that is made available to + * download from Artery official website is the copyrighted work of Artery. + * Artery authorizes customers to use, copy, and distribute the BSP + * software and its related documentation for the purpose of design and + * development in conjunction with Artery microcontrollers. Use of the + * software is governed by this copyright notice and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, + * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, + * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR + * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, + * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * + ************************************************************************** + */ + +/* define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AT32F45x_INT_H +#define __AT32F45x_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* includes ------------------------------------------------------------------*/ +#include "at32f45x.h" + +/* exported types ------------------------------------------------------------*/ +/* exported constants --------------------------------------------------------*/ +/* exported macro ------------------------------------------------------------*/ +/* exported functions ------------------------------------------------------- */ + +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + +void OTGFS1_IRQHandler(void); +void OTGFS1_WKUP_IRQHandler(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.cmake b/hw/bsp/at32f45x/boards/at_start_f455/board.cmake new file mode 100644 index 000000000..f06f9599e --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f455/board.cmake @@ -0,0 +1,8 @@ +set(MCU_VARIANT AT32F455ZET7) +set(MCU_LINKER_NAME AT32F455xE) + +set(JLINK_DEVICE ${MCU_VARIANT}) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT}) +endfunction() diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.h b/hw/bsp/at32f45x/boards/at_start_f455/board.h new file mode 100644 index 000000000..64e27c016 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f455/board.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* metadata: + name: AT-START-F455 + url: https://www.arterychip.com/en/product/AT32F455.jsp +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define USB_VBUS_IGNORE + +// LED +#define LED_PORT GPIOD +#define LED_PIN GPIO_PINS_13 +#define LED_STATE_ON 0 // Active Low +#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE) + +// Button +#define BUTTON_PORT GPIOA +#define BUTTON_PIN GPIO_PINS_0 +#define BUTTON_STATE_ACTIVE 1 +#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE) + +// UART +#define PRINT_UART USART1 +#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK +#define PRINT_UART_TX_PIN GPIO_PINS_9 +#define PRINT_UART_TX_GPIO GPIOA +#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK +#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9 +#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7 + +//USB +#define USB_ID 0 +#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK +#define OTG_IRQ OTGFS1_IRQn +#define OTG_IRQ_HANDLER OTGFS1_IRQHandler +#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn +#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler +#define OTG_WKUP_EXINT_LINE EXINT_LINE_18 +#define OTG_PIN_GPIO GPIOA +#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_DP GPIO_PINS_12 +#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12 +#define OTG_PIN_DM GPIO_PINS_11 +#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11 +#define OTG_PIN_VBUS GPIO_PINS_9 +#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9 +#define OTG_PIN_ID GPIO_PINS_10 +#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10 +#define OTG_PIN_SOF_GPIO GPIOA +#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_SOF GPIO_PINS_8 +#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8 +#define OTG_PIN_MUX GPIO_MUX_10 + +//Vbus +static inline void board_vbus_sense_init(void) +{ + *(int*)(0x50000038) |= (1<<21); +} + +#ifdef __cplusplus + } +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.mk b/hw/bsp/at32f45x/boards/at_start_f455/board.mk new file mode 100644 index 000000000..7c24ad288 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f455/board.mk @@ -0,0 +1,7 @@ +MCU_VARIANT = AT32F455ZET7 +MCU_LINKER_NAME = AT32F455xE + +JLINK_DEVICE = ${MCU_VARIANT} + +CFLAGS += \ + -D${MCU_VARIANT} diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.cmake b/hw/bsp/at32f45x/boards/at_start_f456/board.cmake new file mode 100644 index 000000000..a5048d3b1 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f456/board.cmake @@ -0,0 +1,8 @@ +set(MCU_VARIANT AT32F456ZET7) +set(MCU_LINKER_NAME AT32F456xE) + +set(JLINK_DEVICE ${MCU_VARIANT}) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT}) +endfunction() diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.h b/hw/bsp/at32f45x/boards/at_start_f456/board.h new file mode 100644 index 000000000..d3d734a9b --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f456/board.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* metadata: + name: AT-START-F456 + url: https://www.arterychip.com/en/product/AT32F456.jsp +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define USB_VBUS_IGNORE + +// LED +#define LED_PORT GPIOD +#define LED_PIN GPIO_PINS_13 +#define LED_STATE_ON 0 // Active Low +#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE) + +// Button +#define BUTTON_PORT GPIOA +#define BUTTON_PIN GPIO_PINS_0 +#define BUTTON_STATE_ACTIVE 1 +#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE) + +// UART +#define PRINT_UART USART1 +#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK +#define PRINT_UART_TX_PIN GPIO_PINS_9 +#define PRINT_UART_TX_GPIO GPIOA +#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK +#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9 +#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7 + +//USB +#define USB_ID 0 +#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK +#define OTG_IRQ OTGFS1_IRQn +#define OTG_IRQ_HANDLER OTGFS1_IRQHandler +#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn +#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler +#define OTG_WKUP_EXINT_LINE EXINT_LINE_18 +#define OTG_PIN_GPIO GPIOA +#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_DP GPIO_PINS_12 +#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12 +#define OTG_PIN_DM GPIO_PINS_11 +#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11 +#define OTG_PIN_VBUS GPIO_PINS_9 +#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9 +#define OTG_PIN_ID GPIO_PINS_10 +#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10 +#define OTG_PIN_SOF_GPIO GPIOA +#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_SOF GPIO_PINS_8 +#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8 +#define OTG_PIN_MUX GPIO_MUX_10 + +//Vbus +static inline void board_vbus_sense_init(void) +{ + *(int*)(0x50000038) |= (1<<21); +} + +#ifdef __cplusplus + } +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.mk b/hw/bsp/at32f45x/boards/at_start_f456/board.mk new file mode 100644 index 000000000..596d99d61 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f456/board.mk @@ -0,0 +1,7 @@ +MCU_VARIANT = AT32F456ZET7 +MCU_LINKER_NAME = AT32F456xE + +JLINK_DEVICE = ${MCU_VARIANT} + +CFLAGS += \ + -D${MCU_VARIANT} diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.cmake b/hw/bsp/at32f45x/boards/at_start_f457/board.cmake new file mode 100644 index 000000000..c8cd886be --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f457/board.cmake @@ -0,0 +1,8 @@ +set(MCU_VARIANT AT32F457ZET7) +set(MCU_LINKER_NAME AT32F457xE) + +set(JLINK_DEVICE ${MCU_VARIANT}) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT}) +endfunction() diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.h b/hw/bsp/at32f45x/boards/at_start_f457/board.h new file mode 100644 index 000000000..2216b1ed3 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f457/board.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* metadata: + name: AT-START-F457 + url: https://www.arterychip.com/en/product/AT32F457.jsp +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define USB_VBUS_IGNORE + +// LED +#define LED_PORT GPIOD +#define LED_PIN GPIO_PINS_13 +#define LED_STATE_ON 0 // Active Low +#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE) + +// Button +#define BUTTON_PORT GPIOA +#define BUTTON_PIN GPIO_PINS_0 +#define BUTTON_STATE_ACTIVE 1 +#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE) + +// UART +#define PRINT_UART USART1 +#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK +#define PRINT_UART_TX_PIN GPIO_PINS_9 +#define PRINT_UART_TX_GPIO GPIOA +#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK +#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9 +#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7 + +//USB +#define USB_ID 0 +#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK +#define OTG_IRQ OTGFS1_IRQn +#define OTG_IRQ_HANDLER OTGFS1_IRQHandler +#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn +#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler +#define OTG_WKUP_EXINT_LINE EXINT_LINE_18 +#define OTG_PIN_GPIO GPIOA +#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_DP GPIO_PINS_12 +#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12 +#define OTG_PIN_DM GPIO_PINS_11 +#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11 +#define OTG_PIN_VBUS GPIO_PINS_9 +#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9 +#define OTG_PIN_ID GPIO_PINS_10 +#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10 +#define OTG_PIN_SOF_GPIO GPIOA +#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK +#define OTG_PIN_SOF GPIO_PINS_8 +#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8 +#define OTG_PIN_MUX GPIO_MUX_10 + +//Vbus +static inline void board_vbus_sense_init(void) +{ + *(int*)(0x50000038) |= (1<<21); +} + +#ifdef __cplusplus + } +#endif + +#endif /* BOARD_H_ */ diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.mk b/hw/bsp/at32f45x/boards/at_start_f457/board.mk new file mode 100644 index 000000000..4cb4adad5 --- /dev/null +++ b/hw/bsp/at32f45x/boards/at_start_f457/board.mk @@ -0,0 +1,7 @@ +MCU_VARIANT = AT32F457ZET7 +MCU_LINKER_NAME = AT32F457xE + +JLINK_DEVICE = ${MCU_VARIANT} + +CFLAGS += \ + -D${MCU_VARIANT} diff --git a/hw/bsp/at32f45x/family.c b/hw/bsp/at32f45x/family.c new file mode 100644 index 000000000..0593e5115 --- /dev/null +++ b/hw/bsp/at32f45x/family.c @@ -0,0 +1,258 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* metadata: + manufacturer: Artery +*/ + +#include "at32f45x_clock.h" +#include "at32f45x_int.h" +#include "board.h" +#include "bsp/board_api.h" + +void usb_clock48m_select(usb_clk48_s clk_s); +void led_and_button_init(void); +void uart_print_init(uint32_t baudrate); +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ +void OTGFS1_IRQHandler(void) { + tusb_int_handler(0, true); +} +void OTGFS1_WKUP_IRQHandler(void) { + tusb_int_handler(0, true); +} + +void board_init(void) { + /* config nvic priority group */ + nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); + + /* config system clock */ + system_clock_config(); + + /* enable usb clock */ + crm_periph_clock_enable(OTG_CLOCK, TRUE); + + /* select usb 48m clcok source */ + usb_clock48m_select(USB_CLK_HEXT); + + /* vbus ignore */ + board_vbus_sense_init(); + + /* configure systick */ + systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV); + SysTick_Config(system_core_clock / 1000); +#if CFG_TUSB_OS == OPT_OS_FREERTOS + // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) + NVIC_SetPriority(OTG_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); +#endif + +/* otgfs use vbus pin */ +#ifndef USB_VBUS_IGNORE + gpio_init_type gpio_init_struct; + crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE); + gpio_default_para_init(&gpio_init_struct); + gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; + gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + gpio_init_struct.gpio_mode = GPIO_MODE_MUX; + gpio_init_struct.gpio_pins = OTG_PIN_VBUS; + gpio_init_struct.gpio_pull = GPIO_PULL_DOWN; + gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX); + gpio_init(OTG_PIN_GPIO, &gpio_init_struct); +#endif + + /* config led and key */ + led_and_button_init(); + + /* config usart printf */ + uart_print_init(115200); + printf("usart printf config success!\r\n"); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ +/** + * @brief usb 48M clock select + * @param clk_s:USB_CLK_HICK, USB_CLK_HEXT + * @retval none + */ +void usb_clock48m_select(usb_clk48_s clk_s) +{ + if(clk_s == USB_CLK_HICK) + { + crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK); + + /* enable the acc calibration ready interrupt */ + crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK, TRUE); + + /* update the c1\c2\c3 value */ + acc_write_c1(7980); + acc_write_c2(8000); + acc_write_c3(8020); + + /* open acc calibration */ + acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE); + } + else + { + crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_PLLU); + } +} + +void uart_print_init(uint32_t baudrate) { + gpio_init_type gpio_init_struct; + /* enable the uart and gpio clock */ + crm_periph_clock_enable(PRINT_UART_CRM_CLK, TRUE); + crm_periph_clock_enable(PRINT_UART_TX_GPIO_CRM_CLK, TRUE); + gpio_default_para_init(&gpio_init_struct); + /* configure the uart tx pin */ + gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; + gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + gpio_init_struct.gpio_mode = GPIO_MODE_MUX; + gpio_init_struct.gpio_pins = PRINT_UART_TX_PIN; + gpio_init_struct.gpio_pull = GPIO_PULL_NONE; + gpio_init(PRINT_UART_TX_GPIO, &gpio_init_struct); + gpio_pin_mux_config(PRINT_UART_TX_GPIO, PRINT_UART_TX_PIN_SOURCE, PRINT_UART_TX_PIN_MUX_NUM); + /* configure uart param */ + usart_init(PRINT_UART, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT); + usart_transmitter_enable(PRINT_UART, TRUE); + usart_enable(PRINT_UART, TRUE); +} + +void led_and_button_init(void) { + /* LED */ + gpio_init_type gpio_led_init_struct; + /* enable the led clock */ + LED_GPIO_CLK_EN(); + /* set default parameter */ + gpio_default_para_init(&gpio_led_init_struct); + /* configure the led gpio */ + gpio_led_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; + gpio_led_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + gpio_led_init_struct.gpio_mode = GPIO_MODE_OUTPUT; + gpio_led_init_struct.gpio_pins = LED_PIN; + gpio_led_init_struct.gpio_pull = GPIO_PULL_NONE; + gpio_init(LED_PORT, &gpio_led_init_struct); + /* Button */ + gpio_init_type gpio_button_init_struct; + /* enable the button clock */ + BUTTON_GPIO_CLK_EN(); + /* set default parameter */ + gpio_default_para_init(&gpio_button_init_struct); + /* configure the button gpio */ + gpio_button_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; + gpio_button_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + gpio_button_init_struct.gpio_mode = GPIO_MODE_INPUT; + gpio_button_init_struct.gpio_pins = BUTTON_PIN; + gpio_button_init_struct.gpio_pull = GPIO_PULL_DOWN; + gpio_init(BUTTON_PORT, &gpio_button_init_struct); +} + +void board_led_write(bool state) { + gpio_bits_write(LED_PORT, LED_PIN, state ^ (!LED_STATE_ON)); +} + +uint32_t board_button_read(void) { + return gpio_input_data_bit_read(BUTTON_PORT, BUTTON_PIN); +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + volatile uint32_t *at32_uuid = ((volatile uint32_t *) 0x1FFFF7E8); + uint32_t *id32 = (uint32_t *) (uintptr_t) id; + uint8_t const len = 12; + + id32[0] = at32_uuid[0]; + id32[1] = at32_uuid[1]; + id32[2] = at32_uuid[2]; + + return len; +} + +int board_uart_read(uint8_t *buf, int len) { + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const *buf, int len) { +#if CFG_TUSB_OS == OPT_OS_NONE + int txsize = len; + uint16_t timeout = 0xffff; + while (txsize--) { + while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { + timeout--; + if (timeout == 0) { + return 0; + } + } + PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); + buf++; + } + return len; +#else + (void) buf; + (void) len; + return 0; +#endif +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; +void SysTick_Handler(void) { + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} + +void SVC_Handler(void) { +} + +void PendSV_Handler(void) { +} +#endif + +void HardFault_Handler(void) { + __asm("BKPT #0\n"); +} + +// Required by __libc_init_array in startup code if we are compiling using +// -nostdlib/-nostartfiles. +void _init(void); +void _init(void) { +} + +#ifdef USE_FULL_ASSERT +void assert_failed(const char *file, uint32_t line) { + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + e.g.: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/hw/bsp/at32f45x/family.cmake b/hw/bsp/at32f45x/family.cmake new file mode 100644 index 000000000..fe13347af --- /dev/null +++ b/hw/bsp/at32f45x/family.cmake @@ -0,0 +1,97 @@ +include_guard() + +set(AT32_FAMILY at32f45x) +set(AT32_SDK_LIB ${TOP}/hw/mcu/artery/${AT32_FAMILY}/libraries) + +string(TOUPPER ${AT32_FAMILY} AT32_FAMILY_UPPER) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS ${AT32_FAMILY_UPPER} CACHE INTERNAL "") + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +set(STARTUP_FILE_GNU ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/startup_${AT32_FAMILY}.s) +set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) +set(STARTUP_FILE_IAR ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/startup_${AT32_FAMILY}.s) +if (NOT DEFINED LD_FILE_GNU) +set(LD_FILE_GNU ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/linker/${MCU_LINKER_NAME}_FLASH.ld) +endif () +set(LD_FILE_Clang ${LD_FILE_GNU}) +set(LD_FILE_IAR ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/linker/${MCU_LINKER_NAME}.icf) + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +function(family_add_board BOARD_TARGET) + add_library(${BOARD_TARGET} STATIC + ${AT32_SDK_LIB}/cmsis/cm4/device_support/system_${AT32_FAMILY}.c + ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_gpio.c + ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_misc.c + ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_usart.c + ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_acc.c + ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_crm.c + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${AT32_SDK_LIB}/cmsis/cm4/core_support + ${AT32_SDK_LIB}/cmsis/cm4/device_support + ${AT32_SDK_LIB}/drivers/inc + ) + + update_board(${BOARD_TARGET}) +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_${AT32_FAMILY_UPPER}) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_clock.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_int.c + ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c + ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c + ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_link_options(${TARGET} PUBLIC + "LINKER:--script=${LD_FILE_Clang}" + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${TARGET} PUBLIC + "LINKER:--config=${LD_FILE_IAR}" + ) + endif () + + set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES + SKIP_LINTING ON + COMPILE_OPTIONS -w) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_jlink(${TARGET}) +endfunction() diff --git a/hw/bsp/at32f45x/family.mk b/hw/bsp/at32f45x/family.mk new file mode 100644 index 000000000..e42f27557 --- /dev/null +++ b/hw/bsp/at32f45x/family.mk @@ -0,0 +1,40 @@ +AT32_FAMILY = at32f45x +AT32_SDK_LIB = hw/mcu/artery/${AT32_FAMILY}/libraries + +include $(TOP)/$(BOARD_PATH)/board.mk + +CPU_CORE ?= cortex-m4 + +CFLAGS_GCC += \ + -flto + +CFLAGS += \ + -DCFG_TUSB_MCU=OPT_MCU_AT32F45X \ + +LDFLAGS_GCC += \ + -flto --specs=nosys.specs -nostdlib -nostartfiles + +SRC_C += \ + src/portable/synopsys/dwc2/dcd_dwc2.c \ + src/portable/synopsys/dwc2/hcd_dwc2.c \ + src/portable/synopsys/dwc2/dwc2_common.c \ + $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_gpio.c \ + $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_misc.c \ + $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_usart.c \ + $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_crm.c \ + $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_acc.c \ + $(AT32_SDK_LIB)/cmsis/cm4/device_support/system_${AT32_FAMILY}.c + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(AT32_SDK_LIB)/drivers/inc \ + $(TOP)/$(AT32_SDK_LIB)/cmsis/cm4/core_support \ + $(TOP)/$(AT32_SDK_LIB)/cmsis/cm4/device_support + +SRC_S_GCC += ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/startup_${AT32_FAMILY}.s +SRC_S_IAR += ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/startup_${AT32_FAMILY}.s + +LD_FILE_GCC ?= ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/linker/${MCU_LINKER_NAME}_FLASH.ld +LD_FILE_IAR ?= ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/linker/${MCU_LINKER_NAME}.icf + +flash: flash-atlink diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index 1602e35eb..40eee082d 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -157,10 +157,12 @@ target_link_libraries(tinyusb_bsp INTERFACE # tinyusb_additions will hold our extra settings for examples add_library(tinyusb_additions INTERFACE) +if (PICO_PLATFORM STREQUAL rp2040) target_compile_definitions(tinyusb_additions INTERFACE PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1 PICO_RP2040_USB_DEVICE_UFRAME_FIX=1 -) + ) +endif () if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt") target_compile_definitions(tinyusb_additions INTERFACE diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 55eba81dd..be0224811 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -674,17 +674,17 @@ void audiod_init(void) { switch (i) { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 case 0: - tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, true); break; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 case 1: - tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, true); break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 case 2: - tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, true); break; #endif } @@ -716,17 +716,17 @@ void audiod_init(void) { switch (i) { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 case 0: - tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, true); break; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 case 1: - tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, true); break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 case 2: - tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, true); break; #endif } diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index d74760608..6ac1405f3 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -329,7 +329,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_ #endif -// scatter read 4 bytes from two buffers. Parameter are not checked +// scatter read 4 bytes from two buffers (LE). Parameter are not checked TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *buf1, uint8_t len1, const uint8_t *buf2, uint8_t len2) { uint32_t result = 0; @@ -348,7 +348,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *bu return result; } -// scatter write 4 bytes to two buffers. Parameter are not checked +// scatter write 4 bytes (LE) to two buffers. Parameter are not checked TU_ATTR_ALWAYS_INLINE static inline void tu_scatter_write32(uint32_t value, uint8_t *buf1, uint8_t len1, uint8_t *buf2, uint8_t len2) { for (uint8_t i = 0; i < len1; ++i) { diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index e97b6ccce..a92435912 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -59,7 +59,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) { //--------------------------------------------------------------------+ // Setup API //--------------------------------------------------------------------+ -bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) { +bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable) { // Limit index space to 2*depth - this allows for a fast "modulo" calculation // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable // only if overflow happens once (important for unsupervised DMA applications) @@ -72,7 +72,6 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si f->buffer = (uint8_t *)buffer; f->depth = depth; - f->item_size = (uint16_t)(item_size & 0x7FFFu); f->overwritable = overwritable; f->rd_idx = 0u; f->wr_idx = 0u; @@ -114,172 +113,265 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { // Pull & Push // copy data to/from fifo without updating read/write pointers //--------------------------------------------------------------------+ -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 -// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode -static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) { - // Reading full available 32 bit words from const app address - uint16_t full_words = len >> 2; - while (full_words--) { - const uint32_t tmp32 = *reg_rx; - tu_unaligned_write32(ff_buf, tmp32); - ff_buf += 4; - } +#if CFG_TUSB_FIFO_HWFIFO_API + #if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE + #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n) _hwfifo = (_const volatile void *)((uintptr_t)(_hwfifo) + _n) + #else + #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n) + #endif + + #define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE) - // Read the remaining 1-3 bytes from const app address - const uint8_t bytes_rem = len & 0x03; - if (bytes_rem) { - const uint32_t tmp32 = *reg_rx; - memcpy(ff_buf, &tmp32, bytes_rem); + #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE +static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) { + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4 + if (data_stride == 4) { + *((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src); } + #endif + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2 + if (data_stride == 2) { + *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src); + } + #endif } // Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode -static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) { - // Write full available 32 bit words to const address - uint16_t full_words = len >> 2u; - while (full_words--) { - *reg_tx = tu_unaligned_read32(ff_buf); - ff_buf += 4u; +void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) { + // Write full available 16/32 bit words to dest + const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE; + while (len >= data_stride) { + stride_write(hwfifo, src, data_stride); + src += data_stride; + len -= data_stride; + HWFIFO_ADDR_NEXT(hwfifo, ); + } + + #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS + // 16-bit access is allowed for odd bytes + if (len >= 2) { + *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src); + src += 2; + len -= 2; + HWFIFO_ADDR_NEXT_N(hwfifo, , 2); + } + #endif + + #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS + // 8-bit access is allowed for odd bytes + while (len > 0) { + *((volatile uint8_t *)hwfifo) = *src++; + len--; + HWFIFO_ADDR_NEXT_N(hwfifo, , 1); } + #else - // Write the remaining 1-3 bytes - const uint8_t bytes_rem = len & 0x03; - if (bytes_rem) { - uint32_t tmp32 = 0u; - memcpy(&tmp32, ff_buf, bytes_rem); - *reg_tx = tmp32; + // Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit + if (len > 0) { + uint32_t tmp = 0u; + memcpy(&tmp, src, len); + stride_write(hwfifo, &tmp, data_stride); + HWFIFO_ADDR_NEXT(hwfifo, ); } + #endif } -#endif + #endif -// send n items to fifo WITHOUT updating write pointer -static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, - tu_fifo_access_mode_t copy_mode) { - const uint16_t lin_count = f->depth - wr_ptr; - const uint16_t wrap_count = n - lin_count; + #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ +static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) { + (void)data_stride; // possible unused + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4 + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4 + if (data_stride == 4) + #endif + { + tu_unaligned_write32(dest, *((const volatile uint32_t *)hwfifo)); + } + #endif - uint16_t lin_bytes = lin_count * f->item_size; - uint16_t wrap_bytes = wrap_count * f->item_size; + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2 + #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2 + if (data_stride == 2) + #endif + { + tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo)); + } + #endif +} - // current buffer of fifo - uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size); +void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) { + // Reading full available 16/32-bit hwfifo and write to fifo + const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE; + while (len >= data_stride) { + stride_read(hwfifo, dest, data_stride); + dest += data_stride; + len -= data_stride; + HWFIFO_ADDR_NEXT(hwfifo, const); + } - switch (copy_mode) { - case TU_FIFO_INC_ADDR_RW8: - if (n <= lin_count) { - // Linear only - memcpy(ff_buf, app_buf, n * f->item_size); - } else { - // Wrap around - memcpy(ff_buf, app_buf, lin_bytes); // linear part - memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part - } - break; + #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS + // 16-bit access is allowed for odd bytes + if (len >= 2) { + tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo)); + dest += 2; + len -= 2; + HWFIFO_ADDR_NEXT_N(hwfifo, const, 2); + } + #endif -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 - case TU_FIFO_FIXED_ADDR_RW32: { - const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; - if (n <= lin_count) { - // Linear only - ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size); - } else { - // Wrap around + #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS + // 8-bit access is allowed for odd bytes + while (len > 0) { + *dest++ = *((const volatile uint8_t *)hwfifo); + len--; + HWFIFO_ADDR_NEXT_N(hwfifo, const, 1); + } + #else + // Read odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit + if (len > 0) { + uint32_t tmp; + stride_read(hwfifo, &tmp, data_stride); + memcpy(dest, &tmp, len); + HWFIFO_ADDR_NEXT(hwfifo, const); + } + #endif +} + #endif + +// push to sw fifo from hwfifo +static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, + const tu_hwfifo_access_t *access_mode) { + uint16_t lin_bytes = f->depth - wr_ptr; + uint16_t wrap_bytes = n - lin_bytes; + uint8_t *ff_buf = f->buffer + wr_ptr; - // Write full words to linear part of buffer - uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; - ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes); - ff_buf += lin_4n_bytes; + const volatile void *hwfifo = (const volatile void *)app_buf; + if (n <= lin_bytes) { + // Linear only case + tu_hwfifo_read(hwfifo, ff_buf, n, access_mode); + } else { + // Wrap around case - // There could be odd 1-3 bytes before the wrap-around boundary - const uint8_t rem = lin_bytes & 0x03; - if (rem > 0) { - const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); - const uint32_t tmp32 = *reg_rx; - tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem); + // Write full words to linear part of buffer + const uint8_t data_stride = access_mode->data_stride; + const uint32_t odd_mask = data_stride - 1; + uint16_t lin_even = lin_bytes & ~odd_mask; + tu_hwfifo_read(hwfifo, ff_buf, lin_even, access_mode); + HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_even); + ff_buf += lin_even; - wrap_bytes -= remrem; - ff_buf = f->buffer + remrem; // wrap around - } else { - ff_buf = f->buffer; // wrap around to beginning - } + // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary + // combine it with the wrapped part to form a full word for data stride + const uint8_t lin_odd = lin_bytes & odd_mask; + if (lin_odd > 0) { + const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd); + uint8_t buf_temp[4]; + tu_hwfifo_read(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode); + HWFIFO_ADDR_NEXT(hwfifo, const); - // Write data wrapped part - if (wrap_bytes > 0) { - ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes); - } + for (uint8_t i = 0; i < lin_odd; ++i) { + ff_buf[i] = buf_temp[i]; + } + for (uint8_t i = 0; i < wrap_odd; ++i) { + f->buffer[i] = buf_temp[lin_odd + i]; } - break; + + wrap_bytes -= wrap_odd; + ff_buf = f->buffer + wrap_odd; // wrap around + } else { + ff_buf = f->buffer; // wrap around to beginning } -#endif - default: - break; // unknown mode + // Write data wrapped part + if (wrap_bytes > 0) { + tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode); + } } } -// get n items from fifo WITHOUT updating read pointer -static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_access_mode_t copy_mode) { - const uint16_t lin_count = f->depth - rd_ptr; - const uint16_t wrap_count = n - lin_count; // only used if wrapped +// pull from sw fifo to hwfifo +static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, + const tu_hwfifo_access_t *access_mode) { + uint16_t lin_bytes = f->depth - rd_ptr; + uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped + const uint8_t *ff_buf = f->buffer + rd_ptr; - uint16_t lin_bytes = lin_count * f->item_size; - uint16_t wrap_bytes = wrap_count * f->item_size; + volatile void *hwfifo = (volatile void *)app_buf; - // current buffer of fifo - const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); - - switch (copy_mode) { - case TU_FIFO_INC_ADDR_RW8: - if (n <= lin_count) { - // Linear only - memcpy(app_buf, ff_buf, n * f->item_size); - } else { - // Wrap around - memcpy(app_buf, ff_buf, lin_bytes); // linear part - memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part - } - break; - -#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 - case TU_FIFO_FIXED_ADDR_RW32: { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + if (n <= lin_bytes) { + // Linear only case + tu_hwfifo_write(hwfifo, ff_buf, n, access_mode); + } else { + // Wrap around case - if (n <= lin_count) { - // Linear only - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size); - } else { - // Wrap around case + // Read full words from linear part + const uint8_t data_stride = access_mode->data_stride; + const uint32_t odd_mask = data_stride - 1; + uint16_t lin_even = lin_bytes & ~odd_mask; + tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode); + HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even); + ff_buf += lin_even; - // Read full words from linear part - uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes); - ff_buf += lin_4n_bytes; + // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary + const uint8_t lin_odd = lin_bytes & odd_mask; + if (lin_odd > 0) { + const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd); - // There could be odd 1-3 bytes before the wrap-around boundary - const uint8_t rem = lin_bytes & 0x03; - if (rem > 0) { - const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); - const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem); + uint8_t buf_temp[4]; + for (uint8_t i = 0; i < lin_odd; ++i) { + buf_temp[i] = ff_buf[i]; + } + for (uint8_t i = 0; i < wrap_odd; ++i) { + buf_temp[lin_odd + i] = f->buffer[i]; + } - *reg_tx = scatter32; + tu_hwfifo_write(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode); + HWFIFO_ADDR_NEXT(hwfifo, ); - wrap_bytes -= remrem; - ff_buf = f->buffer + remrem; // wrap around - } else { - ff_buf = f->buffer; // wrap around to beginning - } + wrap_bytes -= wrap_odd; + ff_buf = f->buffer + wrap_odd; // wrap around + } else { + ff_buf = f->buffer; // wrap around to beginning + } - // Read data wrapped part - if (wrap_bytes > 0) { - ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes); - } - } - break; + // Read data wrapped part + if (wrap_bytes > 0) { + tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode); } + } +} #endif - default: - break; // unknown mode +// send n items to fifo WITHOUT updating write pointer +static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) { + uint16_t lin_bytes = f->depth - wr_ptr; + uint16_t wrap_bytes = n - lin_bytes; + uint8_t *ff_buf = f->buffer + wr_ptr; + + if (n <= lin_bytes) { + // Linear only case + memcpy(ff_buf, app_buf, n); + } else { + // Wrap around case + memcpy(ff_buf, app_buf, lin_bytes); // linear part + memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part + } +} + +// get n items from fifo WITHOUT updating read pointer +static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr) { + uint16_t lin_bytes = f->depth - rd_ptr; + uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped + const uint8_t *ff_buf = f->buffer + rd_ptr; + + // single byte access + if (n <= lin_bytes) { + // Linear only + memcpy(app_buf, ff_buf, n); + } else { + // Wrap around + memcpy(app_buf, ff_buf, lin_bytes); // linear part + memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part } } @@ -332,7 +424,7 @@ static uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { // Works on local copies of w and r // Must be protected by read mutex since in case of an overflow read pointer gets modified uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, - tu_fifo_access_mode_t access_mode) { + const tu_hwfifo_access_t *access_mode) { uint16_t count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); if (count == 0) { return 0; // nothing to peek @@ -349,7 +441,16 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui } const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - ff_pull_n(f, p_buffer, n, rd_ptr, access_mode); + +#if CFG_TUSB_FIFO_HWFIFO_API + if (access_mode != NULL) { + hwff_pull_n(f, p_buffer, n, rd_ptr, access_mode); + } else +#endif + { + (void)access_mode; + ff_pull_n(f, p_buffer, n, rd_ptr); + } return n; } @@ -357,13 +458,13 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui // Read n items without removing it from the FIFO, correct read pointer if overflowed uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { ff_lock(f->mutex_rd); - const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8); + const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, NULL); ff_unlock(f->mutex_rd); return ret; } // Read n items from fifo with access mode -uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) { +uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode) { ff_lock(f->mutex_rd); // Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable @@ -375,7 +476,8 @@ uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_f } // Write n items to fifo with access mode -uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) { +uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, + const tu_hwfifo_access_t *access_mode) { if (n == 0) { return 0; } @@ -401,8 +503,8 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, // function! Since it would end up in a race condition with read functions! if (n >= f->depth) { // Only copy last part - if (access_mode == TU_FIFO_INC_ADDR_RW8) { - buf8 += (n - f->depth) * f->item_size; + if (access_mode == NULL) { + buf8 += (n - f->depth); } else { // TODO should read from hw fifo to discard data, however reading an odd number could // accidentally discard data. @@ -437,7 +539,14 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - ff_push_n(f, buf8, n, wr_ptr, access_mode); +#if CFG_TUSB_FIFO_HWFIFO_API + if (access_mode != NULL) { + hwff_push_n(f, buf8, n, wr_ptr, access_mode); + } else +#endif + { + ff_push_n(f, buf8, n, wr_ptr); + } f->wr_idx = advance_index(f->depth, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); @@ -477,7 +586,7 @@ static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_ } const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size); + memcpy(buf, f->buffer + rd_ptr, 1); return true; } @@ -512,7 +621,7 @@ bool tu_fifo_write(tu_fifo_t *f, const void *data) { ret = false; } else { const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size); + memcpy(f->buffer + wr_ptr, data, 1); f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 2e2a0db6f..86ba59059 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -32,6 +32,25 @@ extern "C" { #endif +#include "common/tusb_common.h" +#include "osal/osal.h" + +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ +// mutex is only needed for RTOS. For OS None, we don't get preempted +#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED + +#define CFG_TUSB_FIFO_HWFIFO_API (CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO) + +#ifndef CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 0 +#endif + +#ifndef CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 +#endif + // Due to the use of unmasked pointers, this FIFO does not suffer from losing // one item slice. Furthermore, write and read operations are completely // decoupled as write and read functions do not modify a common state. Henceforth, @@ -41,17 +60,6 @@ extern "C" { // read pointers can be updated from within a DMA ISR. Overflows are detectable // within a certain number (see tu_fifo_overflow()). -#include "common/tusb_common.h" -#include "osal/osal.h" - -// mutex is only needed for RTOS -// for OS None, we don't get preempted -#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED - -#if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO - #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 -#endif - /* Write/Read "pointer" is in the range of: 0 .. depth - 1, and is used to get the fifo data. * Write/Read "index" is always in the range of: 0 .. 2*depth-1 * @@ -111,20 +119,16 @@ extern "C" { typedef struct { uint8_t *buffer; // buffer pointer uint16_t depth; // max items + bool overwritable; // overwritable when full + // 1 byte padding here - struct TU_ATTR_PACKED { - uint16_t item_size : 15; // size of each item - bool overwritable : 1; // ovwerwritable when full - }; - - volatile uint16_t wr_idx; // write index + volatile uint16_t wr_idx; // write index TODO maybe can drop volatile volatile uint16_t rd_idx; // read index #if OSAL_MUTEX_REQUIRED osal_mutex_t mutex_wr; osal_mutex_t mutex_rd; #endif - } tu_fifo_t; typedef struct { @@ -134,29 +138,32 @@ typedef struct { } linear, wrapped; } tu_fifo_buffer_info_t; -#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ - { \ - .buffer = _buffer, \ - .depth = _depth, \ - .item_size = sizeof(_type), \ - .overwritable = _overwritable, \ +// Access mode for hardware fifo read/write +typedef struct { + uint8_t data_stride; + uintptr_t param; +} tu_hwfifo_access_t; + +#define TU_FIFO_INIT(_buffer, _depth, _overwritable) \ + { \ + .buffer = _buffer, \ + .depth = _depth, \ + .overwritable = _overwritable, \ } -#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ - uint8_t _name##_buf[_depth*sizeof(_type)]; \ - tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable) +#define TU_FIFO_DEF(_name, _depth, _overwritable) \ + uint8_t _name##_buf[_depth]; \ + tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _overwritable) -// Write modes intended to allow special read and write functions to be able to -// copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others -typedef enum { - TU_FIFO_INC_ADDR_RW8, // increased address read/write by bytes - normal (default) mode - TU_FIFO_FIXED_ADDR_RW32, // fixed address read/write by 4 bytes (word). Used for STM32 access into USB hardware FIFO -} tu_fifo_access_mode_t; +// Moving data from tusb_fifo <-> USB hardware FIFOs e.g. STM32s need to use a special stride mode which reads/writes +// data in 2/4 byte chunks from/to a fixed address (USB FIFO register) instead of incrementing the address. For this use +// read/write access_mode with stride_mode = true. The STRIDE DATA and ADDR stride must be configured with +// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE //--------------------------------------------------------------------+ // Setup API //--------------------------------------------------------------------+ -bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable); +bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable); void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); void tu_fifo_clear(tu_fifo_t *f); @@ -191,7 +198,7 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info); // peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo //--------------------------------------------------------------------+ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, - tu_fifo_access_mode_t access_mode); + const tu_hwfifo_access_t *access_mode); bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer); uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n); @@ -199,10 +206,10 @@ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n); // Read API // peek() + advance read index //--------------------------------------------------------------------+ -uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode); +uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode); bool tu_fifo_read(tu_fifo_t *f, void *buffer); TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) { - return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8); + return tu_fifo_read_n_access_mode(f, buffer, n, NULL); } // discard first n items from fifo i.e advance read pointer by n with mutex @@ -212,12 +219,41 @@ uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n); //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ -uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode); +uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, const tu_hwfifo_access_t *access_mode); bool tu_fifo_write(tu_fifo_t *f, const void *data); TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) { - return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8); + return tu_fifo_write_n_access_mode(f, data, n, NULL); +} + +//--------------------------------------------------------------------+ +// Hardware FIFO API +// Special hardware FIFO/Buffer to hold USB data, usually requires certain access method these can be configured with +// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (data width) and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE (address increment) +// Note: these usually has opposite direction (read/write) to/from our software FIFO (tu_fifo_t) +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_write_from_fifo(volatile void *hwfifo, tu_fifo_t *f, uint16_t n, + const tu_hwfifo_access_t *access_mode) { + const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0}; + return tu_fifo_read_n_access_mode(f, (void *)(uintptr_t)hwfifo, n, + (access_mode != NULL) ? access_mode : &default_access); +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_read_to_fifo(const volatile void *hwfifo, tu_fifo_t *f, + uint16_t n, const tu_hwfifo_access_t *access_mode) { + const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0}; + return tu_fifo_write_n_access_mode(f, (const void *)(uintptr_t)hwfifo, n, + (access_mode != NULL) ? access_mode : &default_access); } +#if CFG_TUSB_FIFO_HWFIFO_API +// read from hwfifo to buffer +void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode); + +// write to hwfifo from buffer with access mode +void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode); + +#endif + //--------------------------------------------------------------------+ // Internal Helper Local // work on local copies of read/write indices in order to only access them once for re-entrancy diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index ebe486e40..5b9497b9a 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -184,10 +184,15 @@ //--------------------------------------------------------------------+ // ST //--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_STM32C0) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 2048u + #elif TU_CHECK_MCU(OPT_MCU_STM32F0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u #elif TU_CHECK_MCU(OPT_MCU_STM32F1) // - F102, F103 use fsdev @@ -203,7 +208,7 @@ defined(STM32F103xE) || defined(STM32F103xG) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 512u #else #error "Unsupported STM32F1 mcu" #endif @@ -218,7 +223,16 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32F3) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + + #if defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \ + defined(STM32F373xC) + #define CFG_TUSB_FSDEV_PMA_SIZE 512u + #elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \ + defined(STM32F303xD) || defined(STM32F303xE) + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u + #else + #error "Unsupported STM32F3 mcu" + #endif #elif TU_CHECK_MCU(OPT_MCU_STM32F4) #define TUP_USBIP_DWC2 @@ -244,6 +258,26 @@ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 +#elif TU_CHECK_MCU(OPT_MCU_STM32G0) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 2048u + +#elif TU_CHECK_MCU(OPT_MCU_STM32G4) + // Device controller + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u + + // TypeC controller + #define TUP_USBIP_TYPEC_STM32 + #define TUP_TYPEC_RHPORTS_NUM 1 + +#elif TU_CHECK_MCU(OPT_MCU_STM32H5) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 2048u + #elif TU_CHECK_MCU(OPT_MCU_STM32H7) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 @@ -257,35 +291,30 @@ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif -#elif TU_CHECK_MCU(OPT_MCU_STM32H5) - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 +#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6) + #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_STM32 -#elif TU_CHECK_MCU(OPT_MCU_STM32G4) - // Device controller - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_STM32 + // FS has 6, HS has 9 + #define TUP_DCD_ENDPOINT_MAX 9 - // TypeC controller - #define TUP_USBIP_TYPEC_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_TYPEC_RHPORTS_NUM 1 + // MCU with on-chip HS Phy + #define TUP_RHPORT_HIGHSPEED 1 -#elif TU_CHECK_MCU(OPT_MCU_STM32G0) - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + // Enable dcache if DMA is enabled + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 -#elif TU_CHECK_MCU(OPT_MCU_STM32C0) +#elif TU_CHECK_MCU(OPT_MCU_STM32L0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u -#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) +#elif TU_CHECK_MCU(OPT_MCU_STM32L1) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 512u #elif TU_CHECK_MCU(OPT_MCU_STM32L4) // - L4x2, L4x3 use fsdev @@ -302,28 +331,32 @@ defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u #else #error "Unsupported STM32L4 mcu" #endif -#elif TU_CHECK_MCU(OPT_MCU_STM32WB) +#elif TU_CHECK_MCU(OPT_MCU_STM32L5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE (1024u) -#elif TU_CHECK_MCU(OPT_MCU_STM32WBA) - #define TUP_USBIP_DWC2 - #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 9 - #define TUP_RHPORT_HIGHSPEED 1 +#elif TU_CHECK_MCU(OPT_MCU_STM32U0) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u + +#elif TU_CHECK_MCU(OPT_MCU_STM32U3) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_STM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 2048u #elif TU_CHECK_MCU(OPT_MCU_STM32U5) + // U535/545 use fsdev #if defined(STM32U535xx) || defined(STM32U545xx) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 - + #define CFG_TUSB_FSDEV_PMA_SIZE 2048u #else #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 @@ -338,35 +371,16 @@ #endif #endif -#elif TU_CHECK_MCU(OPT_MCU_STM32L5) - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 - -#elif TU_CHECK_MCU(OPT_MCU_STM32U0) - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 - -#elif TU_CHECK_MCU(OPT_MCU_STM32U3) +#elif TU_CHECK_MCU(OPT_MCU_STM32WB) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u -#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6) +#elif TU_CHECK_MCU(OPT_MCU_STM32WBA) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - - // FS has 6, HS has 9 - #define TUP_DCD_ENDPOINT_MAX 9 - - // MCU with on-chip HS Phy - #define TUP_RHPORT_HIGHSPEED 1 - - // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_RHPORT_HIGHSPEED 1 //--------------------------------------------------------------------+ // Sony @@ -422,10 +436,6 @@ #define TUP_MCU_MULTIPLE_CORE 1 #endif - // Disable slave if DMA is enabled - #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE - #elif TU_CHECK_MCU(OPT_MCU_ESP32P4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_ESP32 @@ -438,10 +448,6 @@ #define TUP_MCU_MULTIPLE_CORE 1 - // Disable slave if DMA is enabled - #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE - // Enable dcache if DMA is enabled #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE @@ -573,6 +579,7 @@ #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_CH32 + #define CFG_TUSB_FSDEV_PMA_SIZE 512u // default to FSDEV for device #if !defined(CFG_TUD_WCH_USBIP_USBFS) @@ -618,32 +625,17 @@ //--------------------------------------------------------------------+ // ArteryTek //--------------------------------------------------------------------+ -#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407) +#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407, OPT_MCU_AT32F413) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 - -#elif TU_CHECK_MCU(OPT_MCU_AT32F413) - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define CFG_TUSB_FSDEV_PMA_SIZE 512u #elif TU_CHECK_MCU(OPT_MCU_AT32F415) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 #define TUP_DCD_ENDPOINT_MAX 4 -#elif TU_CHECK_MCU(OPT_MCU_AT32F435_437) - #define TUP_USBIP_DWC2 - #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 - -#elif TU_CHECK_MCU(OPT_MCU_AT32F423) - #define TUP_USBIP_DWC2 - #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 - -#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405) +#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405, OPT_MCU_AT32F423, OPT_MCU_AT32F425, OPT_MCU_AT32F435_437, OPT_MCU_AT32F45X) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 #define TUP_DCD_ENDPOINT_MAX 8 @@ -655,11 +647,6 @@ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS #endif -#elif TU_CHECK_MCU(OPT_MCU_AT32F425) - #define TUP_USBIP_DWC2 - #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 - //--------------------------------------------------------------------+ // HPMicro //--------------------------------------------------------------------+ @@ -674,10 +661,7 @@ #endif -//--------------------------------------------------------------------+ // External USB controller -//--------------------------------------------------------------------+ - #if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4 * (CFG_TUH_DEVICE_MAX - 1)) @@ -689,6 +673,10 @@ // Default Values //--------------------------------------------------------------------+ +#if defined(TUP_USBIP_FSDEV) + #define TUP_DCD_ENDPOINT_MAX 8 +#endif + #ifndef TUP_MCU_MULTIPLE_CORE #define TUP_MCU_MULTIPLE_CORE 0 #endif diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index 587554e7f..c9e06361c 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -96,10 +96,12 @@ * - TU_VERIFY_1ARGS : return false if failed * - TU_VERIFY_2ARGS : return provided value if failed *------------------------------------------------------------------*/ -#define TU_VERIFY_DEFINE(_cond, _ret) \ - do { \ - if (!(_cond)) { return _ret; } \ - } while(0) +#define TU_VERIFY_DEFINE(_cond, _ret) \ + do { \ + if (!(_cond)) { \ + return _ret; \ + } \ + } while (0) #define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false) #define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret) diff --git a/src/host/usbh.c b/src/host/usbh.c index e99d9e977..a725b7c8b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1405,12 +1405,13 @@ static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_por // NOTE: due to the shared control buffer, we must complete enumerating // one device before enumerating another one. //--------------------------------------------------------------------+ -enum { // USB 2.0 specs 7.1.7 for timing - ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection - ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port - ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset - ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery - ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms +enum { // USB 2.0 specs 7.1.7 for timing + ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection + ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port + ENUM_RESET_ROOT_POST_DELAY_MS = 2, // 2 ms delay after root port reset before getting speed/status + ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset + ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery + ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms }; enum { @@ -1469,6 +1470,7 @@ static bool enum_new_device(hcd_event_t* event) { hcd_port_reset(dev0_bus->rhport); tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS); hcd_port_reset_end(dev0_bus->rhport); + tusb_time_delay_ms_api(ENUM_RESET_ROOT_POST_DELAY_MS); if (!hcd_port_connect_status(dev0_bus->rhport)) { // device unplugged while delaying diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 174136e38..6ab18ace8 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -157,21 +157,21 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd typedef struct { void (* interrupt_set)(bool enabled); + uint16_t item_size; tu_fifo_t ff; } osal_queue_def_t; typedef osal_queue_def_t* osal_queue_t; // _int_set is used as mutex in OS NONE (disable/enable USB ISR) -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - uint8_t _name##_buf[_depth*sizeof(_type)]; \ - osal_queue_def_t _name = { \ - .interrupt_set = _int_set, \ - .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ - } +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth * sizeof(_type)]; \ + osal_queue_def_t _name = {.interrupt_set = _int_set, \ + .item_size = sizeof(_type), \ + .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)} TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { - (void) tu_fifo_clear(&qdef->ff); + tu_fifo_clear(&qdef->ff); return (osal_queue_t) qdef; } @@ -184,7 +184,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v (void) msec; // not used, always behave as msec = 0 qhdl->interrupt_set(false); - const bool success = tu_fifo_read(&qhdl->ff, data); + const bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size); qhdl->interrupt_set(true); return success; @@ -195,7 +195,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void qhdl->interrupt_set(false); } - const bool success = tu_fifo_write(&qhdl->ff, data); + const bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size); if (!in_isr) { qhdl->interrupt_set(true); diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h index f5385071a..79b728e9a 100644 --- a/src/osal/osal_pico.h +++ b/src/osal/osal_pico.h @@ -47,40 +47,39 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { // Spinlock API //--------------------------------------------------------------------+ typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock -#define OSAL_SPINLOCK_DEF(_name, _int_set) \ - osal_spinlock_t _name +#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { critical_section_init(ctx); } TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { - (void) in_isr; + (void)in_isr; critical_section_enter_blocking(ctx); } TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { - (void) in_isr; + (void)in_isr; critical_section_exit(ctx); } //--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ -typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t; +typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t; -TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) { +TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) { sem_init(semdef, 0, 255); return semdef; } TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) { - (void) semd_hdl; + (void)semd_hdl; return true; // nothing to do } TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - (void) in_isr; + (void)in_isr; return sem_release(sem_hdl); } @@ -96,15 +95,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s // MUTEX API // Within tinyusb, mutex is never used in ISR context //--------------------------------------------------------------------+ -typedef struct mutex osal_mutex_def_t, * osal_mutex_t; +typedef struct mutex osal_mutex_def_t, *osal_mutex_t; -TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) { +TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { mutex_init(mdef); return mdef; } TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) { - (void) mutex_hdl; + (void)mutex_hdl; return true; // nothing to do } @@ -123,46 +122,45 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd #include "common/tusb_fifo.h" typedef struct { - tu_fifo_t ff; + uint16_t item_size; + tu_fifo_t ff; struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section } osal_queue_def_t; -typedef osal_queue_def_t* osal_queue_t; +typedef osal_queue_def_t *osal_queue_t; // role device/host is used by OS NONE for mutex (disable usb isr) only -#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ - uint8_t _name##_buf[_depth*sizeof(_type)]; \ - osal_queue_def_t _name = { \ - .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \ - } +#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ + uint8_t _name##_buf[_depth * sizeof(_type)]; \ + osal_queue_def_t _name = {.item_size = sizeof(_type), .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)} -TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { +TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { critical_section_init(&qdef->critsec); - (void) tu_fifo_clear(&qdef->ff); - return (osal_queue_t) qdef; + tu_fifo_clear(&qdef->ff); + return (osal_queue_t)qdef; } TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) { - osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl; + osal_queue_def_t *qdef = (osal_queue_def_t *)qhdl; critical_section_deinit(&qdef->critsec); return true; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) { - (void) msec; // not used, always behave as msec = 0 +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) { + (void)msec; // not used, always behave as msec = 0 critical_section_enter_blocking(&qhdl->critsec); - bool success = tu_fifo_read(&qhdl->ff, data); + bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size); critical_section_exit(&qhdl->critsec); return success; } -TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) { - (void) in_isr; +TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, const void *data, bool in_isr) { + (void)in_isr; critical_section_enter_blocking(&qhdl->critsec); - bool success = tu_fifo_write(&qhdl->ff, data); + bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size); critical_section_exit(&qhdl->critsec); return success; diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index ad20d64bd..3827be318 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -170,68 +170,6 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne } } -static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len) -{ - volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo; - uintptr_t addr = (uintptr_t)buf; - while (len >= 4) { - reg->u32 = *(uint32_t const *)addr; - addr += 4; - len -= 4; - } - if (len >= 2) { - reg->u16 = *(uint16_t const *)addr; - addr += 2; - len -= 2; - } - if (len) { - reg->u8 = *(uint8_t const *)addr; - } -} - -static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len) -{ - volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo; - uintptr_t addr = (uintptr_t)buf; - while (len >= 4) { - *(uint32_t *)addr = reg->u32; - addr += 4; - len -= 4; - } - if (len >= 2) { - *(uint16_t *)addr = reg->u16; - addr += 2; - len -= 2; - } - if (len) { - *(uint8_t *)addr = reg->u8; - } -} - -static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir) -{ - static const struct { - void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info); - void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n); - void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len); - } ops[] = { - /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet}, - /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet}, - }; - tu_fifo_buffer_info_t info; - ops[dir].tu_fifo_get_info(f, &info); - unsigned total_len = len; - len = TU_MIN(total_len, info.linear.len); - ops[dir].pipe_read_write(info.linear.ptr, fifo, len); - unsigned rem = total_len - len; - if (rem) { - len = TU_MIN(rem, info.wrapped.len); - ops[dir].pipe_read_write(info.wrapped.ptr, fifo, len); - rem -= len; - } - ops[dir].tu_fifo_advance(f, total_len - rem); -} - static void process_setup_packet(uint8_t rhport) { musb_regs_t* musb_regs = MUSB_REGS(rhport); @@ -277,9 +215,9 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem); if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN); + tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL); } else { - pipe_write_packet(buf, fifo_ptr, len); + tu_hwfifo_write(fifo_ptr, buf, len, NULL); pipe->buf = buf + len; } pipe->remaining = rem - len; @@ -308,9 +246,9 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) volatile void *fifo_ptr = &musb_regs->fifo[epnum]; if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT); + tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL); } else { - pipe_read_packet(buf, fifo_ptr, len); + tu_hwfifo_read(fifo_ptr, buf, len, NULL); pipe->buf = buf + len; } pipe->remaining = rem - len; @@ -378,7 +316,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes); volatile void *fifo_ptr = &musb_regs->fifo[0]; if (dir_in) { - pipe_write_packet(buffer, fifo_ptr, len); + tu_hwfifo_write(fifo_ptr, buffer, len, NULL); _dcd.pipe0.buf = buffer + len; _dcd.pipe0.length = len; @@ -458,7 +396,7 @@ static void process_ep0(uint8_t rhport) const unsigned rem = _dcd.pipe0.remaining; const unsigned len = TU_MIN(TU_MIN(rem, 64), vld); volatile void *fifo_ptr = &musb_regs->fifo[0]; - pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len); + tu_hwfifo_read(fifo_ptr, _dcd.pipe0.buf, len, NULL); _dcd.pipe0.remaining = rem - len; _dcd.remaining_ctrl -= len; diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 1faac2aa8..4115eecc5 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -437,7 +437,7 @@ void dcd_int_handler(uint8_t rhport) // write to EP fifo #if 0 // TODO support dcd_edpt_xfer_fifo if (xfer->ff) { - tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32); + tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, true); } else #endif @@ -471,7 +471,7 @@ void dcd_int_handler(uint8_t rhport) // Read from EP fifo #if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { - tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32); + tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, true); } else #endif diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 91b876718..ca17d6251 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -194,7 +194,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) /* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */ #if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { - tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, TU_FIFO_FIXED_ADDR_RW32); + tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, true); } else #endif @@ -696,7 +696,7 @@ void dcd_int_handler(uint8_t rhport) /* copy the data from the PC to the previously provided buffer */ #if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { - tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), TU_FIFO_FIXED_ADDR_RW32); + tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), true); } else #endif diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 15852f29f..71d5cf19c 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -39,122 +39,104 @@ #include "device/dcd.h" // Current implementation force vbus detection as always present, causing device think it is always plugged into host. -// Therefore it cannot detect disconnect event, mistaken it as suspend. +// Therefore, it cannot detect disconnect event, mistaken it as suspend. // Note: won't work if change to 0 (for now) -#define FORCE_VBUS_DETECT 1 + #define FORCE_VBUS_DETECT 1 + + #define USB_INTS_ERROR_BITS \ + (USB_INTS_ERROR_DATA_SEQ_BITS | USB_INTS_ERROR_BIT_STUFF_BITS | USB_INTS_ERROR_CRC_BITS | \ + USB_INTS_ERROR_RX_OVERFLOW_BITS | USB_INTS_ERROR_RX_TIMEOUT_BITS) /*------------------------------------------------------------------*/ /* Low level controller *------------------------------------------------------------------*/ -// Init these in dcd_init -static uint8_t* next_buffer_ptr; +// HW buffer pointer from USB buffer space (max 3840 bytes) +static uint8_t *hw_buffer_ptr; // USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in. static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2]; -// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd +// SOF may be used by remote wakeup as RESUME, this indicates whether SOF is actually used by usbd static bool _sof_enable = false; -TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) { - return &hw_endpoints[num][dir]; -} - -TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(uint8_t ep_addr) { - uint8_t num = tu_edpt_number(ep_addr); - tusb_dir_t dir = tu_edpt_dir(ep_addr); - return hw_endpoint_get_by_num(num, dir); +TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get(uint8_t epnum, tusb_dir_t dir) { + return &hw_endpoints[epnum][dir]; } -// Allocate from the USB buffer space (max 3840 bytes) -static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) { - // round up size to multiple of 64 - size = tu_round_up(ep->wMaxPacketSize, 64); - - // double buffered Bulk endpoint - if (ep->transfer_type == TUSB_XFER_BULK) { - size *= 2u; - } - - // assign buffer - ep->hw_data_buf = next_buffer_ptr; - next_buffer_ptr += size; - - hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data)); - pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf); -} - -// Enable endpoint -TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) { - uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf); - *ep->endpoint_control = reg; +TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get_by_addr(uint8_t ep_addr) { + const uint8_t num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + return hw_endpoint_get(num, dir); } // main processing for dcd_edpt_iso_activate -static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - - const uint8_t num = tu_edpt_number(ep_addr); - const tusb_dir_t dir = tu_edpt_dir(ep_addr); - - ep->ep_addr = ep_addr; - - // For device, IN is a tx transfer and OUT is an rx transfer - ep->rx = (dir == TUSB_DIR_OUT); - - ep->next_pid = 0u; +static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { + ep->ep_addr = ep_addr; + ep->next_pid = 0u; ep->wMaxPacketSize = wMaxPacketSize; - ep->transfer_type = transfer_type; - - // Every endpoint has a buffer control register in dpram - if (dir == TUSB_DIR_IN) { - ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in; - } else { - ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out; - } + ep->transfer_type = transfer_type; // Clear existing buffer control state - *ep->buffer_control = 0; - - if (num == 0) { - // EP0 has no endpoint control register because the buffer offsets are fixed - ep->endpoint_control = NULL; + io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + *buf_ctrl_reg = 0; + // allocated hw buffer + const uint8_t epnum = tu_edpt_number(ep_addr); + if (epnum == 0) { // Buffer offset is fixed (also double buffered) ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0]; } else { - // Set the endpoint control register (starts at EP1, hence num-1) - if (dir == TUSB_DIR_IN) { - ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in; - } else { - ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out; + // round up size to multiple of 64 + uint16_t size = (uint16_t)tu_round_up(wMaxPacketSize, 64); + + // double buffered Bulk endpoint + if (transfer_type == TUSB_XFER_BULK) { + size *= 2u; + + #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + ep->e15_bulk_in = true; + } + #endif } + + // assign buffer + ep->hw_data_buf = hw_buffer_ptr; + hw_buffer_ptr += size; + + hard_assert(hw_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data)); + pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf); } } -// Init, allocate buffer and enable endpoint -static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type); - const uint8_t num = tu_edpt_number(ep_addr); - if (num != 0) { - // EP0 is already enabled - hw_endpoint_alloc(ep, ep->wMaxPacketSize); - hw_endpoint_enable(ep); +static void hw_endpoint_enable(hw_endpoint_t *ep, uint8_t transfer_type) { + io_rw_32 *ctrl_reg = hwep_ctrl_reg_device(ep); + // Set endpoint control register to enable (EP0 has no endpoint control register) + if (ctrl_reg != NULL) { + const uint32_t ctrl_value = + EP_CTRL_ENABLE_BITS | ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf); + *ctrl_reg = ctrl_value; } } -static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - hw_endpoint_xfer_start(ep, buffer, total_bytes); +// Init and enable endpoint +static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { + const uint8_t epnum = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); + + hw_endpoint_init(ep, ep_addr, wMaxPacketSize, transfer_type); + hw_endpoint_enable(ep, transfer_type); } static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { // Abort any pending transfer + const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr); + const uint8_t epnum = tu_edpt_number(ep->ep_addr); + const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1)); + // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1). // Which means we are not guaranteed to safely abort pending transfer on B0 and B1. - const uint8_t dir = tu_edpt_dir(ep->ep_addr); - const uint8_t epnum = tu_edpt_number(ep->ep_addr); - const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1)); if (rp2040_chip_version() >= 2) { usb_hw_set->abort = abort_mask; while ((usb_hw->abort_done & abort_mask) != abort_mask) {} @@ -165,7 +147,8 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { buf_ctrl |= USB_BUF_CTRL_DATA1_PID; } - _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); + io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl); hw_endpoint_reset_transfer(ep); if (rp2040_chip_version() >= 2) { @@ -174,7 +157,7 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { } } -static void __tusb_irq_path_func(hw_handle_buff_status)(void) { +static void __tusb_irq_path_func(handle_hw_buff_status)(void) { uint32_t remaining_buffers = usb_hw->buf_status; pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers); uint bit = 1u; @@ -184,12 +167,13 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void) { usb_hw_clear->buf_status = bit; // IN transfer for even i, OUT transfer for odd i - struct hw_endpoint* ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN); + const uint8_t epnum = i >> 1u; + const tusb_dir_t dir = (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN; + hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); - // Continue xfer - bool done = hw_endpoint_xfer_continue(ep); + const bool done = hw_endpoint_xfer_continue(ep); if (done) { - // Notify + // Notify usbd const uint16_t xferred_len = ep->xferred_len; hw_endpoint_reset_transfer(ep); dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); @@ -204,7 +188,7 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) { // If we have finished this transfer on EP0 set pid back to 1 for next // setup transfer. Also clear a stall in case for (uint8_t dir = 0; dir < 2; dir++) { - struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir); + struct hw_endpoint *ep = hw_endpoint_get(0, dir); ep->next_pid = 1u; if (ep->active) { hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs @@ -223,11 +207,11 @@ static void __tusb_irq_path_func(reset_non_control_endpoints)(void) { tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t)); // reclaim buffer space - next_buffer_ptr = &usb_dpram->epx_data[0]; + hw_buffer_ptr = &usb_dpram->epx_data[0]; } static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { - uint32_t const status = usb_hw->ints; + const uint32_t status = usb_hw->ints; uint32_t handled = 0; if (status & USB_INTF_DEV_SOF_BITS) { @@ -240,27 +224,26 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { e15_last_sof = time_us_32(); for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++) { - struct hw_endpoint* ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN); + struct hw_endpoint *ep = hw_endpoint_get(i, TUSB_DIR_IN); // Active Bulk IN endpoint requires SOF - if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) { + if (ep->e15_bulk_in && ep->active) { keep_sof_alive = true; hw_endpoint_lock_update(ep, 1); - - // Deferred enable? if (ep->pending) { ep->pending = 0; hw_endpoint_start_next_buffer(ep); } - hw_endpoint_lock_update(ep, -1); } } #endif // disable SOF interrupt if it is used for RESUME in remote wakeup - if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS; + if (!keep_sof_alive && !_sof_enable) { + usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS; + } dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true); } @@ -269,7 +252,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { // before closing the EP, the events will be delivered in same order. if (status & USB_INTS_BUFF_STATUS_BITS) { handled |= USB_INTS_BUFF_STATUS_BITS; - hw_handle_buff_status(); + handle_hw_buff_status(); } if (status & USB_INTS_SETUP_REQ_BITS) { @@ -287,15 +270,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { #if FORCE_VBUS_DETECT == 0 // Since we force VBUS detect On, device will always think it is connected and // couldn't distinguish between disconnect and suspend - if (status & USB_INTS_DEV_CONN_DIS_BITS) - { + if (status & USB_INTS_DEV_CONN_DIS_BITS) { handled |= USB_INTS_DEV_CONN_DIS_BITS; - if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS ) - { + if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) { // Connected: nothing to do - }else - { + } else { // Disconnected dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); } @@ -315,10 +295,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS; -#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX + #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX // Only run enumeration workaround if pull up is enabled - if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix(); -#endif + if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) { + rp2040_usb_device_enumeration_fix(); + } + #endif } /* Note from pico datasheet 4.1.2.6.4 (v1.2) @@ -346,13 +328,6 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { } } -#define USB_INTS_ERROR_BITS ( \ - USB_INTS_ERROR_DATA_SEQ_BITS | \ - USB_INTS_ERROR_BIT_STUFF_BITS | \ - USB_INTS_ERROR_CRC_BITS | \ - USB_INTS_ERROR_RX_OVERFLOW_BITS | \ - USB_INTS_ERROR_RX_TIMEOUT_BITS) - /*------------------------------------------------------------------*/ /* Controller API *------------------------------------------------------------------*/ @@ -369,9 +344,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version()); // Reset hardware to default state - rp2040_usb_init(); + rp2usb_init(); -#if FORCE_VBUS_DETECT + #if FORCE_VBUS_DETECT // Force VBUS detect so the device thinks it is plugged into a host usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; #endif @@ -425,12 +400,11 @@ void dcd_int_disable(__unused uint8_t rhport) { irq_set_enabled(USBCTRL_IRQ, false); } -void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) { - assert(rhport == 0); - +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + (void)dev_addr; // Can't set device address in hardware until status xfer has complete // Send 0len complete response on EP0 IN - hw_endpoint_xfer(0x80, NULL, 0); + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } void dcd_remote_wakeup(__unused uint8_t rhport) { @@ -475,7 +449,6 @@ void dcd_sof_enable(uint8_t rhport, bool en) { /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ - void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { (void) rhport; @@ -489,7 +462,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { (void) rhport; const uint8_t xfer_type = desc_edpt->bmAttributes.xfer; - TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS); hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type); return true; } @@ -497,56 +469,57 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { // New API: Allocate packet buffer used by ISO endpoints // Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void) rhport; - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS); - hw_endpoint_alloc(ep, largest_packet_size); + (void)rhport; + struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); + hw_endpoint_init(ep, ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS); return true; } // New API: Configure and enable an ISO endpoint according to descriptor -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { - (void) rhport; - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress); +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) { + (void)rhport; + const uint8_t epnum = tu_edpt_number(ep_desc->bEndpointAddress); + const tusb_dir_t dir = tu_edpt_dir(ep_desc->bEndpointAddress); + struct hw_endpoint *ep = hw_endpoint_get(epnum, dir); TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously if (ep->active) { hw_endpoint_abort_xfer(ep); // abort any pending transfer } - ep->wMaxPacketSize = ep_desc->wMaxPacketSize; - hw_endpoint_enable(ep); + + hw_endpoint_enable(ep, TUSB_XFER_ISOCHRONOUS); return true; } void dcd_edpt_close_all(uint8_t rhport) { (void) rhport; - // may need to use EP Abort reset_non_control_endpoints(); } -bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - assert(rhport == 0); - hw_endpoint_xfer(ep_addr, buffer, total_bytes); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)rhport; + (void)is_isr; + hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr); + hw_endpoint_xfer_start(ep, buffer, total_bytes); return true; } void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; + const uint8_t epnum = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); - if (tu_edpt_number(ep_addr) == 0) { + if (epnum == 0) { // A stall on EP0 has to be armed so it can be cleared on the next setup packet - usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS - : USB_EP_STALL_ARM_EP0_OUT_BITS; + usb_hw_set->ep_stall_arm = (dir == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS; } - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - - // stall and clear current pending buffer - // may need to use EP_ABORT - _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL); + // stall and clear current pending buffer, may need to use EP_ABORT + io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + hwbuf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL); } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { @@ -557,7 +530,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { // clear stall also reset toggle to DATA0, ready for next transfer ep->next_pid = 0; - _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL); + io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + hwbuf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL); } } diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index cd8c905d5..7bf247ced 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -62,34 +62,33 @@ enum { USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS }; -static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) -{ +static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) { uint8_t num = tu_edpt_number(ep_addr); - if ( num == 0 ) return &epx; + if (num == 0) { + return &epx; + } - for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ ) - { + for (uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) { struct hw_endpoint *ep = &ep_pool[i]; - if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep; + if (ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr)) { + return ep; + } } return NULL; } -TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void) { return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB; } -TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) -{ +TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) { // If this device is different to the speed of the root device // (i.e. is a low speed device on a full speed hub) then need pre return hcd_port_speed_get(0) != tuh_speed_get(dev_addr); } -static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result) -{ +static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result) { // Mark transfer as done before we tell the tinyusb stack uint8_t dev_addr = ep->dev_addr; uint8_t ep_addr = ep->ep_addr; @@ -98,47 +97,28 @@ static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_ hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true); } -static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep) -{ +static void __tusb_irq_path_func(handle_hwbuf_status_bit)(uint bit, struct hw_endpoint *ep) { usb_hw_clear->buf_status = bit; - // EP may have been stalled? - assert(ep->active); - bool done = hw_endpoint_xfer_continue(ep); - if ( done ) - { + const bool done = hw_endpoint_xfer_continue(ep); + if (done) { hw_xfer_complete(ep, XFER_RESULT_SUCCESS); } } -static void __tusb_irq_path_func(hw_handle_buff_status)(void) -{ - uint32_t remaining_buffers = usb_hw->buf_status; - pico_trace("buf_status 0x%08lx\n", remaining_buffers); +static void __tusb_irq_path_func(handle_hwbuf_status)(void) { + uint32_t buf_status = usb_hw->buf_status; + pico_trace("buf_status 0x%08lx\n", buf_status); // Check EPX first - uint bit = 0b1; - if ( remaining_buffers & bit ) - { - remaining_buffers &= ~bit; + uint32_t bit = 1u; + if (buf_status & bit) { + buf_status &= ~bit; struct hw_endpoint * ep = &epx; - - uint32_t ep_ctrl = *ep->endpoint_control; - if ( ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS ) - { - TU_LOG(3, "Double Buffered: "); - } - else - { - TU_LOG(3, "Single Buffered: "); - } - TU_LOG_HEX(3, ep_ctrl); - - _handle_buff_status_bit(bit, ep); + handle_hwbuf_status_bit(bit, ep); } // Check "interrupt" (asynchronous) endpoints for both IN and OUT - for ( uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++ ) - { + for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && buf_status; i++) { // EPX is bit 0 & 1 // IEP1 IN is bit 2 // IEP1 OUT is bit 3 @@ -147,20 +127,17 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void) // IEP3 IN is bit 6 // IEP3 OUT is bit 7 // etc - for ( uint j = 0; j < 2; j++ ) - { + for (uint j = 0; j < 2; j++) { bit = 1 << (i * 2 + j); - if ( remaining_buffers & bit ) - { - remaining_buffers &= ~bit; - _handle_buff_status_bit(bit, &ep_pool[i]); + if (buf_status & bit) { + buf_status &= ~bit; + handle_hwbuf_status_bit(bit, &ep_pool[i]); } } } - if ( remaining_buffers ) - { - panic("Unhandled buffer %d\n", remaining_buffers); + if (buf_status) { + panic("Unhandled buffer %d\n", buf_status); } } @@ -220,7 +197,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) { handled |= USB_INTS_BUFF_STATUS_BITS; TU_LOG(2, "Buffer complete\r\n"); - hw_handle_buff_status(); + handle_hwbuf_status(); } if ( status & USB_INTS_TRANS_COMPLETE_BITS ) @@ -240,9 +217,8 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) if ( status & USB_INTS_ERROR_DATA_SEQ_BITS ) { usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS; - TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n", - tu_u32_low16(*epx.buffer_control), - tu_u32_high16(*epx.buffer_control)); + TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(*hwbuf_ctrl_reg_host(&epx)), + tu_u32_high16(*hwbuf_ctrl_reg_host(&epx))); panic("Data Seq Error \n"); } @@ -266,7 +242,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void) ep = &ep_pool[i]; if ( !ep->configured ) { - // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate + // Will be configured by hw_endpoint_init / hw_endpoint_allocate ep->interrupt_num = (uint8_t) (i - 1); return ep; } @@ -274,41 +250,31 @@ static struct hw_endpoint *_next_free_interrupt_ep(void) return ep; } -static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) -{ - struct hw_endpoint * ep = NULL; +static hw_endpoint_t *hw_endpoint_allocate(uint8_t transfer_type) { + hw_endpoint_t *ep = NULL; - if ( transfer_type != TUSB_XFER_CONTROL ) - { + if (transfer_type == TUSB_XFER_CONTROL) { + ep = &epx; + ep->hw_data_buf = &usbh_dpram->epx_data[0]; + } else { // Note: even though datasheet name these "Interrupt" endpoints. These are actually // "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation) ep = _next_free_interrupt_ep(); pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num); assert(ep); - ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl; - ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl; // 0 for epx (double buffered): TODO increase to 1024 for ISO // 2x64 for intep0 // 3x64 for intep1 // etc ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)]; } - else - { - ep = &epx; - ep->buffer_control = &usbh_dpram->epx_buf_ctrl; - ep->endpoint_control = &usbh_dpram->epx_ctrl; - ep->hw_data_buf = &usbh_dpram->epx_data[0]; - } return ep; } -static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval) -{ +static void hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, + uint8_t transfer_type, uint8_t bmInterval) { // Already has data buffer, endpoint control, and buffer control allocated at this point - assert(ep->endpoint_control); - assert(ep->buffer_control); assert(ep->hw_data_buf); uint8_t const num = tu_edpt_number(ep_addr); @@ -317,49 +283,41 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep->ep_addr = ep_addr; ep->dev_addr = dev_addr; - // For host, IN to host == RX, anything else rx == false - ep->rx = (dir == TUSB_DIR_IN); - // Response to a setup packet on EP0 starts with pid of 1 ep->next_pid = (num == 0 ? 1u : 0u); ep->wMaxPacketSize = wMaxPacketSize; - ep->transfer_type = transfer_type; - pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type); + pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, transfer_type); pico_trace("dev %d ep %02X setup buffer @ 0x%p\n", ep->dev_addr, ep->ep_addr, ep->hw_data_buf); uint dpram_offset = hw_data_offset(ep->hw_data_buf); // Bits 0-5 should be 0 assert(!(dpram_offset & 0b111111)); // Fill in endpoint control register with buffer offset - uint32_t ep_reg = EP_CTRL_ENABLE_BITS - | EP_CTRL_INTERRUPT_PER_BUFFER - | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) - | dpram_offset; - if ( bmInterval ) - { - ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); + uint32_t ctrl_value = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | + ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; + if (bmInterval) { + ctrl_value |= (uint32_t)((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); } - *ep->endpoint_control = ep_reg; - pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg); + + io_rw_32 *ctrl_reg = hwep_ctrl_reg_host(ep); + *ctrl_reg = ctrl_value; + pico_trace("endpoint control (0x%p) <- 0x%lx\n", ctrl_reg, ctrl_value); ep->configured = true; - if ( ep != &epx ) - { + if (ep != &epx) { // Endpoint has its own addr_endp and interrupt bits to be setup! // This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with: // - device address // - endpoint number / direction // - preamble - uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB)); + uint32_t reg = (uint32_t)(dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB)); - if ( dir == TUSB_DIR_OUT ) - { + if (dir == TUSB_DIR_OUT) { reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS; } - if ( need_pre(dev_addr) ) - { + if (need_pre(dev_addr)) { reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS; } usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg; @@ -367,8 +325,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t // Finally, enable interrupt that endpoint usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1); - // If it's an interrupt endpoint we need to set up the buffer control - // register + // If it's an interrupt endpoint we need to set up the buffer control register } } @@ -382,7 +339,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { assert(rhport == 0); // Reset any previous state - rp2040_usb_init(); + rp2usb_init(); // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En) usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; @@ -466,8 +423,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { // reset epx if it is currently active with unplugged device if (epx.configured && epx.active && epx.dev_addr == dev_addr) { epx.configured = false; - *epx.endpoint_control = 0; - *epx.buffer_control = 0; + *hwep_ctrl_reg_host(&epx) = 0; + *hwbuf_ctrl_reg_host(&epx) = 0; hw_endpoint_reset_transfer(&epx); } @@ -482,54 +439,41 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { // unconfigure the endpoint ep->configured = false; - *ep->endpoint_control = 0; - *ep->buffer_control = 0; + *hwep_ctrl_reg_host(ep) = 0; + *hwbuf_ctrl_reg_host(ep) = 0; hw_endpoint_reset_transfer(ep); } } } } -uint32_t hcd_frame_number(uint8_t rhport) -{ - (void) rhport; +uint32_t hcd_frame_number(uint8_t rhport) { + (void)rhport; return usb_hw->sof_rd; } -void hcd_int_enable(uint8_t rhport) -{ - (void) rhport; - assert(rhport == 0); +void hcd_int_enable(uint8_t rhport) { + (void)rhport; irq_set_enabled(USBCTRL_IRQ, true); } -void hcd_int_disable(uint8_t rhport) -{ - (void) rhport; +void hcd_int_disable(uint8_t rhport) { + (void)rhport; // todo we should check this is disabling from the correct core; note currently this is never called - assert(rhport == 0); irq_set_enabled(USBCTRL_IRQ, false); } //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) -{ - (void) rhport; - +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) { + (void)rhport; pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); - - // Allocated differently based on if it's an interrupt endpoint or not - struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); + hw_endpoint_t *ep = hw_endpoint_allocate(ep_desc->bmAttributes.xfer); TU_ASSERT(ep); - _hw_endpoint_init(ep, - dev_addr, - ep_desc->bEndpointAddress, - tu_edpt_packet_size(ep_desc), - ep_desc->bmAttributes.xfer, - ep_desc->bInterval); + hw_endpoint_init(ep, dev_addr, ep_desc->bEndpointAddress, tu_edpt_packet_size(ep_desc), ep_desc->bmAttributes.xfer, + ep_desc->bInterval); return true; } @@ -539,13 +483,12 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) { return false; // TODO not implemented yet } -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) -{ +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { (void) rhport; pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); - uint8_t const ep_num = tu_edpt_number(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); // Get appropriate ep. Either EPX or interrupt endpoint @@ -557,19 +500,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * assert(!ep->active); // Control endpoint can change direction 0x00 <-> 0x80 - if ( ep_addr != ep->ep_addr ) - { + if (ep_addr != ep->ep_addr) { assert(ep_num == 0); // Direction has flipped on endpoint control so re init it but with same properties - _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); + hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, TUSB_XFER_CONTROL, 0); } // If a normal transfer (non-interrupt) then initiate using // sie ctrl registers. Otherwise, interrupt ep registers should // already be configured - if ( ep == &epx ) - { + if (ep == &epx) { hw_endpoint_xfer_start(ep, buffer, buflen); // That has set up buffer control, endpoint control etc @@ -585,8 +526,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS; busy_wait_at_least_cycles(12); usb_hw->sie_ctrl = flags; - }else - { + } else { hw_endpoint_xfer_start(ep, buffer, buflen); } @@ -611,14 +551,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet } // Configure EP0 struct with setup info for the trans complete - struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL); + hw_endpoint_t *ep = hw_endpoint_allocate((uint8_t)TUSB_XFER_CONTROL); TU_ASSERT(ep); // EPX should be inactive assert(!ep->active); // EP0 out - _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0); + hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0); assert(ep->configured); ep->remaining_len = 8; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 9d0bd762d..8f91ecf22 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -35,20 +35,13 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTOTYPE //--------------------------------------------------------------------+ -static void _hw_endpoint_xfer_sync(struct hw_endpoint* ep); +static void hwep_xfer_sync(hw_endpoint_t *ep); -#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX - static bool e15_is_bulkin_ep(struct hw_endpoint* ep); - static bool e15_is_critical_frame_period(struct hw_endpoint* ep); -#else - #define e15_is_bulkin_ep(x) (false) - #define e15_is_critical_frame_period(x) (false) -#endif - -// if usb hardware is in host mode -TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) { - return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false; -} + #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX +static bool e15_is_critical_frame_period(struct hw_endpoint *ep); + #else + #define e15_is_critical_frame_period(x) (false) + #endif //--------------------------------------------------------------------+ // Implementation @@ -62,7 +55,7 @@ static void unaligned_memcpy(void *dst, const void *src, size_t n) { } } -void rp2040_usb_init(void) { +void rp2usb_init(void) { // Reset usb controller reset_block(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS); @@ -93,35 +86,38 @@ void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) { ep->user_buf = 0; } -void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint* ep, uint32_t and_mask, - uint32_t or_mask) { - uint32_t value = 0; +void __tusb_irq_path_func(hwbuf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) { + const bool is_host = rp2usb_is_host_mode(); + uint32_t value = 0; + uint32_t buf_ctrl = *buf_ctrl_reg; if (and_mask) { - value = *ep->buffer_control & and_mask; + value = buf_ctrl & and_mask; } if (or_mask) { value |= or_mask; if (or_mask & USB_BUF_CTRL_AVAIL) { - if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) { - panic("ep %02X was already available", ep->ep_addr); + if (buf_ctrl & USB_BUF_CTRL_AVAIL) { + panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_ctrl_reg); } - *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL; - // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control + *buf_ctrl_reg = value & ~USB_BUF_CTRL_AVAIL; + + // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, we need to + // wait at least 1/48 mhz (usb clock), 12 cycles should be good for 48*12Mhz = 576Mhz. // Don't need delay in host mode as host is in charge - if (!is_host_mode()) { + if (!is_host) { busy_wait_at_least_cycles(12); } } } - *ep->buffer_control = value; + *buf_ctrl_reg = value; } -// prepare buffer, return buffer control -static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) { - uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); +// prepare buffer, move data if tx, return buffer control +static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id, bool is_rx) { + const uint16_t buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); ep->remaining_len = (uint16_t) (ep->remaining_len - buflen); uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL; @@ -130,7 +126,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; ep->next_pid ^= 1u; - if (!ep->rx) { + if (!is_rx) { // Copy data from user buffer to hw buffer unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen); ep->user_buf += buflen; @@ -146,49 +142,73 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, buf_ctrl |= USB_BUF_CTRL_LAST; } - if (buf_id) buf_ctrl = buf_ctrl << 16; + if (buf_id) { + buf_ctrl = buf_ctrl << 16; + } return buf_ctrl; } // Prepare buffer control register value void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) { - uint32_t ep_ctrl = *ep->endpoint_control; + const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr); + + bool is_rx; + bool is_host = false; + io_rw_32 *ep_ctrl_reg; + io_rw_32 *buf_ctrl_reg; + + #if CFG_TUH_ENABLED + is_host = rp2usb_is_host_mode(); + if (is_host) { + buf_ctrl_reg = hwbuf_ctrl_reg_host(ep); + ep_ctrl_reg = hwep_ctrl_reg_host(ep); + is_rx = (dir == TUSB_DIR_IN); + } else + #endif + { + buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + ep_ctrl_reg = hwep_ctrl_reg_device(ep); + is_rx = (dir == TUSB_DIR_OUT); + } // always compute and start with buffer 0 - uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL; + uint32_t buf_ctrl = prepare_ep_buffer(ep, 0, is_rx) | USB_BUF_CTRL_SEL; - // For now: skip double buffered for OUT endpoint in Device mode, since - // host could send < 64 bytes and cause short packet on buffer0 - // NOTE: this could happen to Host mode IN endpoint - // Also, Host mode "interrupt" endpoint hardware is only single buffered, - // NOTE2: Currently Host bulk is implemented using "interrupt" endpoint - bool const is_host = is_host_mode(); - bool const force_single = (!is_host && !tu_edpt_dir(ep->ep_addr)) || - (is_host && tu_edpt_number(ep->ep_addr) != 0); + // EP0 has no endpoint control register, also usbd only schedule 1 packet at a time (single buffer) + if (ep_ctrl_reg != NULL) { + uint32_t ep_ctrl = *ep_ctrl_reg; - if (ep->remaining_len && !force_single) { - // Use buffer 1 (double buffered) if there is still data - // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) + // For now: skip double buffered for RX e.g OUT endpoint in Device mode, since host could send < 64 bytes and cause + // short packet on buffer0 + // NOTE: this could happen to Host mode IN endpoint Also, Host mode "interrupt" endpoint hardware is only single + // buffered, + // NOTE2: Currently Host bulk is implemented using "interrupt" endpoint + const bool force_single = (!is_host && is_rx) || (is_host && tu_edpt_number(ep->ep_addr) != 0); - buf_ctrl |= prepare_ep_buffer(ep, 1); + if (ep->remaining_len && !force_single) { + // Use buffer 1 (double buffered) if there is still data + // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) - // Set endpoint control double buffered bit if needed - ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; - ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; - } else { - // Single buffered since 1 is enough - ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); - ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; - } + buf_ctrl |= prepare_ep_buffer(ep, 1, is_rx); + + // Set endpoint control double buffered bit if needed + ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; + ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; + } else { + // Single buffered since 1 is enough + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + } - *ep->endpoint_control = ep_ctrl; + *ep_ctrl_reg = ep_ctrl; + } TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl)); // Finally, write to buffer_control which will trigger the transfer // the next time the controller polls this dpram address - _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); + hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl); } void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) { @@ -206,13 +226,16 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to ep->active = true; ep->user_buf = buffer; - if (e15_is_bulkin_ep(ep)) { + #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX + if (ep->e15_bulk_in) { usb_hw_set->inte = USB_INTS_DEV_SOF_BITS; } if (e15_is_critical_frame_period(ep)) { - ep->pending = 1; - } else { + ep->pending = 1; // skip transfer if we are in critical frame period + } else + #endif + { hw_endpoint_start_next_buffer(ep); } @@ -220,13 +243,16 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to } // sync endpoint buffer and return transferred bytes -static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) { - uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); - if (buf_id) buf_ctrl = buf_ctrl >> 16; +static uint16_t __tusb_irq_path_func(sync_ep_buffer)(hw_endpoint_t *ep, io_rw_32 *buf_ctrl_reg, uint8_t buf_id, + bool is_rx) { + uint32_t buf_ctrl = *buf_ctrl_reg; + if (buf_id) { + buf_ctrl = buf_ctrl >> 16; + } - uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; + const uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; - if (!ep->rx) { + if (!is_rx) { // We are continuing a transfer here. If we are TX, we have successfully // sent some data can increase the length we have sent assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); @@ -244,7 +270,6 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin // Short packet if (xferred_bytes < ep->wMaxPacketSize) { - pico_trace(" Short packet on buffer %d with %u bytes\r\n", buf_id, xferred_bytes); // Reduce total length as this is last packet ep->remaining_len = 0; } @@ -252,21 +277,38 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin return xferred_bytes; } -static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep) { - // Update hw endpoint struct with info from hardware - // after a buff status interrupt +// Update hw endpoint struct with info from hardware after a buff status interrupt +static void __tusb_irq_path_func(hwep_xfer_sync)(hw_endpoint_t *ep) { + // const uint8_t ep_num = tu_edpt_number(ep->ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr); - uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); - TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl)); + io_rw_32 *buf_ctrl_reg; + io_rw_32 *ep_ctrl_reg; + bool is_rx; - // always sync buffer 0 - uint16_t buf0_bytes = sync_ep_buffer(ep, 0); + #if CFG_TUH_ENABLED + const bool is_host = rp2usb_is_host_mode(); + if (is_host) { + buf_ctrl_reg = hwbuf_ctrl_reg_host(ep); + ep_ctrl_reg = hwep_ctrl_reg_host(ep); + is_rx = (dir == TUSB_DIR_IN); + } else + #endif + { + buf_ctrl_reg = hwbuf_ctrl_reg_device(ep); + ep_ctrl_reg = hwep_ctrl_reg_device(ep); + is_rx = (dir == TUSB_DIR_OUT); + } + + TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(*buf_ctrl_reg), + tu_u32_high16(*buf_ctrl_reg)); + uint16_t buf0_bytes = sync_ep_buffer(ep, buf_ctrl_reg, 0, is_rx); // always sync buffer 0 // sync buffer 1 if double buffered - if ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) { + if (ep_ctrl_reg != NULL && (*ep_ctrl_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS) { if (buf0_bytes == ep->wMaxPacketSize) { // sync buffer 1 if not short packet - sync_ep_buffer(ep, 1); + sync_ep_buffer(ep, buf_ctrl_reg, 1, is_rx); } else { // short packet on buffer 0 // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example @@ -287,7 +329,8 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep) ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; - _hw_endpoint_buffer_control_set_value32(ep, 0); + io_rw_32 *buf_ctrl_reg = is_host ? hwbuf_ctrl_reg_host(ep) : hwbuf_ctrl_reg_device(ep); + hwbuf_ctrl_set(buf_ctrl_reg, 0); usb_hw->abort &= ~TU_BIT(ep_id); @@ -308,7 +351,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) { } // Update EP struct from hardware state - _hw_endpoint_xfer_sync(ep); + hwep_xfer_sync(ep); // Now we have synced our state with the hardware. Is there more data to transfer? // If we are done then notify tinyusb @@ -318,9 +361,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) { hw_endpoint_lock_update(ep, -1); return true; } else { + #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX if (e15_is_critical_frame_period(ep)) { ep->pending = 1; - } else { + } else + #endif + { hw_endpoint_start_next_buffer(ep); } } @@ -335,6 +381,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) { //--------------------------------------------------------------------+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX +// E15 is fixed with RP2350 /* Don't mark IN buffers as available during the last 200us of a full-speed frame. This avoids a situation seen with the USB2.0 hub on a Raspberry @@ -354,16 +401,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) { volatile uint32_t e15_last_sof = 0; -// check if Errata 15 is needed for this endpoint i.e device bulk-in -static bool __tusb_irq_path_func(e15_is_bulkin_ep)(struct hw_endpoint* ep) { - return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN && - ep->transfer_type == TUSB_XFER_BULK); -} - // check if we need to apply Errata 15 workaround : i.e // Endpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame static bool __tusb_irq_path_func(e15_is_critical_frame_period)(struct hw_endpoint* ep) { - TU_VERIFY(e15_is_bulkin_ep(ep)); + if (!ep->e15_bulk_in) { + return false; + } /* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point. * The device state machine cannot recover from receiving an incorrect PID diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index d4d29a816..944d604bc 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -1,10 +1,6 @@ #ifndef RP2040_COMMON_H_ #define RP2040_COMMON_H_ -#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE) -#error TinyUSB device and host mode not supported at the same time -#endif - #include "common/tusb_common.h" #include "pico.h" @@ -13,17 +9,34 @@ #include "hardware/resets.h" #include "hardware/timer.h" -#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX) -#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX +#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE) + #error TinyUSB device and host mode not supported at the same time +#endif + +// E5 and E15 only apply to RP2040 +#if defined(PICO_RP2040) && PICO_RP2040 == 1 + // RP2040 E5: USB device fails to exit RESET state on busy USB bus. + #if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX) + #define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX + #endif + + // RP2040 E15: USB Device controller will hang if certain bus errors occur during an IN transfer. + #if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX) + #define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX + #endif +#endif + +#ifndef TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX + #define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX 0 #endif -#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX) -#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX +#ifndef TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX + #define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX 0 #endif #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX -#undef PICO_RP2040_USB_FAST_IRQ -#define PICO_RP2040_USB_FAST_IRQ 1 + #undef PICO_RP2040_USB_FAST_IRQ + #define PICO_RP2040_USB_FAST_IRQ 1 #endif #ifndef PICO_RP2040_USB_FAST_IRQ @@ -36,6 +49,9 @@ #define __tusb_irq_path_func(x) x #endif +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ #define usb_hw_set ((usb_hw_t *) hw_set_alias_untyped(usb_hw)) #define usb_hw_clear ((usb_hw_t *) hw_clear_alias_untyped(usb_hw)) @@ -43,61 +59,48 @@ #define pico_trace(...) TU_LOG(3, __VA_ARGS__) // Hardware information per endpoint -typedef struct hw_endpoint -{ - // Is this a valid struct - bool configured; - - // Transfer direction (i.e. IN is rx for host but tx for device) - // allows us to common up transfer functions - bool rx; - - uint8_t ep_addr; - uint8_t next_pid; - - // Endpoint control register - io_rw_32 *endpoint_control; - - // Buffer control register - io_rw_32 *buffer_control; - - // Buffer pointer in usb dpram - uint8_t *hw_data_buf; - - // User buffer in main memory - uint8_t *user_buf; - - // Current transfer information - uint16_t remaining_len; - uint16_t xferred_len; +typedef struct hw_endpoint { + uint8_t ep_addr; + uint8_t next_pid; + uint8_t transfer_type; - // Data needed from EP descriptor - uint16_t wMaxPacketSize; + bool active; // transferring data - // Endpoint is in use - bool active; +#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX + bool e15_bulk_in; // Errata15 device bulk in + uint8_t pending; // Transfer scheduled but not active +#endif - // Interrupt, bulk, etc - uint8_t transfer_type; + uint16_t wMaxPacketSize; + uint8_t *hw_data_buf; // Buffer pointer in usb dpram - // Transfer scheduled but not active - uint8_t pending; + // Current transfer information + uint8_t *user_buf; // User buffer in main memory + uint16_t remaining_len; + uint16_t xferred_len; #if CFG_TUH_ENABLED - // Only needed for host - uint8_t dev_addr; + // Is this a valid struct + bool configured; - // If interrupt endpoint - uint8_t interrupt_num; -#endif + // Only needed for host + uint8_t dev_addr; + // If interrupt endpoint + uint8_t interrupt_num; +#endif } hw_endpoint_t; #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX extern volatile uint32_t e15_last_sof; #endif -void rp2040_usb_init(void); +void rp2usb_init(void); + +// if usb hardware is in host mode +TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) { + return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false; +} void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); bool hw_endpoint_xfer_continue(struct hw_endpoint *ep); @@ -110,34 +113,60 @@ TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct // sense to have worker and IRQ on same core, however I think using critsec is about equivalent. } -void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask); +// #if CFG_TUD_ENABLED +TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_device(struct hw_endpoint *ep) { + uint8_t const epnum = tu_edpt_number(ep->ep_addr); + const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr); + if (epnum == 0) { + // EP0 has no endpoint control register because the buffer offsets are fixed and always enabled + return NULL; + } + return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_ctrl[epnum - 1].in : &usb_dpram->ep_ctrl[epnum - 1].out; +} -TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32 (struct hw_endpoint *ep) -{ - return *ep->buffer_control; +TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_device(struct hw_endpoint *ep) { + const uint8_t epnum = tu_edpt_number(ep->ep_addr); + const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr); + return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_buf_ctrl[epnum].in : &usb_dpram->ep_buf_ctrl[epnum].out; } +// #endif -TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32 (struct hw_endpoint *ep, uint32_t value) -{ - _hw_endpoint_buffer_control_update32(ep, 0, value); +#if CFG_TUH_ENABLED +TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_host(struct hw_endpoint *ep) { + if (tu_edpt_number(ep->ep_addr) == 0) { + return &usbh_dpram->epx_ctrl; + } + return &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl; } -TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32 (struct hw_endpoint *ep, uint32_t value) -{ - _hw_endpoint_buffer_control_update32(ep, ~value, value); +TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_host(struct hw_endpoint *ep) { + if (tu_edpt_number(ep->ep_addr) == 0) { + return &usbh_dpram->epx_buf_ctrl; + } + return &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl; } +#endif + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +void hwbuf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask); -TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32 (struct hw_endpoint *ep, uint32_t value) -{ - _hw_endpoint_buffer_control_update32(ep, ~value, 0); +TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) { + hwbuf_ctrl_update(buf_ctrl_reg, 0, value); } -static inline uintptr_t hw_data_offset (uint8_t *buf) -{ - // Remove usb base from buffer pointer - return (uintptr_t) buf ^ (uintptr_t) usb_dpram; +TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) { + hwbuf_ctrl_update(buf_ctrl_reg, ~value, value); } -extern const char *ep_dir_string[]; +TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) { + hwbuf_ctrl_update(buf_ctrl_reg, ~value, 0); +} + +static inline uintptr_t hw_data_offset(uint8_t *buf) { + // Remove usb base from buffer pointer + return (uintptr_t)buf ^ (uintptr_t)usb_dpram; +} #endif diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index 779c7bc3d..e2a51a5ca 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -30,25 +30,7 @@ #if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2) #include "device/dcd.h" -#include "rusb2_type.h" - -#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) - #include "rusb2_rx.h" -#elif TU_CHECK_MCU(OPT_MCU_RAXXX) - #include "rusb2_ra.h" - #if defined(RENESAS_CORTEX_M23) - #define D0FIFO CFIFO - #define D0FIFOSEL CFIFOSEL - #define D0FIFOSEL_b CFIFOSEL_b - #define D1FIFOSEL CFIFOSEL - #define D1FIFOSEL_b CFIFOSEL_b - #define D0FIFOCTR CFIFOCTR - #define D0FIFOCTR_b CFIFOCTR_b - #endif - -#else - #error "Unsupported MCU" -#endif +#include "rusb2_common.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM @@ -161,106 +143,11 @@ static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) { } //--------------------------------------------------------------------+ -// Pipe FIFO -//--------------------------------------------------------------------+ - -// Write data buffer --> hw fifo -static void pipe_write_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len) -{ - (void) rusb; - - volatile uint16_t *ff16; - volatile uint8_t *ff8; - - // Highspeed FIFO is 32-bit - if ( rusb2_is_highspeed_reg(rusb) ) { - // TODO 32-bit access for better performance - ff16 = (volatile uint16_t*) ((uintptr_t) fifo+2); - ff8 = (volatile uint8_t *) ((uintptr_t) fifo+3); - }else { - ff16 = (volatile uint16_t*) fifo; - ff8 = ((volatile uint8_t*) fifo); - } - - uint8_t const* buf8 = (uint8_t const*) buf; - - while (len >= 2) { - *ff16 = tu_unaligned_read16(buf8); - buf8 += 2; - len -= 2; - } - - if (len > 0) { - *ff8 = *buf8; - ++buf8; - } -} - -// Read data buffer <-- hw fifo -static void pipe_read_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len) -{ - (void) rusb; - - // TODO 16/32-bit access for better performance - - uint8_t *p = (uint8_t*)buf; - volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */ - while (len--) *p++ = *reg; -} - -// Write data sw fifo --> hw fifo -static void pipe_write_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) { - tu_fifo_buffer_info_t info; - tu_fifo_get_read_info(f, &info); - - uint16_t cnt_lin = tu_min16(total_len, info.linear.len); - uint16_t cnt_wrap = tu_min16(total_len - cnt_lin, info.wrapped.len); - uint16_t const cnt_written = cnt_lin + cnt_wrap; - - // Ensure only the last write is odd if total_len is odd - if (cnt_wrap == 0) { - pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin); - } else { - pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin & ~1); - - if (cnt_lin & 1) { - uint8_t glue[2] = {info.linear.ptr[cnt_lin & ~1], info.wrapped.ptr[0]}; - pipe_write_packet(rusb, glue, fifo, 2); - cnt_wrap--; - info.wrapped.ptr++; - } - - pipe_write_packet(rusb, info.wrapped.ptr, fifo, cnt_wrap); - } - tu_fifo_advance_read_pointer(f, cnt_written); -} - -// Read data sw fifo <-- hw fifo -static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) { - tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(f, &info); - - uint16_t count = tu_min16(total_len, info.linear.len); - pipe_read_packet(rusb, info.linear.ptr, fifo, count); - - uint16_t rem = total_len - count; - if (rem) { - rem = tu_min16(rem, info.wrapped.len); - pipe_read_packet(rusb, info.wrapped.ptr, fifo, rem); - count += rem; - } - - tu_fifo_advance_write_pointer(f, count); -} - -//--------------------------------------------------------------------+ // Pipe Transfer //--------------------------------------------------------------------+ - -static bool pipe0_xfer_in(rusb2_reg_t* rusb) -{ - pipe_state_t *pipe = &_dcd.pipe[0]; - const unsigned rem = pipe->remaining; +static bool pipe0_xfer_in(rusb2_reg_t *rusb) { + pipe_state_t *pipe = &_dcd.pipe[0]; + const unsigned rem = pipe->remaining; if (!rem) { pipe->buf = NULL; @@ -272,11 +159,25 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb) void *buf = pipe->buf; if (len) { + // uint16_t fifo_sel = RUSB2_CFIFOSEL_ISEL_WRITE | FIFOSEL_BIGEND; + tu_hwfifo_access_t access_mode; + access_mode.param = (uintptr_t)rusb; + // + if (rusb2_is_highspeed_reg(rusb)) { + // fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT; + access_mode.data_stride = 4u; + } else { + // fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT; + access_mode.data_stride = 2u; + } + // rusb->CFIFOSEL = fifo_sel; + // while (0 == (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) {} + if (pipe->ff) { - pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len); + tu_hwfifo_write_from_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode); } else { - pipe_write_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode); + pipe->buf = (uint8_t *)buf + len; } } @@ -288,10 +189,9 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb) return false; } -static bool pipe0_xfer_out(rusb2_reg_t* rusb) -{ - pipe_state_t *pipe = &_dcd.pipe[0]; - const unsigned rem = pipe->remaining; +static bool pipe0_xfer_out(rusb2_reg_t *rusb) { + pipe_state_t *pipe = &_dcd.pipe[0]; + const unsigned rem = pipe->remaining; const uint16_t mps = edpt0_max_packet_size(rusb); const uint16_t vld = rusb->CFIFOCTR_b.DTLN; @@ -299,11 +199,14 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb) void *buf = pipe->buf; if (len) { + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; + if (pipe->ff) { - pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len); + tu_hwfifo_read_to_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode); } else { - pipe_read_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode); + pipe->buf = (uint8_t *)buf + len; } } @@ -330,18 +233,27 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num) return true; } - rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0); - const uint16_t mps = edpt_max_packet_size(rusb, num); + const uint16_t fifo_sel = num | FIFOSEL_BIGEND; + const bool is_highspeed = rusb2_is_highspeed_reg(rusb); + if (is_highspeed) { + rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_32BIT; + } else { + rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_16BIT; + } + + const uint16_t mps = edpt_max_packet_size(rusb, num); pipe_wait_for_ready(rusb, num); - const uint16_t len = tu_min16(rem, mps); - void *buf = pipe->buf; + uint16_t len = tu_min16(rem, mps); + void *buf = pipe->buf; if (len) { + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; if (pipe->ff) { - pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len); + tu_hwfifo_write_from_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode); } else { - pipe_write_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode); + pipe->buf = (uint8_t *)buf + len; } } @@ -362,7 +274,14 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num) pipe_state_t *pipe = &_dcd.pipe[num]; const uint16_t rem = pipe->remaining; - rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT; + uint16_t fifo_sel = num | FIFOSEL_BIGEND; + if (rusb2_is_highspeed_reg(rusb)) { + fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT; + } else { + fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT; + } + rusb->D0FIFOSEL = fifo_sel; + const uint16_t mps = edpt_max_packet_size(rusb, num); pipe_wait_for_ready(rusb, num); @@ -371,11 +290,13 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num) void *buf = pipe->buf; if (len) { + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; if (pipe->ff) { - pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len); + tu_hwfifo_read_to_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode); } else { - pipe_read_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode); + pipe->buf = (uint8_t *)buf + len; } } @@ -428,28 +349,29 @@ static void process_status_completion(uint8_t rhport) dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true); } -static bool process_pipe0_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes) -{ +static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer, + uint16_t total_bytes) { + uint16_t fifo_sel = + (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND; + /* configure fifo direction and access unit settings */ - if ( ep_addr ) { - /* IN, 2 bytes */ - rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT | - (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0); - while ( !(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ) {} - } else { - /* OUT, a byte */ - rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT; - while ( rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE ) {} + if (ep_addr != 0) { + // Control IN + fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE; + } + rusb->CFIFOSEL = fifo_sel; + while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) { + // wait until ISEL_WRITE take effect } pipe_state_t *pipe = &_dcd.pipe[0]; - pipe->ff = buffer_type; - pipe->length = total_bytes; - pipe->remaining = total_bytes; + pipe->ff = buffer_type; + pipe->length = total_bytes; + pipe->remaining = total_bytes; - if ( total_bytes ) { + if (total_bytes) { pipe->buf = buffer; - if ( ep_addr ) { + if (ep_addr) { /* IN */ TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80)); pipe0_xfer_in(rusb); @@ -525,7 +447,7 @@ static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add static void process_pipe0_bemp(uint8_t rhport) { rusb2_reg_t* rusb = RUSB2_REG(rhport); - bool completed = pipe0_xfer_in(rusb); + bool completed = pipe0_xfer_in(rusb); if (completed) { pipe_state_t *pipe = &_dcd.pipe[0]; dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN), @@ -621,18 +543,20 @@ static void process_set_address(uint8_t rhport) { rusb2_reg_t* rusb = RUSB2_REG(rhport); const uint16_t addr = rusb->USBADDR_b.USBADDR; - if (!addr) return; + if (!addr) { + return; + } const tusb_control_request_t setup_packet = { #if defined(__CCRX__) .bmRequestType = { 0 }, /* Note: CCRX needs the braces over this struct member */ -#else - .bmRequestType = 0, -#endif - .bRequest = TUSB_REQ_SET_ADDRESS, - .wValue = addr, - .wIndex = 0, - .wLength = 0, + #else + .bmRequestType = 0, + #endif + .bRequest = TUSB_REQ_SET_ADDRESS, + .wValue = addr, + .wIndex = 0, + .wLength = 0, }; dcd_event_setup_received(rhport, (const uint8_t *) &setup_packet, true); @@ -899,7 +823,6 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ { (void) is_isr; // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 - TU_ASSERT(ff->item_size == 1); rusb2_reg_t* rusb = RUSB2_REG(rhport); dcd_int_disable(rhport); @@ -912,7 +835,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr); - if (!ctr) return; + if (!ctr) { + return; + } dcd_int_disable(rhport); const uint32_t pid = *ctr & 0x3; *ctr = pid | RUSB2_PIPE_CTR_PID_STALL; @@ -924,7 +849,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { rusb2_reg_t * rusb = RUSB2_REG(rhport); volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr); - if (!ctr) return; + if (!ctr) { + return; + } dcd_int_disable(rhport); *ctr = RUSB2_PIPE_CTR_SQCLR_Msk; diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index 6f6d27d0e..4c3315044 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -31,17 +31,9 @@ #include "host/hcd.h" #include "host/usbh.h" -#include "rusb2_type.h" +#include "rusb2_common.h" -#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) - #include "rusb2_rx.h" -#elif TU_CHECK_MCU(OPT_MCU_RAXXX) - #include "rusb2_ra.h" -#else - #error "Unsupported MCU" -#endif - -#define TU_RUSB2_HCD_DBG 2 + #define TU_RUSB2_HCD_DBG 2 //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -76,12 +68,10 @@ typedef struct TU_ATTR_PACKED { TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain) TU_ATTR_BIT_FIELD_ORDER_END -typedef struct -{ - bool need_reset; /* The device has not been reset after connection. */ +typedef struct { pipe_state_t pipe[PIPE_COUNT]; - uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */ - uint8_t ctl_mps[5]; /* EP0 max packet size for each device */ + uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */ + uint8_t ctl_mps[5]; /* EP0 max packet size for each device */ } hcd_data_t; //--------------------------------------------------------------------+ @@ -166,29 +156,6 @@ static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num) while (!rusb->D0FIFOCTR_b.FRDY) {} } -static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len) -{ - // NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address - volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo; - uintptr_t addr = (uintptr_t)buf; - while (len >= 2) { - reg->u16 = *(const uint16_t *)addr; - addr += 2; - len -= 2; - } - if (len) { - reg->u8 = *(const uint8_t *)addr; - ++addr; - } -} - -static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len) -{ - uint8_t *p = (uint8_t*)buf; - volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */ - while (len--) *p++ = *reg; -} - static bool pipe0_xfer_in(rusb2_reg_t* rusb) { pipe_state_t *pipe = &_hcd.pipe[0]; @@ -199,8 +166,12 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb) const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); void *buf = pipe->buf; if (len) { + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; + rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; - pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len); + // pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len); + tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode); pipe->buf = (uint8_t*)buf + len; } if (len < mps) { @@ -227,7 +198,11 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb) const unsigned len = TU_MIN(mps, rem); void *buf = pipe->buf; if (len) { - pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len); + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; + + // pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len); + tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode); pipe->buf = (uint8_t*)buf + len; } if (len < mps) { @@ -242,14 +217,24 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num) pipe_state_t *pipe = &_hcd.pipe[num]; const unsigned rem = pipe->remaining; - rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT; + uint16_t fifo_sel = num | FIFOSEL_BIGEND; + if (rusb2_is_highspeed_reg(rusb)) { + fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT; + } else { + fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT; + } + rusb->D0FIFOSEL = fifo_sel; + const unsigned mps = edpt_max_packet_size(rusb, num); pipe_wait_for_ready(rusb, num); const unsigned vld = rusb->D0FIFOCTR_b.DTLN; const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); void *buf = pipe->buf; if (len) { - pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len); + // pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len); + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; + tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode); pipe->buf = (uint8_t*)buf + len; } if (len < mps) { @@ -275,13 +260,23 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num) return true; } - rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0); + uint16_t fifo_sel = num | FIFOSEL_BIGEND; + if (rusb2_is_highspeed_reg(rusb)) { + fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT; + } else { + fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT; + } + rusb->D0FIFOSEL = fifo_sel; + const unsigned mps = edpt_max_packet_size(rusb, num); pipe_wait_for_ready(rusb, num); const unsigned len = TU_MIN(rem, mps); void *buf = pipe->buf; if (len) { - pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len); + // pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len); + tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u), + .param = (uintptr_t)rusb}; + tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode); pipe->buf = (uint8_t*)buf + len; } if (len < mps) { @@ -296,18 +291,19 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num) static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen) { (void)dev_addr; - rusb2_reg_t* rusb = RUSB2_REG(rhport); const unsigned dir_in = tu_edpt_dir(ep_addr); + uint16_t fifo_sel = + (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND; + /* configure fifo direction and access unit settings */ - if (dir_in) { /* IN, a byte */ - rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT; - while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ; - } else { /* OUT, 2 bytes */ - rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT | - (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0); - while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ; + if (dir_in == TUSB_DIR_OUT) { + fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE; + } + rusb->CFIFOSEL = fifo_sel; + while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) { + // wait until ISEL_WRITE take effect } pipe_state_t *pipe = &_hcd.pipe[0]; @@ -535,13 +531,8 @@ void hcd_int_disable(uint8_t rhport) { rusb2_int_disable(rhport); } -uint32_t hcd_frame_number(uint8_t rhport) -{ - rusb2_reg_t* rusb = RUSB2_REG(rhport); - - /* The device must be reset at least once after connection - * in order to start the frame counter. */ - if (_hcd.need_reset) hcd_port_reset(rhport); +uint32_t hcd_frame_number(uint8_t rhport) { + rusb2_reg_t *rusb = RUSB2_REG(rhport); return rusb->FRMNUM_b.FRNM; } @@ -550,32 +541,18 @@ uint32_t hcd_frame_number(uint8_t rhport) *--------------------------------------------------------------------+*/ bool hcd_port_connect_status(uint8_t rhport) { rusb2_reg_t* rusb = RUSB2_REG(rhport); - return rusb->INTSTS1_b.ATTCH ? true : false; + const uint16_t line_state = rusb->SYSSTS0 & RUSB2_SYSSTS0_LNST_Msk; + return line_state == RUSB2_SYSSTS0_LNST_FS_J || line_state == RUSB2_SYSSTS0_LNST_FS_K; } void hcd_port_reset(uint8_t rhport) { rusb2_reg_t* rusb = RUSB2_REG(rhport); - rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; - while (rusb->DCPCTR_b.PBUSY) {} - - hcd_int_disable(rhport); - rusb->DVSTCTR0_b.UACT = 0; - if (rusb->DCPCTR_b.SUREQ) { - rusb->DCPCTR_b.SUREQCLR = 1; - } - hcd_int_enable(rhport); - - /* Reset should be asserted 10-20ms. */ rusb->DVSTCTR0_b.USBRST = 1; - for (volatile int i = 0; i < 2400000; ++i) {} - rusb->DVSTCTR0_b.USBRST = 0; - - rusb->DVSTCTR0_b.UACT = 1; - _hcd.need_reset = false; } void hcd_port_reset_end(uint8_t rhport) { - (void) rhport; + rusb2_reg_t *rusb = RUSB2_REG(rhport); + rusb->DVSTCTR0_b.USBRST = 0; } tusb_speed_t hcd_port_speed_get(uint8_t rhport) { @@ -584,7 +561,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) { case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH; case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL; case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW; - default: return TUSB_SPEED_INVALID; + default: + return TUSB_SPEED_INVALID; } } @@ -802,7 +780,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (is1 & RUSB2_INTSTS1_ATTCH_Msk) { rusb->DVSTCTR0_b.UACT = 1; - _hcd.need_reset = true; rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk; hcd_event_device_attach(rhport, true); } diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c index 856f9714f..8addbe4c6 100644 --- a/src/portable/renesas/rusb2/rusb2_common.c +++ b/src/portable/renesas/rusb2/rusb2_common.c @@ -27,20 +27,19 @@ #include "tusb_option.h" #if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED) + #include "osal/osal.h" + #include "common/tusb_fifo.h" -#include "rusb2_type.h" + #include "rusb2_common.h" -#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) -#include "rusb2_rx.h" - -#elif TU_CHECK_MCU(OPT_MCU_RAXXX) -#include "rusb2_ra.h" + #if TU_CHECK_MCU(OPT_MCU_RAXXX) + #include "rusb2_ra.h" // USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP rusb2_controller_t rusb2_controller[] = { - { .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn }, + {.reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn}, #ifdef RUSB2_SUPPORT_HIGHSPEED - { .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn }, + {.reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn}, #endif }; @@ -49,10 +48,69 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum); void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) { rusb2_controller[rhport].irqnum = irqnum; } + #endif -#else - #error "Unsupported MCU" -#endif +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +static void hwfifo_set_mbw(rusb2_reg_t *rusb, uintptr_t hwfifo, uint16_t mbw) { + volatile uint16_t *fifo_sel; + if (hwfifo == (uintptr_t)&rusb->CFIFO) { + fifo_sel = &rusb->CFIFOSEL; + } else if (hwfifo == (uintptr_t)&rusb->D0FIFO) { + fifo_sel = &rusb->D0FIFOSEL; + } else if (hwfifo == (uintptr_t)&rusb->D1FIFO) { + fifo_sel = &rusb->D1FIFOSEL; + } else { + return; + } + + *fifo_sel = (*fifo_sel & ~RUSB2_CFIFOSEL_MBW_Msk) | mbw; +} + +// write to hwfifo from buffer with access mode +void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) { + rusb2_reg_t *rusb = (rusb2_reg_t *)access_mode->param; + const uint8_t *buf8 = (const uint8_t *)src; + volatile uint16_t *ff16; + volatile uint8_t *ff8; + const bool is_highspeed = rusb2_is_highspeed_reg(rusb); + if (is_highspeed) { + ff16 = (volatile uint16_t *)((uintptr_t)hwfifo + 2); + ff8 = (volatile uint8_t *)((uintptr_t)hwfifo + 3); + } else { + ff16 = (volatile uint16_t *)hwfifo; + ff8 = ((volatile uint8_t *)hwfifo); + } + + // 32-bit access for highspeed + if (is_highspeed) { + volatile uint32_t *ff32 = (volatile uint32_t *)hwfifo; + while (len >= 4) { + *ff32 = tu_unaligned_read32(buf8); + buf8 += 4; + len -= 4; + } + + if (len >= 2) { + // switch to 16-bit access + hwfifo_set_mbw(rusb, (uintptr_t)hwfifo, RUSB2_FIFOSEL_MBW_16BIT); + } + } + + // 16-bit access + while (len >= 2) { + *ff16 = tu_unaligned_read16(buf8); + buf8 += 2; + len -= 2; + } + + // 8-bit access does not need to change MBW + if (len > 0) { + *ff8 = *buf8; + ++buf8; + } +} #endif diff --git a/src/portable/renesas/rusb2/rusb2_common.h b/src/portable/renesas/rusb2/rusb2_common.h new file mode 100644 index 000000000..6b8c3d7f2 --- /dev/null +++ b/src/portable/renesas/rusb2/rusb2_common.h @@ -0,0 +1,58 @@ +/* + * 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. + */ +#pragma once + +#include "common/tusb_common.h" +#include "rusb2_type.h" + +#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) + #include "rusb2_rx.h" +#elif TU_CHECK_MCU(OPT_MCU_RAXXX) + #include "rusb2_ra.h" + + // Hack for D0FIFO definitions on RA Cortex-M23 + #if defined(RENESAS_CORTEX_M23) + #define D0FIFO CFIFO + #define D0FIFOSEL CFIFOSEL + #define D0FIFOSEL_b CFIFOSEL_b + #define D1FIFOSEL CFIFOSEL + #define D1FIFOSEL_b CFIFOSEL_b + #define D0FIFOCTR CFIFOCTR + #define D0FIFOCTR_b CFIFOCTR_b + #endif + +#else + #error "Unsupported MCU" +#endif + + +//--------------------------------------------------------------------+ +// Common +//--------------------------------------------------------------------+ + +enum { + FIFOSEL_BIGEND = (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0) +}; diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h index 71837d03c..21f116857 100644 --- a/src/portable/renesas/rusb2/rusb2_type.h +++ b/src/portable/renesas/rusb2/rusb2_type.h @@ -41,10 +41,9 @@ extern "C" { #define _ccrx_evenaccess #endif -/*--------------------------------------------------------------------*/ -/* Register Definitions */ -/*--------------------------------------------------------------------*/ - +//--------------------------------------------------------------------+ +// Register Definitions +//--------------------------------------------------------------------+ /* Start of definition of packed structs (used by the CCRX toolchain) */ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN @@ -1669,15 +1668,20 @@ TU_ATTR_BIT_FIELD_ORDER_END /*--------------------------------------------------------------------*/ /* Register Bit Utils */ /*--------------------------------------------------------------------*/ -#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */ -#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */ -#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */ -#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */ +#define RUSB2_SYSSTS0_LNST_SE0 (0) +#define RUSB2_SYSSTS0_LNST_FS_J (1u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed J state */ +#define RUSB2_SYSSTS0_LNST_FS_K (2u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed K state */ +#define RUSB2_SYSSTS0_LNST_LS_SE1 (3u << RUSB2_SYSSTS0_LNST_Pos) /* Low-speed SE1 state */ #define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */ #define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */ #define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */ +#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */ +#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */ +#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */ +#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */ + #define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */ #define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */ diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 087639d4b..22a9e4af8 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -108,11 +108,10 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \ - !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0) +#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0) -#include "device/dcd.h" -#include "fsdev_common.h" + #include "device/dcd.h" + #include "fsdev_common.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -120,25 +119,25 @@ // One of these for every EP IN & OUT, uses a bit of RAM.... typedef struct { - uint8_t *buffer; + uint8_t *buffer; tu_fifo_t *ff; - uint16_t total_len; - uint16_t queued_len; - uint16_t max_packet_size; - uint8_t ep_idx; // index for USB_EPnR register - bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask + uint16_t total_len; + uint16_t queued_len; + uint16_t max_packet_size; + uint8_t ep_idx; // index for USB_EPnR register + bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask } xfer_ctl_t; // EP allocator typedef struct { uint8_t ep_num; uint8_t ep_type; - bool allocated[2]; + bool allocated[2]; } ep_alloc_t; static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2]; static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT]; -static uint8_t remoteWakeCountdown; // When wake is requested +static uint8_t remoteWakeCountdown; // When wake is requested //--------------------------------------------------------------------+ // Prototypes @@ -152,12 +151,12 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir); // PMA allocation/access static uint16_t ep_buf_ptr; ///< Points to first free memory location static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf); -static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); static void edpt0_open(uint8_t rhport); TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) { - btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8); + btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8); } //--------------------------------------------------------------------+ @@ -171,21 +170,21 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; fsdev_core_reset(); FSDEV_REG->CNTR = 0; // Enable USB -#if !defined(FSDEV_BUS_32BIT) + #if !defined(FSDEV_BUS_32BIT) // BTABLE register does not exist any more on 32-bit bus devices FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; -#endif + #endif // Enable interrupts for device mode - FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | - USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; + FSDEV_REG->CNTR |= + USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; handle_bus_reset(rhport); @@ -236,8 +235,8 @@ static void handle_bus_reset(uint8_t rhport) { for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // Clear EP allocation status - ep_alloc_status[i].ep_num = 0xFF; - ep_alloc_status[i].ep_type = 0xFF; + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; ep_alloc_status[i].allocated[0] = false; ep_alloc_status[i].allocated[1] = false; } @@ -245,7 +244,7 @@ static void handle_bus_reset(uint8_t rhport) { // Reset PMA allocation ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; - edpt0_open(rhport); // open control endpoint (both IN & OUT) + edpt0_open(rhport); // open control endpoint (both IN & OUT) FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function } @@ -254,8 +253,8 @@ static void handle_bus_reset(uint8_t rhport) { static void handle_ctr_tx(uint32_t ep_id) { uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN); + const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN); if (ep_is_iso(ep_reg)) { // Ignore spurious interrupts that we don't schedule @@ -265,11 +264,11 @@ static void handle_ctr_tx(uint32_t ep_id) { return; } xfer->iso_in_sending = false; -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1; -#else + #else uint8_t buf_id = BTABLE_BUF_TX; -#endif + #endif btable_set_count(ep_id, buf_id, 0); } @@ -282,17 +281,17 @@ static void handle_ctr_tx(uint32_t ep_id) { static void handle_ctr_setup(uint32_t ep_id) { uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX); - uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX); - uint8_t setup_packet[8] TU_ATTR_ALIGNED(4); + uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX); + uint8_t setup_packet[8] TU_ATTR_ALIGNED(4); - fsdev_read_packet_memory(setup_packet, rx_addr, rx_count); + tu_hwfifo_read(PMA_BUF_AT(rx_addr), setup_packet, rx_count, NULL); // Clear CTR RX if another setup packet arrived before this, it will be discarded ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); // Setup packet should always be 8 bytes. If not, we probably missed the packet if (rx_count == 8) { - dcd_event_setup_received(0, (uint8_t*) setup_packet, true); + dcd_event_setup_received(0, (uint8_t *)setup_packet, true); // Hardware should reset EP0 RX/TX to NAK and both toggle to 1 } else { // Missed setup packet !!! @@ -303,29 +302,30 @@ static void handle_ctr_setup(uint32_t ep_id) { // Handle CTR interrupt for the RX/OUT direction static void handle_ctr_rx(uint32_t ep_id) { - uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; - bool const is_iso = ep_is_iso(ep_reg); - xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT); + uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD; + const bool is_iso = ep_is_iso(ep_reg); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT); uint8_t buf_id; -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 bool const dbl_buf = is_iso; -#else + #else bool const dbl_buf = false; -#endif + #endif if (dbl_buf) { buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; } else { buf_id = BTABLE_BUF_RX; } - uint16_t const rx_count = btable_get_count(ep_id, buf_id); - uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id); + const uint16_t rx_count = btable_get_count(ep_id, buf_id); + uint16_t pma_addr = (uint16_t)btable_get_addr(ep_id, buf_id); + fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(pma_addr); if (xfer->ff) { - fsdev_read_packet_memory_ff(xfer->ff, pma_addr, rx_count); + tu_hwfifo_read_to_fifo(pma_buf, xfer->ff, rx_count, NULL); } else { - fsdev_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count); + tu_hwfifo_read(pma_buf, xfer->buffer + xfer->queued_len, rx_count, NULL); } xfer->queued_len += rx_count; @@ -343,7 +343,7 @@ static void handle_ctr_rx(uint32_t ep_id) { } else { // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always if (!is_iso) { - uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + const uint16_t cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt); } ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits @@ -403,18 +403,18 @@ void dcd_int_handler(uint8_t rhport) { // loop to handle all pending CTR interrupts while (FSDEV_REG->ISTR & USB_ISTR_CTR) { // skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt - uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID; - uint32_t const ep_reg = ep_read(ep_id); + const uint32_t ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID; + const uint32_t ep_reg = ep_read(ep_id); if (ep_reg & USB_EP_CTR_RX) { - #ifdef FSDEV_BUS_32BIT + #ifdef FSDEV_BUS_32BIT /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers * Description: - * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses - * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. - * Workaround: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM + * accesses have completed. If the software responds quickly to the interrupt, the full buffer contents may not be + * correct. Workaround: * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code @@ -425,9 +425,9 @@ void dcd_int_handler(uint8_t rhport) { */ volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver while (cycle_count > 0U) { - cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) } - #endif + #endif if (ep_reg & USB_EP_SETUP) { handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet @@ -455,14 +455,13 @@ void dcd_int_handler(uint8_t rhport) { // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { +void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - uint8_t const dev_addr = (uint8_t)request->wValue; - FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr); + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { + const uint8_t dev_addr = (uint8_t)request->wValue; + FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr); } edpt0_prepare_setup(); @@ -473,15 +472,14 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req * In case of double buffering, high 16bit is the address of 2nd buffer * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ -static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) -{ - uint8_t blsize, num_block; +static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) { + uint8_t blsize, num_block; uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block); - (void) blsize; - (void) num_block; + (void)blsize; + (void)num_block; uint32_t addr = ep_buf_ptr; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer + ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer if (dbuf) { addr |= ((uint32_t)ep_buf_ptr) << 16; @@ -489,7 +487,7 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) } // Verify packet buffer is not overflowed - TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF); + TU_ASSERT(ep_buf_ptr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF); return addr; } @@ -497,35 +495,32 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) /*** * Allocate hardware endpoint */ -static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) { + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { // Check if already allocated - if (ep_alloc_status[i].allocated[dir] && - ep_alloc_status[i].ep_type == ep_type && + if (ep_alloc_status[i].allocated[dir] && ep_alloc_status[i].ep_type == ep_type && ep_alloc_status[i].ep_num == epnum) { return i; } -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS; -#else + #else bool const dbl_buf = false; -#endif + #endif // If EP of current direction is not allocated // For double-buffered mode both directions needs to be free - if (!ep_alloc_status[i].allocated[dir] && - (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) { + if (!ep_alloc_status[i].allocated[dir] && (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) { // Check if EP number is the same if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) { // One EP pair has to be the same type if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) { - ep_alloc_status[i].ep_num = epnum; - ep_alloc_status[i].ep_type = ep_type; + ep_alloc_status[i].ep_num = epnum; + ep_alloc_status[i].ep_type = ep_type; ep_alloc_status[i].allocated[dir] = true; return i; @@ -539,16 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) } void edpt0_open(uint8_t rhport) { - (void) rhport; + (void)rhport; dcd_ep_alloc(0x0, TUSB_XFER_CONTROL); dcd_ep_alloc(0x80, TUSB_XFER_CONTROL); xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; - xfer_status[0][0].ep_idx = 0; + xfer_status[0][0].ep_idx = 0; xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; - xfer_status[0][1].ep_idx = 0; + xfer_status[0][1].ep_idx = 0; uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); @@ -566,13 +561,13 @@ void edpt0_open(uint8_t rhport) { ep_write(0, ep_reg, false); } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; - uint8_t const ep_addr = desc_ep->bEndpointAddress; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - const uint16_t packet_size = tu_edpt_packet_size(desc_ep); - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer); + const uint8_t ep_addr = desc_ep->bEndpointAddress; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + const uint16_t packet_size = tu_edpt_packet_size(desc_ep); + const uint8_t ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer); TU_ASSERT(ep_idx < FSDEV_EP_COUNT); uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; @@ -596,9 +591,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { uint16_t pma_addr = dcd_pma_alloc(packet_size, false); btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); xfer->max_packet_size = packet_size; - xfer->ep_idx = ep_idx; + xfer->ep_idx = ep_idx; ep_change_status(&ep_reg, dir, EP_STAT_NAK); ep_change_dtog(&ep_reg, dir, 0); @@ -622,8 +617,8 @@ void dcd_edpt_close_all(uint8_t rhport) { // Reset endpoint ep_write(i, 0, false); // Clear EP allocation status - ep_alloc_status[i].ep_num = 0xFF; - ep_alloc_status[i].ep_type = 0xFF; + ep_alloc_status[i].ep_num = 0xFF; + ep_alloc_status[i].ep_type = 0xFF; ep_alloc_status[i].allocated[0] = false; ep_alloc_status[i].allocated[1] = false; } @@ -637,46 +632,46 @@ void dcd_edpt_close_all(uint8_t rhport) { bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); + const uint8_t ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); -#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0 - uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true); + #if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0 + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true); uint16_t pma_addr2 = pma_addr >> 16; -#else - uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false); + #else + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false); uint16_t pma_addr2 = pma_addr; -#endif + #endif -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 btable_set_addr(ep_idx, 0, pma_addr); btable_set_addr(ep_idx, 1, pma_addr2); -#else + #else btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); - (void) pma_addr2; -#endif + (void)pma_addr2; + #endif - xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); - xfer->ep_idx = ep_idx; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer->ep_idx = ep_idx; return true; } -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; - uint8_t const ep_addr = desc_ep->bEndpointAddress; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); + const uint8_t ep_addr = desc_ep->bEndpointAddress; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - uint8_t const ep_idx = xfer->ep_idx; + const uint8_t ep_idx = xfer->ep_idx; xfer->max_packet_size = tu_edpt_packet_size(desc_ep); uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX; -#if FSDEV_USE_SBUF_ISO != 0 + #if FSDEV_USE_SBUF_ISO != 0 ep_reg |= USB_EP_KIND; ep_change_status(&ep_reg, dir, EP_STAT_DISABLED); @@ -687,12 +682,12 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) } else { ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX); } -#else + #else ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED); ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); ep_change_dtog(&ep_reg, dir, 0); ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1); -#endif + #endif ep_write(ep_idx, ep_reg, true); @@ -701,28 +696,29 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) // Currently, single-buffered, and only 64 bytes at a time (max) static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { - uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR - bool const is_iso = ep_is_iso(ep_reg); + const bool is_iso = ep_is_iso(ep_reg); uint8_t buf_id; -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 bool const dbl_buf = is_iso; -#else + #else bool const dbl_buf = false; -#endif + #endif if (dbl_buf) { buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0; } else { buf_id = BTABLE_BUF_TX; } - uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id); + uint16_t addr_ptr = (uint16_t)btable_get_addr(ep_ix, buf_id); + fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(addr_ptr); if (xfer->ff) { - fsdev_write_packet_memory_ff(xfer->ff, addr_ptr, len); + tu_hwfifo_write_from_fifo(pma_buf, xfer->ff, len, NULL); } else { - fsdev_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); + tu_hwfifo_write(pma_buf, &(xfer->buffer[xfer->queued_len]), len, NULL); } xfer->queued_len += len; @@ -737,10 +733,10 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { } static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { - (void) rhport; + (void)rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - uint8_t const ep_idx = xfer->ep_idx; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + const uint8_t ep_idx = xfer->ep_idx; if (dir == TUSB_DIR_IN) { dcd_transmit_packet(xfer, ep_idx); @@ -750,11 +746,11 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size); -#if FSDEV_USE_SBUF_ISO == 0 + #if FSDEV_USE_SBUF_ISO == 0 bool const dbl_buf = ep_is_iso(ep_reg); -#else + #else bool const dbl_buf = false; -#endif + #endif if (dbl_buf) { btable_set_rx_bufsize(ep_idx, 0, cnt); btable_set_rx_bufsize(ep_idx, 1, cnt); @@ -769,29 +765,29 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; xfer->queued_len = 0; return edpt_xfer(rhport, ep_num, dir); } -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; xfer->queued_len = 0; return edpt_xfer(rhport, ep_num, dir); @@ -799,10 +795,10 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - uint8_t const ep_idx = xfer->ep_idx; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + const uint8_t ep_idx = xfer->ep_idx; uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir); @@ -814,10 +810,10 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); - uint8_t const ep_idx = xfer->ep_idx; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + const uint8_t ep_idx = xfer->ep_idx; uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir); @@ -837,7 +833,7 @@ void dcd_int_disable(uint8_t rhport) { fsdev_int_disable(rhport); } -#if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU) + #if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU) void dcd_connect(uint8_t rhport) { fsdev_connect(rhport); } @@ -845,6 +841,6 @@ void dcd_connect(uint8_t rhport) { void dcd_disconnect(uint8_t rhport) { fsdev_disconnect(rhport); } -#endif + #endif #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h index 6877dc131..e75430396 100644 --- a/src/portable/st/stm32_fsdev/fsdev_at32.h +++ b/src/portable/st/stm32_fsdev/fsdev_at32.h @@ -35,7 +35,6 @@ #endif -#define FSDEV_PMA_SIZE (512u) #define FSDEV_USE_SBUF_ISO 0 #define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL) #define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL) diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index ee0057cb4..37ea7808e 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -53,7 +53,6 @@ #pragma GCC diagnostic pop #endif -#define FSDEV_PMA_SIZE (512u) #define FSDEV_USE_SBUF_ISO 0 #define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL) #define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL) diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index 5d60ad9a2..4f127ae86 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -69,179 +69,6 @@ void fsdev_deinit(void) { } } - -//--------------------------------------------------------------------+ -// PMA read/write -//--------------------------------------------------------------------+ - -// Write to packet memory area (PMA) from user memory -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { - if (nbytes == 0) { - return true; - } - uint32_t n_write = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); - const uint8_t *src8 = src; - - while (n_write--) { - pma_buf->value = fsdevbus_unaligned_read(src8); - src8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = 0; - for(uint16_t i = 0; i < odd; i++) { - temp |= *src8++ << (i * 8); - } - pma_buf->value = temp; - } - - return true; -} - -// Read from packet memory area (PMA) to user memory. -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { - if (nbytes == 0) { - return true; - } - uint32_t n_read = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); - uint8_t *dst8 = (uint8_t *)dst; - - while (n_read--) { - fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value); - dst8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = pma_buf->value; - while (odd--) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - } - - return true; -} - -// Write to PMA from FIFO -bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { - if (wNBytes == 0) { - return true; - } - - // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - tu_fifo_buffer_info_t info; - tu_fifo_get_read_info(ff, &info); - - uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len); - uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len); - uint16_t const cnt_total = cnt_lin + cnt_wrap; - - // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); - uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); - uint8_t const *src8 = (uint8_t const*) info.linear.ptr; - - // write even linear part - fsdev_write_packet_memory(dst, src8, lin_even); - dst += lin_even; - src8 += lin_even; - - if (lin_odd == 0) { - src8 = (uint8_t const*) info.wrapped.ptr; - } else { - // Combine last linear bytes + first wrapped bytes to form fsdev bus width data - fsdev_bus_t temp = 0; - uint16_t i; - for(i = 0; i < lin_odd; i++) { - temp |= *src8++ << (i * 8); - } - - src8 = (uint8_t const*) info.wrapped.ptr; - for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { - temp |= *src8++ << (i * 8); - } - - fsdev_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE); - dst += FSDEV_BUS_SIZE; - } - - // write the rest of the wrapped part - fsdev_write_packet_memory(dst, src8, cnt_wrap); - - tu_fifo_advance_read_pointer(ff, cnt_total); - return true; -} - -// Read from PMA to FIFO -bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { - if (wNBytes == 0) { - return true; - } - - // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - // Check for first linear part - tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - - uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len); - uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len); - uint16_t cnt_total = cnt_lin + cnt_wrap; - - // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - - uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); - uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); - uint8_t *dst8 = (uint8_t *) info.linear.ptr; - - // read even linear part - fsdev_read_packet_memory(dst8, src, lin_even); - dst8 += lin_even; - src += lin_even; - - if (lin_odd == 0) { - dst8 = (uint8_t *) info.wrapped.ptr; - } else { - // Combine last linear bytes + first wrapped bytes to form fsdev bus width data - fsdev_bus_t temp; - fsdev_read_packet_memory(&temp, src, FSDEV_BUS_SIZE); - src += FSDEV_BUS_SIZE; - - uint16_t i; - for (i = 0; i < lin_odd; i++) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - - dst8 = (uint8_t *) info.wrapped.ptr; - for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - } - - // read the rest of the wrapped part - fsdev_read_packet_memory(dst8, src, cnt_wrap); - - tu_fifo_advance_write_pointer(ff, cnt_total); - return true; -} - //--------------------------------------------------------------------+ // BTable Helper //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h index 0c67ee0c7..c53e345b0 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -32,11 +32,11 @@ #include "common/tusb_common.h" #if CFG_TUD_ENABLED -#include "device/dcd.h" + #include "device/dcd.h" #endif #if CFG_TUH_ENABLED -#include "host/hcd.h" + #include "host/hcd.h" #endif #if defined(TUP_USBIP_FSDEV_STM32) @@ -56,41 +56,37 @@ extern "C" { // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. #ifndef FSDEV_BTABLE_BASE -#define FSDEV_BTABLE_BASE 0U + #define FSDEV_BTABLE_BASE 0U #endif TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes"); -// FSDEV_PMA_SIZE is PMA buffer size in bytes. +// CFG_TUSB_FSDEV_PMA_SIZE is PMA buffer size in bytes. // - 512-byte devices, access with a stride of two words (use every other 16-bit address) // - 1024-byte devices, access with a stride of one word (use every 16-bit address) // - 2048-byte devices, access with 32-bit address // For purposes of accessing the packet -#if FSDEV_PMA_SIZE == 512 +#if CFG_TUSB_FSDEV_PMA_SIZE == 512 // 1x16 bit / word access scheme #define FSDEV_PMA_STRIDE 2 #define pma_access_scheme TU_ATTR_ALIGNED(4) -#elif FSDEV_PMA_SIZE == 1024 +#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024 // 2x16 bit / word access scheme - #define FSDEV_PMA_STRIDE 1 + #define FSDEV_PMA_STRIDE 1 #define pma_access_scheme -#elif FSDEV_PMA_SIZE == 2048 +#elif CFG_TUSB_FSDEV_PMA_SIZE == 2048 // 32 bit access scheme #define FSDEV_BUS_32BIT - #define FSDEV_PMA_STRIDE 1 + #define FSDEV_PMA_STRIDE 1 #define pma_access_scheme #endif // The fsdev_bus_t type can be used for both register and PMA access necessities #ifdef FSDEV_BUS_32BIT - typedef uint32_t fsdev_bus_t; - #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr) - #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value) +typedef uint32_t fsdev_bus_t; #else - typedef uint16_t fsdev_bus_t; - #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr) - #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value) +typedef uint16_t fsdev_bus_t; #endif enum { @@ -124,77 +120,77 @@ typedef union { } ep32[FSDEV_EP_COUNT][2]; } fsdev_btable_t; -TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct"); -TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); +TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_PMA_STRIDE, "size is not correct"); +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT * 8 <= CFG_TUSB_FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); -#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE))) +#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (FSDEV_BTABLE_BASE))) typedef struct { volatile pma_access_scheme fsdev_bus_t value; } fsdev_pma_buf_t; -#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr))) +#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (_addr))) //--------------------------------------------------------------------+ // Registers Typedef //--------------------------------------------------------------------+ // volatile 32-bit aligned -#define _va32 volatile TU_ATTR_ALIGNED(4) +#define _va32 volatile TU_ATTR_ALIGNED(4) typedef struct { struct { _va32 fsdev_bus_t reg; - }ep[FSDEV_EP_COUNT]; + } ep[FSDEV_EP_COUNT]; - _va32 uint32_t RESERVED7[8]; // Reserved - _va32 fsdev_bus_t CNTR; // 40: Control register - _va32 fsdev_bus_t ISTR; // 44: Interrupt status register - _va32 fsdev_bus_t FNR; // 48: Frame number register - _va32 fsdev_bus_t DADDR; // 4C: Device address register - _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) - _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) - _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) + _va32 uint32_t RESERVED7[8]; // Reserved + _va32 fsdev_bus_t CNTR; // 40: Control register + _va32 fsdev_bus_t ISTR; // 44: Interrupt status register + _va32 fsdev_bus_t FNR; // 48: Frame number register + _va32 fsdev_bus_t DADDR; // 4C: Device address register + _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) + _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) + _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) } fsdev_regs_t; TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset"); TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct"); -#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE) +#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE) #ifndef USB_EPTX_STAT -#define USB_EPTX_STAT 0x0030U + #define USB_EPTX_STAT 0x0030U #endif #ifndef USB_EPRX_STAT -#define USB_EPRX_STAT 0x3000U + #define USB_EPRX_STAT 0x3000U #endif #ifndef USB_EPTX_STAT_Pos -#define USB_EPTX_STAT_Pos 4u + #define USB_EPTX_STAT_Pos 4u #endif #ifndef USB_EP_DTOG_TX_Pos -#define USB_EP_DTOG_TX_Pos 6u + #define USB_EP_DTOG_TX_Pos 6u #endif #ifndef USB_EP_CTR_TX_Pos -#define USB_EP_CTR_TX_Pos 7u + #define USB_EP_CTR_TX_Pos 7u #endif typedef enum { EP_STAT_DISABLED = 0, - EP_STAT_STALL = 1, - EP_STAT_NAK = 2, - EP_STAT_VALID = 3 -}ep_stat_t; + EP_STAT_STALL = 1, + EP_STAT_NAK = 2, + EP_STAT_VALID = 3 +} ep_stat_t; -#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) -#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) -#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) -#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) +#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) +#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) //--------------------------------------------------------------------+ // Endpoint Helper @@ -211,7 +207,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value fsdev_int_disable(0); } - FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; + FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t)value; if (need_exclusive) { fsdev_int_enable(0); @@ -226,11 +222,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb ep_write(ep_id, reg, false); } -TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) { +TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) { *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); } -TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) { +TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) { *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); } @@ -259,11 +255,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ch_write_clear_ctr(uint32_t ch_id, tusb ep_write(ch_id, reg, false); } -TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) { +TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) { *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 8 : 0))); } -TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) { +TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) { *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0))); } @@ -281,8 +277,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uin TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) { #ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; #else FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr; @@ -301,12 +297,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, ui TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) { #ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; #else - uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; - cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); + uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; + cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt; #endif } @@ -318,31 +314,11 @@ void fsdev_core_reset(void); void fsdev_deinit(void); // Aligned buffer size according to hardware -uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block); +uint16_t pma_align_buffer_size(uint16_t size, uint8_t *blsize, uint8_t *num_block); // Set RX buffer size void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount); -//--------------------------------------------------------------------+ -// PMA (Packet Memory Area) Access -//--------------------------------------------------------------------+ - -// Write to packet memory area (PMA) from user memory -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); - -// Read from packet memory area (PMA) to user memory. -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); - -// Write to PMA from FIFO -bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); - -// Read from PMA to FIFO -bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); - #ifdef __cplusplus } #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index 4b7d3d301..02dba05a6 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -32,10 +32,23 @@ #ifndef TUSB_FSDEV_STM32_H #define TUSB_FSDEV_STM32_H -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 +#if CFG_TUSB_MCU == OPT_MCU_STM32C0 + #include "stm32c0xx.h" + #define FSDEV_HAS_SBUF_ISO 1 + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_CHEP_VTRX + #define USB_EP_CTR_TX USB_CHEP_VTTX + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" - #define FSDEV_PMA_SIZE (1024u) - #define FSDEV_REG_BASE USB_BASE + #define FSDEV_REG_BASE USB_BASE #define FSDEV_HAS_SBUF_ISO 0 // F0x2 models are crystal-less // All have internal D+ pull-up @@ -44,29 +57,24 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" - #define FSDEV_PMA_SIZE (512u) #define FSDEV_HAS_SBUF_ISO 0 // NO internal Pull-ups // *B, and *C: 2 x 16 bits/word // F1 names this differently from the rest - #define USB_CNTR_LPMODE USB_CNTR_LP_MODE + #define USB_CNTR_LPMODE USB_CNTR_LP_MODE -#elif defined(STM32F302xB) || defined(STM32F302xC) || \ - defined(STM32F303xB) || defined(STM32F303xC) || \ - defined(STM32F373xC) +#elif defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \ + defined(STM32F373xC) #include "stm32f3xx.h" - #define FSDEV_PMA_SIZE (512u) #define FSDEV_HAS_SBUF_ISO 0 // NO internal Pull-ups // *B, and *C: 1 x 16 bits/word // PMA dedicated to USB (no sharing with CAN) -#elif defined(STM32F302x6) || defined(STM32F302x8) || \ - defined(STM32F302xD) || defined(STM32F302xE) || \ - defined(STM32F303xD) || defined(STM32F303xE) +#elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \ + defined(STM32F303xD) || defined(STM32F303xE) #include "stm32f3xx.h" - #define FSDEV_PMA_SIZE (1024u) #define FSDEV_HAS_SBUF_ISO 0 // NO internal Pull-ups // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support @@ -74,28 +82,32 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32L0 #include "stm32l0xx.h" - #define FSDEV_PMA_SIZE (1024u) #define FSDEV_HAS_SBUF_ISO 0 #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 #include "stm32l1xx.h" - #define FSDEV_PMA_SIZE (512u) #define FSDEV_HAS_SBUF_ISO 0 -#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 - #include "stm32g4xx.h" - #define FSDEV_PMA_SIZE (1024u) +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define FSDEV_HAS_SBUF_ISO 0 + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + #include "stm32l5xx.h" #define FSDEV_HAS_SBUF_ISO 0 + #ifndef USB_PMAADDR + #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) + #endif + #elif CFG_TUSB_MCU == OPT_MCU_STM32G0 #include "stm32g0xx.h" - #define FSDEV_PMA_SIZE (2048u) - #define FSDEV_HAS_SBUF_ISO 1 - #define USB USB_DRD_FS + #define FSDEV_HAS_SBUF_ISO 1 + #define USB USB_DRD_FS - #define USB_EP_CTR_RX USB_EP_VTRX - #define USB_EP_CTR_TX USB_EP_VTTX - #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE #define USB_EPREG_MASK USB_CHEP_REG_MASK #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK @@ -110,78 +122,20 @@ #define USB_ISTR_EP_ID USB_ISTR_IDN #define USB_EPADDR_FIELD USB_CHEP_ADDR #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN -#elif CFG_TUSB_MCU == OPT_MCU_STM32C0 - #include "stm32c0xx.h" - #define FSDEV_PMA_SIZE (2048u) - #define FSDEV_HAS_SBUF_ISO 1 - #define USB USB_DRD_FS - #define USB_EP_CTR_RX USB_CHEP_VTRX - #define USB_EP_CTR_TX USB_CHEP_VTTX - #define USB_EPREG_MASK USB_CHEP_REG_MASK - #define USB_CNTR_FRES USB_CNTR_USBRST - #define USB_CNTR_RESUME USB_CNTR_L2RES - #define USB_ISTR_EP_ID USB_ISTR_IDN - #define USB_EPADDR_FIELD USB_CHEP_ADDR - #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + #include "stm32g4xx.h" + #define FSDEV_HAS_SBUF_ISO 0 #elif CFG_TUSB_MCU == OPT_MCU_STM32H5 #include "stm32h5xx.h" - #define FSDEV_PMA_SIZE (2048u) - #define FSDEV_HAS_SBUF_ISO 1 - #define USB USB_DRD_FS - - #define USB_EP_CTR_RX USB_EP_VTRX - #define USB_EP_CTR_TX USB_EP_VTTX - #define USB_EP_T_FIELD USB_CHEP_UTYPE - #define USB_EPREG_MASK USB_CHEP_REG_MASK - #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK - #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK - #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 - #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 - #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 - #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 - #define USB_EPRX_STAT USB_CH_RX_VALID - #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB_CNTR_FRES USB_CNTR_USBRST - #define USB_CNTR_RESUME USB_CNTR_L2RES - #define USB_ISTR_EP_ID USB_ISTR_IDN - #define USB_EPADDR_FIELD USB_CHEP_ADDR - #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN - -#elif CFG_TUSB_MCU == OPT_MCU_STM32WB - #include "stm32wbxx.h" - #define FSDEV_PMA_SIZE (1024u) - #define FSDEV_HAS_SBUF_ISO 0 - /* ST provided header has incorrect value of USB_PMAADDR */ - #define FSDEV_PMA_BASE USB1_PMAADDR - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 - #include "stm32l4xx.h" - #define FSDEV_PMA_SIZE (1024u) - #define FSDEV_HAS_SBUF_ISO 0 - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 - #include "stm32l5xx.h" - #define FSDEV_PMA_SIZE (1024u) - #define FSDEV_HAS_SBUF_ISO 0 - - #ifndef USB_PMAADDR - #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) - #endif - -#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 - #include "stm32u5xx.h" - #define FSDEV_PMA_SIZE (2048u) #define FSDEV_HAS_SBUF_ISO 1 - #define USB USB_DRD_FS + #define USB USB_DRD_FS - #define USB_EP_CTR_RX USB_EP_VTRX - #define USB_EP_CTR_TX USB_EP_VTTX - #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE #define USB_EPREG_MASK USB_CHEP_REG_MASK #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK @@ -200,7 +154,6 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U0 #include "stm32u0xx.h" - #define FSDEV_PMA_SIZE (1024u) #define FSDEV_BUS_32BIT #define FSDEV_HAS_SBUF_ISO 1 #define USB USB_DRD_FS @@ -226,10 +179,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U3 #include "stm32u3xx.h" - #define FSDEV_PMA_SIZE (2048u) #define FSDEV_BUS_32BIT #define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested... - #define USB USB_DRD_FS + #define USB USB_DRD_FS #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX @@ -240,15 +192,45 @@ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 - #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 - #define USB_EPRX_STAT USB_CH_RX_VALID - #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB_CNTR_FRES USB_CNTR_USBRST - #define USB_CNTR_RESUME USB_CNTR_L2RES - #define USB_ISTR_EP_ID USB_ISTR_IDN - #define USB_EPADDR_FIELD USB_CHEP_ADDR - #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 + #include "stm32u5xx.h" + #define FSDEV_HAS_SBUF_ISO 1 + #define USB USB_DRD_FS + + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + #include "stm32wbxx.h" + #define FSDEV_HAS_SBUF_ISO 0 + /* ST provided header has incorrect value of USB_PMAADDR */ + #define FSDEV_PMA_BASE USB1_PMAADDR #else #error You are using an untested or unimplemented STM32 variant. Please update the driver. @@ -299,7 +281,7 @@ // - Enable double buffering on devices with >1KB Packet Memory Area (PMA) // to improve isochronous transfer reliability and performance // - Disable on devices with limited PMA to conserve memory space - #if FSDEV_PMA_SIZE > 1024u + #if CFG_TUSB_FSDEV_PMA_SIZE > 1024u #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1 #else #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0 diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index da9c6961c..acdeccf6d 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -303,10 +303,12 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); - if (ep_id == TUSB_INDEX_INVALID_8) return; + if (ep_id == TUSB_INDEX_INVALID_8) { + return; + } - hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; + hcd_channel_t *channel = &_hcd_data.channel[ch_id]; if (dir == TUSB_DIR_OUT) { // OUT/TX direction @@ -314,7 +316,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { // More data to send uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len); + tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL); btable_set_count(ch_id, BTABLE_BUF_TX, len); edpt->queued_len += len; channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false); @@ -329,8 +331,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { // IN/RX direction uint16_t const rx_count = channel_get_rx_count(ch_id); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); - - fsdev_read_packet_memory(edpt->buffer + edpt->queued_len, pma_addr, rx_count); + tu_hwfifo_read(PMA_BUF_AT(pma_addr), edpt->buffer + edpt->queued_len, rx_count, NULL); edpt->queued_len += rx_count; if ((rx_count < edpt->max_packet_size) || (edpt->queued_len >= edpt->buflen)) { @@ -740,7 +741,7 @@ static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) { uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; addr += channel * TUSB_EPSIZE_BULK_FS * 2 + (dir == TUSB_DIR_IN ? TUSB_EPSIZE_BULK_FS : 0); - TU_ASSERT(addr <= FSDEV_PMA_SIZE, 0xFFFF); + TU_ASSERT(addr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF); return addr; } @@ -841,8 +842,7 @@ static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { if (dir == TUSB_DIR_OUT) { uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size); - - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len); + tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL); btable_set_count(ch_id, BTABLE_BUF_TX, len); edpt->queued_len += len; diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ba40498e6..44f7137f9 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -98,10 +98,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_enabled(dwc2_dep_t* dep) { return (dep->ctl & EPCTL_EPENA) != 0; } -//-------------------------------------------------------------------- -// DMA -//-------------------------------------------------------------------- -#if CFG_TUD_MEM_DCACHE_ENABLE + #if CFG_TUD_DWC2_SLAVE_ENABLE +static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum); + #endif + + //-------------------------------------------------------------------- + // DMA + //-------------------------------------------------------------------- + #if CFG_TUD_MEM_DCACHE_ENABLE bool dcd_dcache_clean(const void* addr, uint32_t data_size) { TU_VERIFY(addr && data_size); return dwc2_dcache_clean(addr, data_size); @@ -345,40 +349,6 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } -static uint16_t epin_write_tx_fifo(uint8_t rhport, uint8_t epnum) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - dwc2_dep_t* const epin = &dwc2->ep[0][epnum]; - xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); - - dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; - const uint16_t remain_packets = tsiz.packet_count; - - uint16_t total_bytes_written = 0; - // Process every single packet (only whole packets can be written to fifo) - for (uint16_t i = 0; i < remain_packets; i++) { - 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 - if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) { - break; - } - - // Push packet to Tx-FIFO - if (xfer->ff) { - volatile uint32_t* tx_fifo = dwc2->fifo[epnum]; - tu_fifo_read_n_access_mode(xfer->ff, (void *)(uintptr_t)tx_fifo, xact_bytes, TU_FIFO_FIXED_ADDR_RW32); - total_bytes_written += xact_bytes; - } else { - dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes); - xfer->buffer += xact_bytes; - total_bytes_written += xact_bytes; - } - } - return total_bytes_written; -} - // Since this function returns void, it is not possible to return a boolean success message // We must make sure that this function is not called when the EP is disabled // Must be called from critical section @@ -423,6 +393,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin } } + #if CFG_TUD_DWC2_DMA_ENABLE const bool is_dma = dma_device_enabled(dwc2); if(is_dma) { if (dir == TUSB_DIR_IN && total_bytes != 0) { @@ -434,11 +405,14 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin if (epnum == 0) { xfer->buffer += total_bytes; } - } else { + } else + #endif + { + #if CFG_TUD_DWC2_SLAVE_ENABLE dep->diepctl = depctl.value; // enable endpoint if (dir == TUSB_DIR_IN && total_bytes != 0) { - const uint16_t xferred_bytes = epin_write_tx_fifo(rhport, epnum); + const uint16_t xferred_bytes = epin_write_tx_fifo(dwc2, epnum); // Enable TXFE interrupt if there are still data to be sent // EP0 only sends one packet at a time, so no need to check for EP0 @@ -446,6 +420,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin dwc2->diepempmsk |= (1u << epnum); } } + #endif } } @@ -689,9 +664,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to // into the USB buffer! bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) { (void) is_isr; - // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 - TU_ASSERT(ff->item_size == 1); - uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); @@ -854,6 +826,39 @@ TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) { #endif #if CFG_TUD_DWC2_SLAVE_ENABLE +static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum) { + dwc2_dep_t *const epin = &dwc2->ep[0][epnum]; + xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); + + dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; + const uint16_t remain_packets = tsiz.packet_count; + + uint16_t total_bytes_written = 0; + // Process every single packet (only whole packets can be written to fifo) + for (uint16_t i = 0; i < remain_packets; i++) { + 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 + if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) { + break; + } + + // Push packet to Tx-FIFO + volatile uint32_t *tx_fifo = dwc2->fifo[epnum]; + if (xfer->ff) { + tu_hwfifo_write_from_fifo(tx_fifo, xfer->ff, xact_bytes, NULL); + total_bytes_written += xact_bytes; + } else { + tu_hwfifo_write(tx_fifo, xfer->buffer, xact_bytes, NULL); + xfer->buffer += xact_bytes; + total_bytes_written += xact_bytes; + } + } + return total_bytes_written; +} + // Process shared receive FIFO, this interrupt is only used in Slave mode static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -893,9 +898,9 @@ static void handle_rxflvl_irq(uint8_t rhport) { if (byte_count != 0) { // Read packet off RxFIFO if (xfer->ff != NULL) { - tu_fifo_write_n_access_mode(xfer->ff, (const void *)(uintptr_t)rx_fifo, byte_count, TU_FIFO_FIXED_ADDR_RW32); + tu_hwfifo_read_to_fifo(rx_fifo, xfer->ff, byte_count, NULL); } else { - dfifo_read_packet(dwc2, xfer->buffer, byte_count); + tu_hwfifo_read(rx_fifo, xfer->buffer, byte_count, NULL); xfer->buffer += byte_count; } } @@ -967,7 +972,7 @@ 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 && tu_bit_test(dwc2->diepempmsk, epnum)) { - epin_write_tx_fifo(rhport, epnum); + epin_write_tx_fifo(dwc2, epnum); // Turn off TXFE if all bytes are written. dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; diff --git a/src/portable/synopsys/dwc2/dwc2_at32.h b/src/portable/synopsys/dwc2/dwc2_at32.h index 513495eb1..10824ae92 100644 --- a/src/portable/synopsys/dwc2/dwc2_at32.h +++ b/src/portable/synopsys/dwc2/dwc2_at32.h @@ -61,6 +61,11 @@ #define OTG1_FIFO_SIZE 1280 #define OTG1_IRQn OTGFS1_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL +#elif CFG_TUSB_MCU == OPT_MCU_AT32F45X + #include <at32f45x.h> + #define OTG1_FIFO_SIZE 1280 + #define OTG1_IRQn OTGFS1_IRQn + #define DWC2_OTG1_REG_BASE 0x50000000UL #endif #ifdef __cplusplus diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index 980574e12..a7e6188df 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -264,58 +264,4 @@ bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) { // // } -//-------------------------------------------------------------------- -// DFIFO -//-------------------------------------------------------------------- -// Read a single data packet from receive DFIFO -void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) { - const volatile uint32_t* rx_fifo = dwc2->fifo[0]; - - // Reading full available 32 bit words from fifo - uint16_t word_count = len >> 2; - while (word_count--) { - tu_unaligned_write32(dst, *rx_fifo); - dst += 4; - } - - // Read the remaining 1-3 bytes from fifo - const uint8_t bytes_rem = len & 0x03; - if (bytes_rem != 0) { - const uint32_t tmp = *rx_fifo; - dst[0] = tu_u32_byte0(tmp); - if (bytes_rem > 1) { - dst[1] = tu_u32_byte1(tmp); - } - if (bytes_rem > 2) { - dst[2] = tu_u32_byte2(tmp); - } - } -} - -// Write a single data packet to DFIFO -void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) { - volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num]; - - // Pushing full available 32 bit words to fifo - uint16_t word_count = len >> 2; - while (word_count--) { - *tx_fifo = tu_unaligned_read32(src); - src += 4; - } - - // Write the remaining 1-3 bytes into fifo - const uint8_t bytes_rem = len & 0x03; - if (bytes_rem) { - uint32_t tmp_word = src[0]; - if (bytes_rem > 1) { - tmp_word |= (src[1] << 8); - } - if (bytes_rem > 2) { - tmp_word |= (src[2] << 16); - } - - *tx_fifo = tmp_word; - } -} - #endif diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index fc748c85f..c40703b09 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -856,7 +856,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; if (byte_count > 0) { - dfifo_read_packet(dwc2, edpt->buffer + xfer->xferred_bytes, byte_count); + tu_hwfifo_read(dwc2->fifo[0], edpt->buffer + xfer->xferred_bytes, byte_count, NULL); xfer->xferred_bytes += byte_count; xfer->fifo_bytes = byte_count; } @@ -907,7 +907,7 @@ static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) { return true; } - dfifo_write_packet(dwc2, ch_id, edpt->buffer + xfer->fifo_bytes, xact_bytes); + tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL); xfer->fifo_bytes += xact_bytes; } } diff --git a/src/tusb.c b/src/tusb.c index 8117c3e3e..ed254a10b 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -316,7 +316,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove #endif s->is_host = is_host; - tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable); #if OSAL_MUTEX_REQUIRED if (ff_buf != NULL && ff_bufsize > 0) { diff --git a/src/tusb_option.h b/src/tusb_option.h index 64fe899db..e0a52593f 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -216,6 +216,7 @@ #define OPT_MCU_AT32F402_405 2504 ///< ArteryTek AT32F402_405 #define OPT_MCU_AT32F425 2505 ///< ArteryTek AT32F425 #define OPT_MCU_AT32F413 2506 ///< ArteryTek AT32F413 +#define OPT_MCU_AT32F45X 2507 ///< ArteryTek AT32F45x // HPMicro #define OPT_MCU_HPM 2600 ///< HPMicro @@ -272,16 +273,7 @@ //--------------------------------------------------------------------+ //------------- DWC2 -------------// -// Slave mode for device -#ifndef CFG_TUD_DWC2_SLAVE_ENABLE - #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT - #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT 1 - #endif - - #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT -#endif - -// DMA for device +// DMA mode for device #ifndef CFG_TUD_DWC2_DMA_ENABLE #ifndef CFG_TUD_DWC2_DMA_ENABLE_DEFAULT #define CFG_TUD_DWC2_DMA_ENABLE_DEFAULT 0 @@ -290,16 +282,16 @@ #define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT #endif -// Slave mode for host -#ifndef CFG_TUH_DWC2_SLAVE_ENABLE - #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT - #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT 1 +// Slave mode for device +#ifndef CFG_TUD_DWC2_SLAVE_ENABLE + #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT + #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE // disabled if DMA is enabled #endif - #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT + #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT #endif -// DMA for host +// DMA mode for host #ifndef CFG_TUH_DWC2_DMA_ENABLE #ifndef CFG_TUH_DWC2_DMA_ENABLE_DEFAULT #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0 @@ -308,14 +300,21 @@ #define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT #endif -#if defined(TUP_USBIP_DWC2) - #if CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 +// Slave mode for host +#ifndef CFG_TUH_DWC2_SLAVE_ENABLE + #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT + #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // disabled if DMA is enabled #endif - #if CFG_TUH_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUH_EDPT_DEDICATED_HWFIFO 1 - #endif + #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT +#endif + +#if defined(TUP_USBIP_DWC2) + #define CFG_TUD_EDPT_DEDICATED_HWFIFO CFG_TUD_DWC2_SLAVE_ENABLE + #define CFG_TUH_EDPT_DEDICATED_HWFIFO CFG_TUH_DWC2_SLAVE_ENABLE + + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32bit access + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address #endif //------------- ChipIdea -------------// @@ -337,7 +336,7 @@ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 #endif -//------------- pio-usb -------------// +//------------- Raspberry Pi -------------// // Enable PIO-USB software host controller #ifndef CFG_TUH_RPI_PIO_USB #define CFG_TUH_RPI_PIO_USB 0 @@ -356,16 +355,36 @@ //------------ FSDEV --------------// #if defined(TUP_USBIP_FSDEV) #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 + + #if CFG_TUSB_FSDEV_PMA_SIZE == 512 + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase + #elif CFG_TUSB_FSDEV_PMA_SIZE == 1024 + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 2 // 16-bit address increase + #elif CFG_TUSB_FSDEV_PMA_SIZE == 2048 + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase + #endif #endif //------------ MUSB --------------// #if defined(TUP_USBIP_MUSB) - #define CFG_TUD_EDPT_DEDICATED_HWFIFO 0 // need testing to enable + #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data + #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access + #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo + #endif //------------ RUSB2 --------------// #if defined(TUP_USBIP_RUSB2) - #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 + #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit data if highspeed + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 + #define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write + // odd byte with byte access #endif //-------------------------------------------------------------------- @@ -724,7 +743,7 @@ #define CFG_TUH_CDC_PL2303 0 #endif -#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST +#ifndef CFG_TUH_CDC_PL2303_VID_PID_LIST // List of product IDs that can use the PL2303 CDC driver #define CFG_TUH_CDC_PL2303_VID_PID_LIST \ { 0x067b, 0x2303 }, /* initial 2303 */ \ diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 6afcb2186..7cb561b2d 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -103,10 +103,10 @@ "name": "ra4m1_ek", "uid": "152E163038303131393346E46F26574B", "tests": { - "device": true, "host": false, "dual": false, - "skip": ["device/cdc_msc", "device/cdc_msc_freertos"] + "device": true, + "host": false, + "dual": false }, - "comment": "MSC is slow to enumerated #2602", "flasher": { "name": "jlink", "uid": "000831174392", diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt index 7172f5575..b44a91d57 100644 --- a/test/unit-test/CMakeLists.txt +++ b/test/unit-test/CMakeLists.txt @@ -113,7 +113,6 @@ add_ceedling_test( ${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c "" ) -target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1) add_ceedling_test( test_usbd diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml index d971d098d..be3fc3de0 100644 --- a/test/unit-test/project.yml +++ b/test/unit-test/project.yml @@ -128,7 +128,9 @@ :defines: :test: - _UNITY_TEST_ - - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + - CFG_TUD_EDPT_DEDICATED_HWFIFO=1 + - CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE=6 + - CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE=0 :release: [] # Enable to inject name of a test as a unique compilation symbol into its respective executable build. diff --git a/test/unit-test/test/test_fifo.c b/test/unit-test/test/test_fifo.c index 35bbeaa62..b9279cb25 100644 --- a/test/unit-test/test/test_fifo.c +++ b/test/unit-test/test/test_fifo.c @@ -32,7 +32,7 @@ #define FIFO_SIZE 64 uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)]; -tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false); +tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, false); tu_fifo_t *ff = &tu_ff; tu_fifo_buffer_info_t info; @@ -40,6 +40,16 @@ tu_fifo_buffer_info_t info; uint8_t test_data[4096]; uint8_t rd_buf[FIFO_SIZE]; +static const tu_hwfifo_access_t hwfifo_access_32 = { + .data_stride = 4, + .param = 0, +}; + +static const tu_hwfifo_access_t hwfifo_access_16 = { + .data_stride = 2, + .param = 0, +}; + void setUp(void) { tu_fifo_clear(ff); memset(&info, 0, sizeof(tu_fifo_buffer_info_t)); @@ -68,34 +78,6 @@ void test_normal(void) { } } -void test_item_size(void) { - uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)]; - tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false); - - uint32_t data4[2 * FIFO_SIZE]; - for (uint32_t i = 0; i < sizeof(data4) / 4; i++) { - data4[i] = i; - } - - // fill up fifo - tu_fifo_write_n(&ff4, data4, FIFO_SIZE); - - uint32_t rd_buf4[FIFO_SIZE]; - uint16_t rd_count; - - // read 0 -> 4 - rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5); - TEST_ASSERT_EQUAL(5, rd_count); - TEST_ASSERT_EQUAL_UINT32_ARRAY(data4, rd_buf4, rd_count); // 0 -> 4 - - tu_fifo_write_n(&ff4, data4 + FIFO_SIZE, 5); - - // read all 5 -> 68 - rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE); - TEST_ASSERT_EQUAL(FIFO_SIZE, rd_count); - TEST_ASSERT_EQUAL_UINT32_ARRAY(data4 + 5, rd_buf4, rd_count); // 5 -> 68 -} - void test_read_n(void) { uint16_t rd_count; @@ -362,7 +344,7 @@ void test_rd_idx_wrap(void) { uint8_t buf[10]; uint8_t dst[10]; - tu_fifo_config(&ff10, buf, 10, 1, 1); + tu_fifo_config(&ff10, buf, 10, 1); uint16_t n; @@ -431,7 +413,7 @@ void test_write_n_fixed_addr_rw32_nowrap(void) { for (uint8_t n = 1; n <= 8; n++) { tu_fifo_clear(ff); - uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32); + uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_32); TEST_ASSERT_EQUAL(n, written); TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); @@ -453,7 +435,7 @@ void test_write_n_fixed_addr_rw32_wrapped(void) { ff->wr_idx = FIFO_SIZE - 3; ff->rd_idx = FIFO_SIZE - 3; - uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, TU_FIFO_FIXED_ADDR_RW32); + uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_32); TEST_ASSERT_EQUAL(n, written); TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); @@ -473,7 +455,7 @@ void test_read_n_fixed_addr_rw32_nowrap(void) { tu_fifo_write_n(ff, pattern, 8); uint32_t reg = 0; - uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32); + uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_32); TEST_ASSERT_EQUAL(n, read_cnt); TEST_ASSERT_EQUAL(8 - n, tu_fifo_count(ff)); @@ -497,7 +479,7 @@ void test_read_n_fixed_addr_rw32_wrapped(void) { } uint32_t reg = 0; - uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, TU_FIFO_FIXED_ADDR_RW32); + uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_32); TEST_ASSERT_EQUAL(n, read_cnt); TEST_ASSERT_EQUAL(0, tu_fifo_count(ff)); @@ -505,6 +487,86 @@ void test_read_n_fixed_addr_rw32_wrapped(void) { } } +void test_write_n_fixed_addr_rw16_nowrap(void) { + tu_fifo_clear(ff); + + volatile uint16_t reg = 0x1122; + uint8_t expected[6] = {0x22, 0x11, 0x22, 0x11, 0x22, 0x11}; + + for (uint8_t n = 1; n <= 6; n++) { + tu_fifo_clear(ff); + uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_16); + TEST_ASSERT_EQUAL(n, written); + TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); + + uint8_t out[6] = {0}; + tu_fifo_read_n(ff, out, n); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n); + } +} + +void test_write_n_fixed_addr_rw16_wrapped(void) { + tu_fifo_clear(ff); + + volatile uint16_t reg = 0xA1B2; + uint8_t expected[6] = {0xB2, 0xA1, 0xB2, 0xA1, 0xB2, 0xA1}; + + for (uint8_t n = 1; n <= 6; n++) { + tu_fifo_clear(ff); + // Position the fifo near the end so writes wrap + ff->wr_idx = FIFO_SIZE - 3; + ff->rd_idx = FIFO_SIZE - 3; + + uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)®, n, &hwfifo_access_16); + TEST_ASSERT_EQUAL(n, written); + TEST_ASSERT_EQUAL(n, tu_fifo_count(ff)); + + uint8_t out[6] = {0}; + tu_fifo_read_n(ff, out, n); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n); + } +} + +void test_read_n_fixed_addr_rw16_nowrap(void) { + uint8_t pattern[6] = {0x10, 0x21, 0x32, 0x43, 0x54, 0x65}; + uint16_t reg_expected[6] = {0x0010, 0x2110, 0x0032, 0x4332, 0x0054, 0x6554}; + + for (uint8_t n = 1; n <= 6; n++) { + tu_fifo_clear(ff); + tu_fifo_write_n(ff, pattern, 6); + + uint16_t reg = 0; + uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_16); + TEST_ASSERT_EQUAL(n, read_cnt); + TEST_ASSERT_EQUAL(6 - n, tu_fifo_count(ff)); + + TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg); + } +} + +void test_read_n_fixed_addr_rw16_wrapped(void) { + uint8_t pattern[6] = {0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5}; + uint16_t reg_expected[6] = {0x00F0, 0xE1F0, 0x00D2, 0xC3D2, 0x00B4, 0xA5B4}; + + for (uint8_t n = 1; n <= 6; n++) { + tu_fifo_clear(ff); + ff->rd_idx = FIFO_SIZE - 1; + ff->wr_idx = (uint16_t)(ff->rd_idx + n); + + for (uint8_t i = 0; i < n; i++) { + uint8_t idx = (uint8_t)((ff->rd_idx + i) % FIFO_SIZE); + ff->buffer[idx] = pattern[i]; + } + + uint16_t reg = 0; + uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, ®, n, &hwfifo_access_16); + TEST_ASSERT_EQUAL(n, read_cnt); + TEST_ASSERT_EQUAL(0, tu_fifo_count(ff)); + + TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg); + } +} + void test_get_read_info_advanced_cases(void) { tu_fifo_clear(ff); diff --git a/tools/build.py b/tools/build.py index 87064b7a0..d22d06a0b 100755 --- a/tools/build.py +++ b/tools/build.py @@ -40,7 +40,9 @@ ci_skip_boards = { } ci_preferred_boards = { - 'stm32h7': ['stm32h743eval'], + 'samd2x_l2x': ['metro_m0_express'], + 'samd5x_e5x': ['metro_m4_express'], + 'stm32h7': ['stm32h743eval'] } diff --git a/tools/get_deps.py b/tools/get_deps.py index deacbb23b..773445adc 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -244,6 +244,9 @@ deps_optional = { 'hw/mcu/artery/at32f413': ['https://github.com/ArteryTek/AT32F413_Firmware_Library.git', 'f6fe62dfec9fd40c5b63d92fc5ef2c2b5e77a450', 'at32f413'], + 'hw/mcu/artery/at32f45x': ['https://github.com/ArteryTek/AT32F45x_Firmware_Library.git', + '3d4a1b38be8ebac292e2350ca53bc4bfa4430233', + 'at32f45x'], 'hw/mcu/hpmicro/hpm_sdk': ['https://github.com/hpmicro/hpm_sdk', '8d2af741ecc4aaa82d7ee395dc1ce25d7070c3ff', 'hpmicro'], |
