summaryrefslogtreecommitdiff
path: root/hw/bsp
diff options
context:
space:
mode:
Diffstat (limited to 'hw/bsp')
-rw-r--r--hw/bsp/BoardPresets.json66
-rw-r--r--hw/bsp/apm32f0xx/FreeRTOSConfig/FreeRTOSConfig.h108
-rw-r--r--hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.cmake13
-rw-r--r--hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.h49
-rw-r--r--hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.mk10
-rw-r--r--hw/bsp/apm32f0xx/family.c146
-rw-r--r--hw/bsp/apm32f0xx/family.cmake83
-rw-r--r--hw/bsp/apm32f0xx/family.mk38
-rw-r--r--hw/bsp/ch32v10x/family.cmake2
-rw-r--r--hw/bsp/ch32v10x/family.mk2
-rw-r--r--hw/bsp/ch32v20x/family.c38
-rw-r--r--hw/bsp/ch32v20x/family.cmake2
-rw-r--r--hw/bsp/ch32v20x/family.mk2
-rw-r--r--hw/bsp/ch32v30x/family.c9
-rw-r--r--hw/bsp/ch32v30x/family.cmake2
-rw-r--r--hw/bsp/ch32v30x/family.mk2
-rw-r--r--hw/bsp/ch583/family.cmake2
-rw-r--r--hw/bsp/ch583/family.mk2
-rw-r--r--hw/bsp/ch583/wch-riscv.cfg2
-rw-r--r--hw/bsp/family_rules.mk16
-rw-r--r--hw/bsp/family_support.cmake44
-rw-r--r--hw/bsp/imxrt/boards/metro_m7_1011/ozone/metro_m7_1011.jdebug3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h5
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176.jdebug69
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176_trace.JLinkScript11
-rw-r--r--hw/bsp/imxrt/family.c73
-rw-r--r--hw/bsp/kinetis_k/family.c40
-rw-r--r--hw/bsp/kinetis_k/family.cmake2
-rw-r--r--hw/bsp/kinetis_k/family.mk4
-rw-r--r--hw/bsp/kinetis_k32l/family.cmake4
-rw-r--r--hw/bsp/kinetis_k32l/family.mk4
-rw-r--r--hw/bsp/kinetis_kl/family.cmake2
-rw-r--r--hw/bsp/kinetis_kl/family.mk4
-rw-r--r--hw/bsp/lpc11/boards/lpcxpresso11u37/board.mk3
-rw-r--r--hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld16
-rw-r--r--hw/bsp/lpc15/family.c13
-rw-r--r--hw/bsp/lpc18/boards/lpcxpresso18s37/board.h6
-rw-r--r--hw/bsp/lpc18/boards/mcb1800/board.h27
-rw-r--r--hw/bsp/lpc18/boards/mcb1800/ozone/lpc1857.jdebug6
-rw-r--r--hw/bsp/lpc18/family.c1
-rw-r--r--hw/bsp/lpc40/boards/ea4088_quickstart/ozone/ea4088_quickstart.jdebug2
-rw-r--r--hw/bsp/lpc40/family.c13
-rw-r--r--hw/bsp/lpc43/boards/ea4357/board.h16
-rw-r--r--hw/bsp/lpc43/boards/lpcxpresso43s67/board.h6
-rw-r--r--hw/bsp/lpc43/family.c30
-rw-r--r--hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake4
-rw-r--r--hw/bsp/lpc55/boards/lpcxpresso55s28/board.mk6
-rw-r--r--hw/bsp/lpc55/family.c8
-rw-r--r--hw/bsp/lpc55/family.mk2
-rw-r--r--hw/bsp/mcx/family.cmake11
-rw-r--r--hw/bsp/nrf/boards/nrf52840dk/ozone/nrf52840.jdebug2
-rw-r--r--hw/bsp/nrf/boards/nrf5340dk/ozone/nrf5340.jdebug6
-rw-r--r--hw/bsp/nrf/family.c6
-rw-r--r--hw/bsp/py32f0/FreeRTOSConfig/FreeRTOSConfig.h108
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake12
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.h75
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.mk12
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h105
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld122
-rw-r--r--hw/bsp/py32f0/family.c133
-rw-r--r--hw/bsp/py32f0/family.cmake89
-rw-r--r--hw/bsp/py32f0/family.mk58
-rw-r--r--hw/bsp/ra/boards/ra6m5_ek/ozone/ra6m5.jdebug2
-rw-r--r--hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1.jdebug17
-rw-r--r--hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1_trace.JLinkScript20
-rw-r--r--hw/bsp/ra/boards/ra8m1_ek/ra_gen/bsp_clock_cfg.h5
-rw-r--r--hw/bsp/ra/family.c29
-rw-r--r--hw/bsp/rp2040/boards/pico2_etm_trace/board.cmake35
-rw-r--r--hw/bsp/rp2040/boards/pico2_etm_trace/board.h80
-rw-r--r--hw/bsp/rp2040/boards/pico2_etm_trace/ozone/rp2350.jdebug79
-rw-r--r--hw/bsp/rp2040/family.c57
-rw-r--r--hw/bsp/rp2040/family.cmake3
-rw-r--r--hw/bsp/samd2x_l2x/family.cmake1
-rw-r--r--hw/bsp/samd5x_e5x/boards/same54_xplained/ozone/same54.jdebug89
-rw-r--r--hw/bsp/samd5x_e5x/family.c27
-rw-r--r--hw/bsp/same7x/boards/same70_xplained/board.h4
-rw-r--r--hw/bsp/same7x/boards/same70_xplained/ozone/same70.jdebug115
-rw-r--r--hw/bsp/same7x/family.c32
-rw-r--r--hw/bsp/stm32h5/boards/stm32h563nucleo/board.h5
-rw-r--r--hw/bsp/stm32h5/boards/stm32h563nucleo/ozone/stm32h563.jdebug113
-rw-r--r--hw/bsp/stm32h5/family.c20
-rw-r--r--hw/bsp/stm32h5/linker/stm32h533xx_flash.icf32
-rw-r--r--hw/bsp/stm32h7/boards/stm32h743eval/ozone/stm32h743.jdebug3
-rw-r--r--hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.h6
-rw-r--r--hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3.jdebug94
-rw-r--r--hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3_trace.JLinkScript11
-rw-r--r--hw/bsp/stm32h7rs/family.c19
-rw-r--r--hw/bsp/stm32l4/boards/stm32l412nucleo/board.h48
-rw-r--r--hw/bsp/stm32n6/boards/stm32n657nucleo/board.h6
-rw-r--r--hw/bsp/stm32n6/boards/stm32n657nucleo/ozone/stm32n657.jdebug94
-rw-r--r--hw/bsp/stm32n6/family.c22
91 files changed, 2650 insertions, 175 deletions
diff --git a/hw/bsp/BoardPresets.json b/hw/bsp/BoardPresets.json
index 93a8f2c32..280d6d592 100644
--- a/hw/bsp/BoardPresets.json
+++ b/hw/bsp/BoardPresets.json
@@ -43,6 +43,10 @@
"inherits": "default"
},
{
+ "name": "apm32f072_dev_board",
+ "inherits": "default"
+ },
+ {
"name": "arduino_nano33_ble",
"inherits": "default"
},
@@ -503,6 +507,10 @@
"inherits": "default"
},
{
+ "name": "pico2_etm_trace",
+ "inherits": "default"
+ },
+ {
"name": "pico_sdk",
"inherits": "default"
},
@@ -511,6 +519,10 @@
"inherits": "default"
},
{
+ "name": "py32f071_dev_board",
+ "inherits": "default"
+ },
+ {
"name": "pybadge",
"inherits": "default"
},
@@ -1008,6 +1020,11 @@
"configurePreset": "apard32690"
},
{
+ "name": "apm32f072_dev_board",
+ "description": "Build preset for the apm32f072_dev_board board",
+ "configurePreset": "apm32f072_dev_board"
+ },
+ {
"name": "arduino_nano33_ble",
"description": "Build preset for the arduino_nano33_ble board",
"configurePreset": "arduino_nano33_ble"
@@ -1628,6 +1645,11 @@
"configurePreset": "nutiny_sdk_nuc505"
},
{
+ "name": "pico2_etm_trace",
+ "description": "Build preset for the pico2_etm_trace board",
+ "configurePreset": "pico2_etm_trace"
+ },
+ {
"name": "pico_sdk",
"description": "Build preset for the pico_sdk board",
"configurePreset": "pico_sdk"
@@ -1638,6 +1660,11 @@
"configurePreset": "portenta_c33"
},
{
+ "name": "py32f071_dev_board",
+ "description": "Build preset for the py32f071_dev_board board",
+ "configurePreset": "py32f071_dev_board"
+ },
+ {
"name": "pybadge",
"description": "Build preset for the pybadge board",
"configurePreset": "pybadge"
@@ -2258,6 +2285,19 @@
]
},
{
+ "name": "apm32f072_dev_board",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "apm32f072_dev_board"
+ },
+ {
+ "type": "build",
+ "name": "apm32f072_dev_board"
+ }
+ ]
+ },
+ {
"name": "arduino_nano33_ble",
"steps": [
{
@@ -3870,6 +3910,19 @@
]
},
{
+ "name": "pico2_etm_trace",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "pico2_etm_trace"
+ },
+ {
+ "type": "build",
+ "name": "pico2_etm_trace"
+ }
+ ]
+ },
+ {
"name": "pico_sdk",
"steps": [
{
@@ -3896,6 +3949,19 @@
]
},
{
+ "name": "py32f071_dev_board",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "py32f071_dev_board"
+ },
+ {
+ "type": "build",
+ "name": "py32f071_dev_board"
+ }
+ ]
+ },
+ {
"name": "pybadge",
"steps": [
{
diff --git a/hw/bsp/apm32f0xx/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/apm32f0xx/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..b8d555ebe
--- /dev/null
+++ b/hw/bsp/apm32f0xx/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,108 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef FREERTOS_CONFIG_H_
+#define FREERTOS_CONFIG_H_
+
+#ifndef __IASMARM__
+ #include "apm32f0xx.h"
+#endif
+
+#define configENABLE_MPU 0
+#define configENABLE_FPU 0
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE 1024
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ 1000
+#define configMAX_PRIORITIES 5
+#define configMINIMAL_STACK_SIZE 128
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION * 4 * 1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 4
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
+
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCHECK_HANDLER_INSTALLATION 0
+
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1
+#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
+
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+#define configPRIO_BITS __NVIC_PRIO_BITS
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ( ( 1 << configPRIO_BITS ) - 1 )
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
+#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
+
+#endif
diff --git a/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.cmake b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.cmake
new file mode 100644
index 000000000..d25f675be
--- /dev/null
+++ b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.cmake
@@ -0,0 +1,13 @@
+set(MCU_VARIANT APM32F072xB)
+set(MCU_LINKER_NAME APM32F07xxB)
+
+set(JLINK_DEVICE APM32F072RB)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ ${MCU_VARIANT}
+ CFG_EXAMPLE_MSC_READONLY
+ CFG_EXAMPLE_MSC_DUAL_READONLY
+ CFG_EXAMPLE_VIDEO_READONLY
+ )
+endfunction()
diff --git a/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.h b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.h
new file mode 100644
index 000000000..2c9e567e5
--- /dev/null
+++ b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.h
@@ -0,0 +1,49 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, 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: APM32F072 Dev Board
+ url: https://www.geehy.com
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED
+#define LED_PORT GPIOC
+#define LED_PIN GPIO_PIN_13
+#define LED_STATE_ON 0
+#define LED_GPIO_CLK_EN() RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOC)
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.mk b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.mk
new file mode 100644
index 000000000..f78d2091f
--- /dev/null
+++ b/hw/bsp/apm32f0xx/boards/apm32f072_dev_board/board.mk
@@ -0,0 +1,10 @@
+MCU_VARIANT = APM32F072xB
+MCU_LINKER_NAME = APM32F07xxB
+
+JLINK_DEVICE = APM32F072RB
+
+CFLAGS += \
+ -D${MCU_VARIANT} \
+ -DCFG_EXAMPLE_MSC_READONLY \
+ -DCFG_EXAMPLE_MSC_DUAL_READONLY \
+ -DCFG_EXAMPLE_VIDEO_READONLY
diff --git a/hw/bsp/apm32f0xx/family.c b/hw/bsp/apm32f0xx/family.c
new file mode 100644
index 000000000..643490797
--- /dev/null
+++ b/hw/bsp/apm32f0xx/family.c
@@ -0,0 +1,146 @@
+/*
+ * 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: Geehy
+*/
+
+#include "apm32f0xx.h"
+#include "apm32f0xx_rcm.h"
+#include "apm32f0xx_gpio.h"
+#include "apm32f0xx_misc.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+void USBD_IRQHandler(void);
+#if CFG_TUSB_OS == OPT_OS_NONE
+void SysTick_Handler(void);
+void SVC_Handler(void);
+void PendSV_Handler(void);
+#endif
+void HardFault_Handler(void);
+void _init(void);
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void USBD_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+//--------------------------------------------------------------------+
+// Board Init
+//--------------------------------------------------------------------+
+void board_init(void) {
+ // Configure HSE and PLL for a 48 MHz system clock
+ SystemClockConfig();
+
+ // Route the 48 MHz PLL clock to USB
+ RCM_ConfigUSBCLK(RCM_USBCLK_PLLCLK);
+
+ // Enable USB peripheral clock
+ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USB);
+
+ // SysTick 1ms tick
+ SysTick_Config(SystemCoreClock / 1000);
+
+ // LED
+ LED_GPIO_CLK_EN();
+ GPIO_Config_T gpio_config;
+ GPIO_ConfigStructInit(&gpio_config);
+ gpio_config.pin = LED_PIN;
+ gpio_config.mode = GPIO_MODE_OUT;
+ gpio_config.outtype = GPIO_OUT_TYPE_PP;
+ gpio_config.speed = GPIO_SPEED_50MHz;
+ GPIO_Config(LED_PORT, &gpio_config);
+
+ board_led_write(false);
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+void board_led_write(bool state) {
+ if (state ^ (!LED_STATE_ON)) {
+ GPIO_SetBit(LED_PORT, LED_PIN);
+ } else {
+ GPIO_ClearBit(LED_PORT, LED_PIN);
+ }
+}
+
+uint32_t board_button_read(void) {
+ return 0;
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t *apm32_uuid = ((volatile uint32_t *) 0x1FFFF7AC);
+ uint32_t *id32 = (uint32_t *) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = apm32_uuid[0];
+ id32[1] = apm32_uuid[1];
+ id32[2] = apm32_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) {
+ (void) buf;
+ (void) len;
+ return 0;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ system_ticks++;
+}
+
+uint32_t tusb_time_millis_api(void) {
+ return system_ticks;
+}
+
+void SVC_Handler(void) {
+}
+
+void PendSV_Handler(void) {
+}
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+void _init(void) {
+}
diff --git a/hw/bsp/apm32f0xx/family.cmake b/hw/bsp/apm32f0xx/family.cmake
new file mode 100644
index 000000000..199ba7cb5
--- /dev/null
+++ b/hw/bsp/apm32f0xx/family.cmake
@@ -0,0 +1,83 @@
+include_guard()
+
+set(APM32_FAMILY apm32f0xx)
+set(APM32_SDK ${TOP}/hw/mcu/geehy/APM32F0xx_SDK/Libraries)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m0plus CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS APM32F0XX CACHE INTERNAL "")
+
+#------------------------------------
+# Startup & Linker script
+#------------------------------------
+set(STARTUP_FILE_GNU ${APM32_SDK}/Device/Geehy/APM32F0xx/Source/gcc/startup_apm32f072.S)
+set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+if (NOT DEFINED LD_FILE_GNU)
+set(LD_FILE_GNU ${APM32_SDK}/Device/Geehy/APM32F0xx/Source/gcc/gcc_${MCU_LINKER_NAME}.ld)
+endif ()
+set(LD_FILE_Clang ${LD_FILE_GNU})
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+function(family_add_board BOARD_TARGET)
+ add_library(${BOARD_TARGET} STATIC
+ ${APM32_SDK}/Device/Geehy/APM32F0xx/Source/system_apm32f0xx.c
+ ${APM32_SDK}/APM32F0xx_StdPeriphDriver/src/apm32f0xx_gpio.c
+ ${APM32_SDK}/APM32F0xx_StdPeriphDriver/src/apm32f0xx_misc.c
+ ${APM32_SDK}/APM32F0xx_StdPeriphDriver/src/apm32f0xx_rcm.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${APM32_SDK}/CMSIS/Include
+ ${APM32_SDK}/Device/Geehy/APM32F0xx/Include
+ ${APM32_SDK}/APM32F0xx_StdPeriphDriver/inc
+ )
+
+ update_board(${BOARD_TARGET})
+endfunction()
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+ family_add_tinyusb(${TARGET} OPT_MCU_APM32F0XX)
+
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+ ${TOP}/src/portable/st/stm32_fsdev/fsdev_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}"
+ )
+ 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/apm32f0xx/family.mk b/hw/bsp/apm32f0xx/family.mk
new file mode 100644
index 000000000..7e26918c2
--- /dev/null
+++ b/hw/bsp/apm32f0xx/family.mk
@@ -0,0 +1,38 @@
+APM32_FAMILY = apm32f0xx
+APM32_SDK = hw/mcu/geehy/APM32F0xx_SDK/Libraries
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CPU_CORE ?= cortex-m0plus
+
+CFLAGS += \
+ -flto
+
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_APM32F0XX
+
+LDFLAGS += \
+ -flto --specs=nosys.specs -nostdlib -nostartfiles
+
+SRC_C += \
+ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \
+ src/portable/st/stm32_fsdev/fsdev_common.c \
+ $(APM32_SDK)/APM32F0xx_StdPeriphDriver/src/apm32f0xx_gpio.c \
+ $(APM32_SDK)/APM32F0xx_StdPeriphDriver/src/apm32f0xx_misc.c \
+ $(APM32_SDK)/APM32F0xx_StdPeriphDriver/src/apm32f0xx_rcm.c \
+ $(APM32_SDK)/Device/Geehy/APM32F0xx/Source/system_apm32f0xx.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(APM32_SDK)/APM32F0xx_StdPeriphDriver/inc \
+ $(TOP)/$(APM32_SDK)/CMSIS/Include \
+ $(TOP)/$(APM32_SDK)/Device/Geehy/APM32F0xx/Include
+
+SRC_S += $(APM32_SDK)/Device/Geehy/APM32F0xx/Source/gcc/startup_apm32f072.S
+
+LD_FILE ?= $(APM32_SDK)/Device/Geehy/APM32F0xx/Source/gcc/gcc_${MCU_LINKER_NAME}.ld
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM0
+
+flash: flash-jlink
diff --git a/hw/bsp/ch32v10x/family.cmake b/hw/bsp/ch32v10x/family.cmake
index fb9ccb3a3..287b8c2ff 100644
--- a/hw/bsp/ch32v10x/family.cmake
+++ b/hw/bsp/ch32v10x/family.cmake
@@ -93,6 +93,6 @@ function(family_configure_example TARGET RTOS)
# Flashing
family_add_bin_hex(${TARGET})
- family_flash_openocd_wch(${TARGET})
+ family_flash_openocd(${TARGET})
#family_flash_uf2(${TARGET} ${UF2_FAMILY_ID})
endfunction()
diff --git a/hw/bsp/ch32v10x/family.mk b/hw/bsp/ch32v10x/family.mk
index fb699b0bb..443509699 100644
--- a/hw/bsp/ch32v10x/family.mk
+++ b/hw/bsp/ch32v10x/family.mk
@@ -49,5 +49,5 @@ INC += \
FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V
-OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
+OPENOCD_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
flash: flash-openocd-wch
diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c
index 76024cfde..8875e4faa 100644
--- a/hw/bsp/ch32v20x/family.c
+++ b/hw/bsp/ch32v20x/family.c
@@ -27,25 +27,25 @@ manufacturer: WCH
* - CFG_TUD_WCH_USBIP_USBFS
*/
-// Port0: USBD (fsdev)
-__attribute__((interrupt)) __attribute__((used)) void USB_LP_CAN1_RX0_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-}
-
-__attribute__((interrupt)) __attribute__((used)) void USB_HP_CAN1_TX_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-
-}
-
-__attribute__((interrupt)) __attribute__((used)) void USBWakeUp_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-}
+// Port0: USBD (fsdev). The USBD raises three IRQ lines (LP/HP/WakeUp) that all funnel into the
+// non-reentrant tud_int_handler and can nest (HP preempts LP) with QingKe HWSTK enabled. The
+// mainline toolchain's plain __attribute__((interrupt)) emits a software prologue that fights the
+// hardware context stack and corrupts the return on nesting. Emit naked handlers that rely on
+// HWSTK for context save/restore (equivalent to WCH's "WCH-Interrupt-fast"), which nests safely.
+#if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_FSDEV
+ // The `call dcd_int_handler` below lives inside naked asm where LTO cannot see it; without a
+ // compiler-visible reference, -flto builds (make) internalize/drop the symbol and the link fails.
+ TU_ATTR_USED static void (*const fsdev_isr_keep)(uint8_t) = dcd_int_handler;
+ #define FSDEV_NAKED_ISR(name) \
+ __attribute__((naked)) __attribute__((used)) void name(void) { \
+ __asm volatile("li a0, 0\n\t call dcd_int_handler\n\t mret"); }
+#else
+ #define FSDEV_NAKED_ISR(name) \
+ __attribute__((naked)) __attribute__((used)) void name(void) { __asm volatile("mret"); }
+#endif
+FSDEV_NAKED_ISR(USB_LP_CAN1_RX0_IRQHandler)
+FSDEV_NAKED_ISR(USB_HP_CAN1_TX_IRQHandler)
+FSDEV_NAKED_ISR(USBWakeUp_IRQHandler)
// Port1: USBFS
__attribute__((interrupt)) __attribute__((used)) void USBHD_IRQHandler(void) {
diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake
index 785f5ee35..a27ff021e 100644
--- a/hw/bsp/ch32v20x/family.cmake
+++ b/hw/bsp/ch32v20x/family.cmake
@@ -125,7 +125,7 @@ function(family_configure_example TARGET RTOS)
# Flashing
family_add_bin_hex(${TARGET})
- family_flash_openocd_wch(${TARGET})
+ family_flash_openocd(${TARGET})
family_flash_wlink_rs(${TARGET})
#family_flash_uf2(${TARGET} ${UF2_FAMILY_ID})
endfunction()
diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk
index 1d059bcba..1889c4e26 100644
--- a/hw/bsp/ch32v20x/family.mk
+++ b/hw/bsp/ch32v20x/family.mk
@@ -63,6 +63,6 @@ INC += \
FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V
-OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
+OPENOCD_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
flash: flash-wlink-rs
#flash: flash-openocd-wch
diff --git a/hw/bsp/ch32v30x/family.c b/hw/bsp/ch32v30x/family.c
index aee4e7d4f..02c3c7d44 100644
--- a/hw/bsp/ch32v30x/family.c
+++ b/hw/bsp/ch32v30x/family.c
@@ -29,6 +29,7 @@
*/
#include "stdio.h"
+#include <string.h>
// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
@@ -166,6 +167,14 @@ uint32_t board_button_read(void) {
#endif
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ volatile uint32_t* ch32_uuid = ((volatile uint32_t*) 0x1FFFF7E8UL); // ESIG unique ID
+ uint32_t uid[3] = { ch32_uuid[0], ch32_uuid[1], ch32_uuid[2] };
+ const size_t len = max_len < sizeof(uid) ? max_len : sizeof(uid);
+ memcpy(id, uid, len); // byte copy: id[] need not be 4-byte aligned
+ return len;
+}
+
int board_uart_read(uint8_t* buf, int len) {
(void) buf;
(void) len;
diff --git a/hw/bsp/ch32v30x/family.cmake b/hw/bsp/ch32v30x/family.cmake
index b974bd5e7..e33e4b85d 100644
--- a/hw/bsp/ch32v30x/family.cmake
+++ b/hw/bsp/ch32v30x/family.cmake
@@ -115,6 +115,6 @@ function(family_configure_example TARGET RTOS)
# Flashing
family_add_bin_hex(${TARGET})
- family_flash_openocd_wch(${TARGET})
+ family_flash_openocd(${TARGET})
family_flash_wlink_rs(${TARGET})
endfunction()
diff --git a/hw/bsp/ch32v30x/family.mk b/hw/bsp/ch32v30x/family.mk
index 5ccdea8ae..59778ec54 100644
--- a/hw/bsp/ch32v30x/family.mk
+++ b/hw/bsp/ch32v30x/family.mk
@@ -62,5 +62,5 @@ LD_FILE ?= $(FAMILY_PATH)/linker/ch32v30x.ld
# For freeRTOS port source
FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V
-OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
+OPENOCD_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
flash: flash-openocd-wch
diff --git a/hw/bsp/ch583/family.cmake b/hw/bsp/ch583/family.cmake
index a379298e5..f4b874e4e 100644
--- a/hw/bsp/ch583/family.cmake
+++ b/hw/bsp/ch583/family.cmake
@@ -104,5 +104,5 @@ function(family_configure_example TARGET RTOS)
# Flashing
family_add_bin_hex(${TARGET})
- family_flash_openocd_wch(${TARGET})
+ family_flash_openocd(${TARGET})
endfunction()
diff --git a/hw/bsp/ch583/family.mk b/hw/bsp/ch583/family.mk
index 98d0f9337..3444c4811 100644
--- a/hw/bsp/ch583/family.mk
+++ b/hw/bsp/ch583/family.mk
@@ -52,7 +52,7 @@ INC += \
LD_FILE ?= $(FAMILY_PATH)/linker/ch582.ld
-OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
+OPENOCD_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg
flash: flash-openocd-wch
# For freeRTOS port source
diff --git a/hw/bsp/ch583/wch-riscv.cfg b/hw/bsp/ch583/wch-riscv.cfg
index 64d595d8e..aa35aa9c5 100644
--- a/hw/bsp/ch583/wch-riscv.cfg
+++ b/hw/bsp/ch583/wch-riscv.cfg
@@ -9,7 +9,7 @@ sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME
-$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 0x8000 -work-area-backup 1
+$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
diff --git a/hw/bsp/family_rules.mk b/hw/bsp/family_rules.mk
index ccf49dd0e..011572888 100644
--- a/hw/bsp/family_rules.mk
+++ b/hw/bsp/family_rules.mk
@@ -130,20 +130,18 @@ flash-pyocd: $(BUILD)/$(PROJECT).hex
#pyocd reset -t $(PYOCD_TARGET)
# --------------- openocd -----------------
+# OPENOCD can name another build, e.g. one of the vendor forks, though
+# https://github.com/hathach/openocd branch tinyusb covers every board here
+OPENOCD ?= openocd
OPENOCD_OPTION ?=
flash-openocd: $(BUILD)/$(PROJECT).elf
- openocd $(OPENOCD_OPTION) -c "program $< verify reset exit"
+ $(OPENOCD) $(OPENOCD_OPTION) -c "program $< verify reset exit"
# --------------- openocd-wch -----------------
-# wch-linke is not supported yet in official openOCD yet. We need to either use
-# 1. download openocd as part of mounriver studio http://www.mounriver.com/download or
-# 2. compiled from https://github.com/hathach/riscv-openocd-wch or
-# https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz
-# with ./configure --disable-werror --enable-wlinke --enable-ch347=no
-OPENOCD_WCH ?= /home/${USER}/app/riscv-openocd-wch/src/openocd
-OPENOCD_WCH_OPTION ?=
+# WCH parts need an openocd built with the wlinke adapter. The image is written
+# without verify: WCH code flash is not readable back over the debug bus.
flash-openocd-wch: $(BUILD)/$(PROJECT).elf
- $(OPENOCD_WCH) $(OPENOCD_WCH_OPTION) -c init -c halt -c "flash write_image $<" -c reset -c exit
+ $(OPENOCD) $(OPENOCD_OPTION) -c init -c halt -c "flash write_image $<" -c reset -c exit
# --------------- wlink-rs -----------------
# flash with https://github.com/ch32-rs/wlink
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
index 1f3952205..33ceb49c2 100644
--- a/hw/bsp/family_support.cmake
+++ b/hw/bsp/family_support.cmake
@@ -688,7 +688,9 @@ function(family_flash_stflash TARGET)
endfunction()
-# Add flash openocd target
+# Add flash openocd target.
+# The default 'openocd' should be https://github.com/hathach/openocd (branch tinyusb): which is mainline plus
+# every config the rig needs (RP2350, MAX32/MAX78, WCH) and a drop-in superset of the vendor (downstream) forks
function(family_flash_openocd TARGET)
if (NOT DEFINED OPENOCD)
set(OPENOCD openocd)
@@ -715,38 +717,20 @@ function(family_flash_openocd TARGET)
#set_property(TARGET ${TARGET}-openocd PROPERTY FOLDER ${TARGET}-group)
endfunction()
-
-# Add flash openocd-wch target
-# compiled from https://github.com/hathach/riscv-openocd-wch or https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz
-function(family_flash_openocd_wch TARGET)
- if (NOT DEFINED OPENOCD)
- set(OPENOCD $ENV{HOME}/app/riscv-openocd-wch/src/openocd)
+# Add flash openocd adi (Analog Devices) target using the openocd included
+# with msdk (MAXIM_PATH), otherwise the default openocd
+function(family_flash_openocd_adi TARGET)
+ # use openocd from msdk if MAXIM_PATH is set, as cmake variable or in the
+ # environment. Normalize the latter since msdk can be Windows (MinGW) or Linux
+ if (NOT DEFINED MAXIM_PATH AND DEFINED ENV{MAXIM_PATH})
+ file(TO_CMAKE_PATH "$ENV{MAXIM_PATH}" MAXIM_PATH)
endif ()
- family_flash_openocd(${TARGET})
-endfunction()
-
-
-# Add flash openocd adi (Analog Devices) target
-# included with msdk or compiled from release branch of https://github.com/analogdevicesinc/openocd
-function(family_flash_openocd_adi TARGET)
- if (DEFINED MAXIM_PATH)
- # use openocd from msdk with MAXIM_PATH cmake variable first if the user specified it
- set(OPENOCD ${MAXIM_PATH}/Tools/OpenOCD/openocd)
- set(OPENOCD_OPTION2 "-s ${MAXIM_PATH}/Tools/OpenOCD/scripts")
- elseif (DEFINED ENV{MAXIM_PATH})
- # use openocd from msdk with MAXIM_PATH environment variable. Normalize
- # since msdk can be Windows (MinGW) or Linux
- file(TO_CMAKE_PATH "$ENV{MAXIM_PATH}" MAXIM_PATH_NORM)
- set(OPENOCD ${MAXIM_PATH_NORM}/Tools/OpenOCD/openocd)
- set(OPENOCD_OPTION2 "-s ${MAXIM_PATH_NORM}/Tools/OpenOCD/scripts")
- else()
- # compiled from source
- if (NOT DEFINED OPENOCD_ADI_PATH)
- set(OPENOCD_ADI_PATH $ENV{HOME}/app/openocd_adi)
+ if (MAXIM_PATH)
+ if (NOT DEFINED OPENOCD)
+ set(OPENOCD ${MAXIM_PATH}/Tools/OpenOCD/openocd)
endif ()
- set(OPENOCD ${OPENOCD_ADI_PATH}/src/openocd)
- set(OPENOCD_OPTION2 "-s ${OPENOCD_ADI_PATH}/tcl")
+ set(OPENOCD_OPTION2 "-s ${MAXIM_PATH}/Tools/OpenOCD/scripts")
endif ()
family_flash_openocd(${TARGET})
diff --git a/hw/bsp/imxrt/boards/metro_m7_1011/ozone/metro_m7_1011.jdebug b/hw/bsp/imxrt/boards/metro_m7_1011/ozone/metro_m7_1011.jdebug
index 90f9b77e5..80489b61c 100644
--- a/hw/bsp/imxrt/boards/metro_m7_1011/ozone/metro_m7_1011.jdebug
+++ b/hw/bsp/imxrt/boards/metro_m7_1011/ozone/metro_m7_1011.jdebug
@@ -10,6 +10,7 @@
*/
void OnProjectLoad (void) {
Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
Project.SetTraceTiming (50, 50, 50, 50);
Project.SetDevice ("MIMXRT1011xxx4A");
Project.SetHostIF ("USB", "");
@@ -22,7 +23,7 @@ void OnProjectLoad (void) {
// timing delay for trace pins in pico seconds, default is 2 nano seconds
- File.Open ("../../../../../../examples/cmake-build-metro-m7-1011-sd/device/cdc_msc/cdc_msc.elf");
+ File.Open ("../../../../../../examples/cmake-build-metro_m7_1011/device/cdc_msc/cdc_msc.elf");
}
/*********************************************************************
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
index a6332d896..c041fd47b 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
@@ -35,6 +35,11 @@
// required since iMXRT MCUX-SDK include this file for board size
#define BOARD_FLASH_SIZE (0x1000000U)
+// TRACE_ETM: this board wires the 100M PHY reset (ENET_RST_B) to
+// GPIO_LPSR_04; the family trace init holds it in reset (RMII lines share
+// the trace pads)
+#define TRACE_ETM_QUIET_ENET_PHY 1
+
// LED: IOMUXC_GPIO_AD_04_GPIO9_IO03
#define LED_PORT BOARD_INITPINS_USER_LED_PERIPHERAL
#define LED_PIN BOARD_INITPINS_USER_LED_CHANNEL
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176.jdebug b/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176.jdebug
new file mode 100644
index 000000000..6931b9cd1
--- /dev/null
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176.jdebug
@@ -0,0 +1,69 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* MIMXRT1170-EVKB trace requires board rework: the TRACE pads
+* (GPIO_DISP_B2_02..06) are factory-wired to the ENET_1G PHY - populate
+* 0-ohm R1881-R1886 to route them to the Cortex Debug+ETM connector J58
+* (EVKB Hardware User Guide 3.2).
+* Firmware must be built with TRACE_ETM=1 (trace pad mux + CSTRACE clock
+* + JTAG_nTRST/DMIC_DATA1 pad fix in board_init).
+*
+* Validated: port width 1, 0 ns sample timing, 50 MHz CSTRACE root
+* (25 MHz TRACE_CLK pin, set by trace_etm_init - the rework path corrupts
+* at the stock 132 MHz root) while the CM7 runs 996 MHz. A startup-burst
+* trace overflow is expected and benign; width 4 fails at any timing.
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ // declares the CSSYS TPIU/funnel (system APB-AP, not in the CM7 ROM table)
+ Project.SetJLinkScript ("./mimxrt1176_trace.JLinkScript");
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (1);
+ Project.SetTraceTiming (0, 0, 0, 0);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 996000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M7F.svd");
+
+ Project.SetDevice ("MIMXRT1176xxxA_M7");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-mimxrt1170_evkb/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* JTAG_nTRST shares its pad with DMIC_DATA1, which drives it low by
+* default and kills ETM trace - mux the pad to GPIO before the app runs
+* (EVKB Hardware User Guide 3.2). No SP/PC init here: the app boots from
+* FlexSPI NOR, so the ROM bootloader must perform it (SEGGER wiki
+* "i.MXRT1176" / NXP community solution for ERR050708 boards).
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ Target.WriteU32 (0x40C08028, 0xA); // IOMUXC GPIO_LPSR_10 -> GPIO12_IO10
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Intentionally empty: SP/PC init from the vector table would bypass the
+* ROM bootloader's FlexSPI setup (see AfterTargetReset note).
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+}
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176_trace.JLinkScript b/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176_trace.JLinkScript
new file mode 100644
index 000000000..ef39235d8
--- /dev/null
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/ozone/mimxrt1176_trace.JLinkScript
@@ -0,0 +1,11 @@
+/* RT1176 pin trace: the CSSYS TPIU and ATB funnel live on the system APB-AP
+ * (AP2) and are not discoverable from the CM7 ROM table - declare them, or
+ * J-Link aborts with "Required trace components for pin trace not found!"
+ * (addresses per i.MX RT1170 RM memory map: CSSYS TPIU E004_6000, CSSYS ATB
+ * Funnel E004_5000; same values as SEGGER's RT1176 trace example script).
+ */
+int ConfigTargetSettings(void) {
+ JLINK_ExecCommand("CORESIGHT_SetTPIUBaseAddr = 0xE0046000 ForceUnlock = 1 APIndex = 2");
+ JLINK_ExecCommand("CORESIGHT_SetCSTFBaseAddr = 0xE0045000 ForceUnlock = 1 APIndex = 2");
+ return 0;
+}
diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c
index 9f3297e9a..4bd7993f0 100644
--- a/hw/bsp/imxrt/family.c
+++ b/hw/bsp/imxrt/family.c
@@ -106,6 +106,74 @@ static void init_usb_phy(uint8_t usb_id) {
usb_phy->TX = phytx;
}
+#ifdef TRACE_ETM
+static void trace_etm_init(void) {
+#if defined(CPU_MIMXRT1011DAE5A)
+ // Metro M7 rev A "ETM Trace" rework: 4-bit TRACE + TRACE_CLK on the added
+ // 2x10 header; the RT1011 has a single mux option per trace signal
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_00_ARM_TRACE0, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_13_ARM_TRACE1, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_12_ARM_TRACE2, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_11_ARM_TRACE3, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_02_ARM_TRACE_CLK, 0U);
+ // fast slew, max speed, high drive
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_00_ARM_TRACE0, 0x00F1U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_13_ARM_TRACE1, 0x00F1U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_12_ARM_TRACE2, 0x00F1U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_11_ARM_TRACE3, 0x00F1U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_02_ARM_TRACE_CLK, 0x00F1U);
+
+ // TRACE_CLK_ROOT already runs 132 MHz (PLL2/4) from BOARD_BootClockRUN,
+ // which leaves it gated - just ungate
+ CLOCK_EnableClock(kCLOCK_Trace);
+#elif defined(CPU_MIMXRT1176DVMAA_cm7)
+ // JTAG_nTRST pad is shared with DMIC_DATA1 which drives it low by default and
+ // breaks ETM trace - switch the pad to GPIO (MIMXRT1170-EVKB HUG 3.2)
+ IOMUXC_SetPinMux(IOMUXC_GPIO_LPSR_10_GPIO12_IO10, 0U);
+
+#ifdef TRACE_ETM_QUIET_ENET_PHY
+ // Hold the 100M Ethernet PHY (RTL8201) in reset: its RMII lines are
+ // hardwired to the trace pads and drive against the stream at speed. The
+ // reset net is a BOARD property (mimxrt1170_evkb: ENET_RST_B =
+ // GPIO_LPSR_04), hence the board.h gate.
+ IOMUXC_SetPinMux(IOMUXC_GPIO_LPSR_04_GPIO12_IO04, 0U);
+ GPIO12->GDIR |= (1U << 4);
+ GPIO12->DR &= ~(1U << 4);
+#endif
+
+ // TRACE0-3 + TRACE_CLK on GPIO_DISP_B2_02..06, fast slew + high drive
+ IOMUXC_SetPinMux(IOMUXC_GPIO_DISP_B2_02_ARM_TRACE00, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_DISP_B2_03_ARM_TRACE01, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_DISP_B2_04_ARM_TRACE02, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_DISP_B2_05_ARM_TRACE03, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_DISP_B2_06_ARM_TRACE_CLK, 0U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_DISP_B2_02_ARM_TRACE00, IOMUXC_SW_PAD_CTL_PAD_DSE_MASK);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_DISP_B2_03_ARM_TRACE01, IOMUXC_SW_PAD_CTL_PAD_DSE_MASK);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_DISP_B2_04_ARM_TRACE02, IOMUXC_SW_PAD_CTL_PAD_DSE_MASK);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_DISP_B2_05_ARM_TRACE03, IOMUXC_SW_PAD_CTL_PAD_DSE_MASK);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_DISP_B2_06_ARM_TRACE_CLK, IOMUXC_SW_PAD_CTL_PAD_DSE_MASK);
+
+ // 100 MHz CSTRACE root (OscRc400M/4) -> 50 MHz TRACE_CLK pin (= root/2).
+ // With the PHY held in reset the CLK line is clean here; 133 MHz root
+ // (66 MHz pin) is marginal on this board, stock 132 MHz corrupts.
+ CLOCK_SetRootClockMux(kCLOCK_Root_Cstrace, kCLOCK_CSTRACE_ClockRoot_MuxOscRc400M);
+ CLOCK_SetRootClockDiv(kCLOCK_Root_Cstrace, 4);
+ CLOCK_EnableClock(kCLOCK_Cstrace);
+
+ // Enable the CM7 slave port on the platform trace funnel (E004_3000): the
+ // debugger only programs the CSSYS funnel/TPIU it was told about, and this
+ // in-between funnel resets with all ports disabled, silently eating the ETM
+ // stream. Core-side CoreSight accesses honor the lock, hence the LAR unlock.
+ *(volatile uint32_t *) 0xE0043FB0 = 0xC5ACCE55;
+ *(volatile uint32_t *) 0xE0043000 |= 1U;
+#else
+ #error "TRACE_ETM: no trace pin setup for this MCU variant"
+#endif
+}
+#else
+ #define trace_etm_init()
+#endif
+
void board_init(void) {
// make sure the dcache is on.
#if defined(__DCACHE_PRESENT) && __DCACHE_PRESENT
@@ -119,10 +187,7 @@ void board_init(void) {
SystemCoreClockUpdate();
BOARD_ConfigMPU(); // defined in board.h
-
-#ifdef TRACE_ETM
- //CLOCK_EnableClock(kCLOCK_Trace);
-#endif
+ trace_etm_init();
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
diff --git a/hw/bsp/kinetis_k/family.c b/hw/bsp/kinetis_k/family.c
index a5af83931..2df3313b8 100644
--- a/hw/bsp/kinetis_k/family.c
+++ b/hw/bsp/kinetis_k/family.c
@@ -35,10 +35,25 @@
#include "fsl_clock.h"
#include "fsl_uart.h"
#include "fsl_sysmpu.h"
+#include "common/tusb_fifo.h"
#include "board/clock_config.h"
#include "board/pin_mux.h"
+#ifdef UART_DEV
+// RX ring buffer filled by the RDRF interrupt so board_uart_read() is non-blocking
+// and does not drop bytes to UART overrun (see stm32 family for reference).
+static uint8_t uart_rx_ff_buf[32];
+static tu_fifo_t uart_rx_ff;
+
+void UART0_RX_TX_IRQHandler(void) {
+ if (UART_DEV->S1 & UART_S1_RDRF_MASK) {
+ uint8_t byte = UART_DEV->D; // reading S1 then D clears RDRF (and any overrun)
+ tu_fifo_write(&uart_rx_ff, &byte);
+ }
+}
+#endif
+
//--------------------------------------------------------------------+
// Forward USB interrupt events to TinyUSB IRQ Handler
//--------------------------------------------------------------------+
@@ -89,6 +104,9 @@ void board_init(void) {
.enableRx = true
};
UART_Init(UART_DEV, &uart_config, UART_CLOCK);
+ tu_fifo_config(&uart_rx_ff, uart_rx_ff_buf, sizeof(uart_rx_ff_buf), false);
+ UART_DEV->C2 |= UART_C2_RIE_MASK; // enable RX data register full interrupt
+ NVIC_EnableIRQ(UART0_RX_TX_IRQn);
#endif
// USB
@@ -112,14 +130,11 @@ uint32_t board_button_read(void) {
}
int board_uart_read(uint8_t *buf, int len) {
- (void) buf;
- (void) len;
#ifdef UART_DEV
- // Read blocking will block until there is data
-// UART_ReadBlocking(UART_DEV, buf, len);
-// return len;
- return 0;
+ return (int) tu_fifo_read_n(&uart_rx_ff, buf, (uint16_t) len);
#else
+ (void) buf;
+ (void) len;
return 0;
#endif
}
@@ -144,6 +159,19 @@ int board_uart_write(void const *buf, int len) {
#endif
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ // Kinetis 128-bit Unique Identification Register (SIM->UIDH/UIDMH/UIDML/UIDL)
+ uint32_t* id32 = (uint32_t*) (uintptr_t) id;
+
+ id32[0] = SIM->UIDH;
+ id32[1] = SIM->UIDMH;
+ id32[2] = SIM->UIDML;
+ id32[3] = SIM->UIDL;
+
+ return 16;
+}
+
#if CFG_TUSB_OS == OPT_OS_NONE
volatile uint32_t system_ticks = 0;
diff --git a/hw/bsp/kinetis_k/family.cmake b/hw/bsp/kinetis_k/family.cmake
index e1b5c221e..e408c0f4a 100644
--- a/hw/bsp/kinetis_k/family.cmake
+++ b/hw/bsp/kinetis_k/family.cmake
@@ -63,7 +63,7 @@ function(family_configure_example TARGET RTOS)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
${TOP}/src/portable/chipidea/ci_fs/dcd_ci_fs.c
- ${TOP}/src/portable/nxp/khci/hcd_khci.c
+ ${TOP}/src/portable/chipidea/ci_fs/hcd_ci_fs.c
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
)
target_include_directories(${TARGET} PUBLIC
diff --git a/hw/bsp/kinetis_k/family.mk b/hw/bsp/kinetis_k/family.mk
index b1e1fb3aa..5d0e4a702 100644
--- a/hw/bsp/kinetis_k/family.mk
+++ b/hw/bsp/kinetis_k/family.mk
@@ -17,8 +17,8 @@ LDFLAGS += \
--specs=nosys.specs --specs=nano.specs \
SRC_C += \
- src/portable/nxp/khci/dcd_khci.c \
- src/portable/nxp/khci/hcd_khci.c \
+ src/portable/chipidea/ci_fs/dcd_ci_fs.c \
+ src/portable/chipidea/ci_fs/hcd_ci_fs.c \
$(MCU_DIR)/system_${MCU_VARIANT}.c \
$(MCU_DIR)/drivers/fsl_clock.c \
$(SDK_DIR)/drivers/gpio/fsl_gpio.c \
diff --git a/hw/bsp/kinetis_k32l/family.cmake b/hw/bsp/kinetis_k32l/family.cmake
index 020695589..950682363 100644
--- a/hw/bsp/kinetis_k32l/family.cmake
+++ b/hw/bsp/kinetis_k32l/family.cmake
@@ -64,8 +64,8 @@ function(family_configure_example TARGET RTOS)
target_sources(${TARGET} PUBLIC
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- ${TOP}/src/portable/nxp/khci/dcd_khci.c
- ${TOP}/src/portable/nxp/khci/hcd_khci.c
+ ${TOP}/src/portable/chipidea/ci_fs/dcd_ci_fs.c
+ ${TOP}/src/portable/chipidea/ci_fs/hcd_ci_fs.c
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
)
target_include_directories(${TARGET} PUBLIC
diff --git a/hw/bsp/kinetis_k32l/family.mk b/hw/bsp/kinetis_k32l/family.mk
index a99fb5dbe..357128aa5 100644
--- a/hw/bsp/kinetis_k32l/family.mk
+++ b/hw/bsp/kinetis_k32l/family.mk
@@ -13,8 +13,8 @@ LDFLAGS += \
-specs=nosys.specs -specs=nano.specs
SRC_C += \
- src/portable/nxp/khci/dcd_khci.c \
- src/portable/nxp/khci/hcd_khci.c \
+ src/portable/chipidea/ci_fs/dcd_ci_fs.c \
+ src/portable/chipidea/ci_fs/hcd_ci_fs.c \
$(MCUX_DEVICES)/K32L/$(MCU_VARIANT)/system_$(MCU_VARIANT).c \
$(MCUX_DEVICES)/K32L/$(MCU_VARIANT)/drivers/fsl_clock.c \
$(MCUX_CORE)/drivers/gpio/fsl_gpio.c \
diff --git a/hw/bsp/kinetis_kl/family.cmake b/hw/bsp/kinetis_kl/family.cmake
index 230a3057d..b74f4f8b9 100644
--- a/hw/bsp/kinetis_kl/family.cmake
+++ b/hw/bsp/kinetis_kl/family.cmake
@@ -62,7 +62,7 @@ function(family_configure_example TARGET RTOS)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
${TOP}/src/portable/chipidea/ci_fs/dcd_ci_fs.c
- ${TOP}/src/portable/nxp/khci/hcd_khci.c
+ ${TOP}/src/portable/chipidea/ci_fs/hcd_ci_fs.c
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
)
target_include_directories(${TARGET} PUBLIC
diff --git a/hw/bsp/kinetis_kl/family.mk b/hw/bsp/kinetis_kl/family.mk
index 201ab99dc..9c780a868 100644
--- a/hw/bsp/kinetis_kl/family.mk
+++ b/hw/bsp/kinetis_kl/family.mk
@@ -17,8 +17,8 @@ LDFLAGS += \
-specs=nosys.specs -specs=nano.specs \
SRC_C += \
- src/portable/nxp/khci/dcd_khci.c \
- src/portable/nxp/khci/hcd_khci.c \
+ src/portable/chipidea/ci_fs/dcd_ci_fs.c \
+ src/portable/chipidea/ci_fs/hcd_ci_fs.c \
$(MCU_DIR)/system_$(MCU).c \
$(MCU_DIR)/drivers/fsl_clock.c \
$(SDK_DIR)/drivers/gpio/fsl_gpio.c \
diff --git a/hw/bsp/lpc11/boards/lpcxpresso11u37/board.mk b/hw/bsp/lpc11/boards/lpcxpresso11u37/board.mk
index fdc17374b..718c46bbf 100644
--- a/hw/bsp/lpc11/boards/lpcxpresso11u37/board.mk
+++ b/hw/bsp/lpc11/boards/lpcxpresso11u37/board.mk
@@ -4,8 +4,7 @@ MCU_DRV = 11xx
CFLAGS += \
-DCORE_M0 \
-DCFG_EXAMPLE_MSC_READONLY \
- -DCFG_EXAMPLE_VIDEO_READONLY \
- -DCFG_TUSB_MEM_SECTION='__attribute__((section(".data.$$RAM2")))'
+ -DCFG_EXAMPLE_VIDEO_READONLY
# mcu driver cause following warnings
CFLAGS += \
diff --git a/hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld b/hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld
index 8e0a4e4c6..b7237a3ec 100644
--- a/hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld
+++ b/hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld
@@ -172,6 +172,22 @@ SECTIONS
. = ALIGN(4) ;
_end_noinit = .;
} > RamLoc8
+ /* Main (MSP/ISR) stack lives at the top of the USB SRAM bank: the 8K main bank is packed so
+ tight that only ~280 B remained above .bss, and ISR frames overflowed into the topmost task
+ stack (cdc_msc_freertos hard fault). Nothing else is placed in this bank in either build
+ system, so the stack owns all 2 KB; the ASSERT is future-proofing in case USB buffers are
+ ever mapped here again.
+
+ This bank is clocked by SYSAHBCLKCTRL[27] (USBRAM enable), and the stack is used from the
+ first instruction of the reset handler - long before any TinyUSB or BSP code could turn a
+ clock on. It works because the boot ROM hands over with that bit already set. Anything that
+ gates the USB RAM clock to save power will hard fault at reset, not at USB init. */
+ __user_stack_top = ORIGIN(RamUsb2) + LENGTH(RamUsb2);
+ /* Stated as an addition, not a subtraction: ld arithmetic is unsigned, so an overflowing
+ bank would underflow the difference into a huge positive value and pass silently. */
+ ASSERT(ADDR(.noinit_RAM2) + SIZEOF(.noinit_RAM2) + 0x200 <= __user_stack_top,
+ "main stack headroom in RamUsb2 below 512 bytes")
+
PROVIDE(_pvHeapStart = DEFINED(__user_heap_base) ? __user_heap_base : .);
PROVIDE(_vStackTop = DEFINED(__user_stack_top) ? __user_stack_top : __top_RamLoc8 - 0);
diff --git a/hw/bsp/lpc15/family.c b/hw/bsp/lpc15/family.c
index bbfee1b51..5178ad68b 100644
--- a/hw/bsp/lpc15/family.c
+++ b/hw/bsp/lpc15/family.c
@@ -122,6 +122,19 @@ uint32_t board_button_read(void)
return Chip_GPIO_GetPinState(LPC_GPIO, BUTTON_PORT, BUTTON_PIN) ? 0 : 1;
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len)
+{
+ // IAP ReadUID (cmd 58) returns status + 4 words = full 128-bit UID
+ unsigned int command[5] = { IAP_READ_UID_CMD, 0, 0, 0, 0 };
+ unsigned int result[5];
+ iap_entry(command, result);
+ TU_ASSERT(result[0] == IAP_CMD_SUCCESS, 0);
+
+ size_t const len = tu_min32(max_len, 16);
+ memcpy(id, &result[1], len);
+ return len;
+}
+
int board_uart_read(uint8_t* buf, int len)
{
(void) buf; (void) len;
diff --git a/hw/bsp/lpc18/boards/lpcxpresso18s37/board.h b/hw/bsp/lpc18/boards/lpcxpresso18s37/board.h
index 2cf4dbdf8..1be07c49e 100644
--- a/hw/bsp/lpc18/boards/lpcxpresso18s37/board.h
+++ b/hw/bsp/lpc18/boards/lpcxpresso18s37/board.h
@@ -76,6 +76,12 @@ static inline void board_lpc18_pinmux(void)
Chip_SCU_SetPinMuxing(pinmuxing, sizeof(pinmuxing) / sizeof(PINMUX_GRP_T));
}
+
+// TRACE_ETM builds: no trace header is wired out on the LPCXpresso18S37 -
+// provide the no-op the family init expects (see mcb1800/ea4357 for a
+// board that routes the trace pins)
+static inline void board_trace_pinmux(void) {}
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/lpc18/boards/mcb1800/board.h b/hw/bsp/lpc18/boards/mcb1800/board.h
index dba7a62a3..ec7f1fa95 100644
--- a/hw/bsp/lpc18/boards/mcb1800/board.h
+++ b/hw/bsp/lpc18/boards/mcb1800/board.h
@@ -48,15 +48,6 @@
static inline void board_lpc18_pinmux(void) {
const PINMUX_GRP_T pinmuxing[] = {
- // ETM Trace
- #ifdef TRACE_ETM
- { 0xF, 4, SCU_MODE_FUNC2 | SCU_MODE_HIGHSPEEDSLEW_EN },
- { 0xF, 5, SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
- { 0xF, 6, SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
- { 0xF, 7, SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
- { 0xF, 8, SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
- #endif
-
// LEDs
{ 0xD, 10, (SCU_MODE_INBUFF_EN | SCU_MODE_INACT | SCU_MODE_FUNC4) },
{ 0xD, 11, (SCU_MODE_INBUFF_EN | SCU_MODE_INACT | SCU_MODE_FUNC4 | SCU_MODE_PULLDOWN) },
@@ -96,6 +87,24 @@ static inline void board_lpc18_pinmux(void) {
}
}
+#ifdef TRACE_ETM
+// Must run AFTER Chip_SetupCoreClock: muxing the trace pins earlier starts
+// TRACECLK at the boot clock and the mid-init frequency switch desyncs the
+// trace decoder ("Unknown trace data packet").
+static inline void board_trace_pinmux(void) {
+ // SCU_MODE_INACT: disable the pull-up on the 60 MHz trace lines - leaving it
+ // enabled degrades the edges enough for intermittent decode corruption.
+ const PINMUX_GRP_T trace_pinmux[] = {
+ { 0xF, 4, SCU_MODE_INACT | SCU_MODE_FUNC2 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 5, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 6, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 7, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 8, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ };
+ Chip_SCU_SetPinMuxing(trace_pinmux, sizeof(trace_pinmux) / sizeof(PINMUX_GRP_T));
+}
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/lpc18/boards/mcb1800/ozone/lpc1857.jdebug b/hw/bsp/lpc18/boards/mcb1800/ozone/lpc1857.jdebug
index f94960f09..a6dcef0eb 100644
--- a/hw/bsp/lpc18/boards/mcb1800/ozone/lpc1857.jdebug
+++ b/hw/bsp/lpc18/boards/mcb1800/ozone/lpc1857.jdebug
@@ -10,7 +10,7 @@
*/
void OnProjectLoad (void) {
Project.AddSvdFile ("Cortex-M3.svd");
- Project.AddSvdFile ("../../../../../../../cmsis-svd/data/NXP/LPC18xx.svd");
+ //Project.AddSvdFile ("../../../../../../../cmsis-svd/data/NXP/LPC18xx.svd");
Project.SetDevice ("LPC1857");
Project.SetHostIF ("USB", "");
@@ -20,8 +20,8 @@ void OnProjectLoad (void) {
Project.SetTraceSource ("Trace Pins");
Project.SetTracePortWidth (4);
- //File.Open ("../../../../../../examples/cmake-build-mcb1800/device/cdc_msc/cdc_msc.elf");
- File.Open ("../../../../../../examples/cmake-build-mcb1800/host/cdc_msc_hid/cdc_msc_hid.elf");
+ File.Open ("../../../../../../examples/cmake-build-mcb1800/device/cdc_msc/cdc_msc.elf");
+ //File.Open ("../../../../../../examples/cmake-build-mcb1800/host/cdc_msc_hid/cdc_msc_hid.elf");
}
/*********************************************************************
*
diff --git a/hw/bsp/lpc18/family.c b/hw/bsp/lpc18/family.c
index 8a612d9d8..58c2193fc 100644
--- a/hw/bsp/lpc18/family.c
+++ b/hw/bsp/lpc18/family.c
@@ -69,6 +69,7 @@ void SystemInit(void) {
#ifdef TRACE_ETM
// Trace clock is limited to 60MHz, limit CPU clock to 120MHz
Chip_SetupCoreClock(CLKIN_CRYSTAL, 120000000UL, true);
+ board_trace_pinmux(); // after clock setup so TRACECLK starts at its final frequency
#else
// CPU clock max to 180 Mhz
Chip_SetupCoreClock(CLKIN_CRYSTAL, MAX_CLOCK_FREQ, true);
diff --git a/hw/bsp/lpc40/boards/ea4088_quickstart/ozone/ea4088_quickstart.jdebug b/hw/bsp/lpc40/boards/ea4088_quickstart/ozone/ea4088_quickstart.jdebug
index 6aaf1076d..20de1e915 100644
--- a/hw/bsp/lpc40/boards/ea4088_quickstart/ozone/ea4088_quickstart.jdebug
+++ b/hw/bsp/lpc40/boards/ea4088_quickstart/ozone/ea4088_quickstart.jdebug
@@ -21,7 +21,7 @@ void OnProjectLoad (void) {
Project.SetTracePortWidth (4);
// User settings
- File.Open ("../../../../../../examples/device/cdc_msc/cmake-build-ea4088-quickstart/cdc_msc.elf");
+ File.Open ("../../../../../../examples/cmake-build-ea4088_quickstart/device/cdc_msc/cdc_msc.elf");
}
/*********************************************************************
diff --git a/hw/bsp/lpc40/family.c b/hw/bsp/lpc40/family.c
index d8a63576b..750bd2660 100644
--- a/hw/bsp/lpc40/family.c
+++ b/hw/bsp/lpc40/family.c
@@ -135,6 +135,19 @@ uint32_t board_button_read(void) {
return BUTTON_ACTIV_STATE == Chip_GPIO_GetPinState(LPC_GPIO, BUTTON_PORT, BUTTON_PIN);
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ // IAP ReadUID (cmd 58) returns status + 4 words = full 128-bit UID
+ // (lpcopen's Chip_IAP_ReadUID() only returns the first word)
+ unsigned int command[5] = { IAP_READ_UID_CMD, 0, 0, 0, 0 };
+ unsigned int result[5];
+ iap_entry(command, result);
+ TU_ASSERT(result[0] == IAP_CMD_SUCCESS, 0);
+
+ size_t const len = tu_min32(max_len, 16);
+ memcpy(id, &result[1], len);
+ return len;
+}
+
int board_uart_read(uint8_t *buf, int len) {
//return UART_ReceiveByte(BOARD_UART_PORT);
(void) buf;
diff --git a/hw/bsp/lpc43/boards/ea4357/board.h b/hw/bsp/lpc43/boards/ea4357/board.h
index fca617361..0152825f5 100644
--- a/hw/bsp/lpc43/boards/ea4357/board.h
+++ b/hw/bsp/lpc43/boards/ea4357/board.h
@@ -83,6 +83,22 @@ static const PINMUX_GRP_T pinmuxing[] = {
// { 0, 3, SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC0 },
//};
+#ifdef TRACE_ETM
+// Must run AFTER Chip_SetupCoreClock: muxing the trace pins earlier starts
+// TRACECLK at the boot clock and the mid-init frequency switch desyncs the
+// trace decoder. SCU_MODE_INACT keeps pull-ups off the 60 MHz lines.
+static inline void board_trace_pinmux(void) {
+ const PINMUX_GRP_T trace_pinmux[] = {
+ { 0xF, 4, SCU_MODE_INACT | SCU_MODE_FUNC2 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 5, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 6, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 7, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ { 0xF, 8, SCU_MODE_INACT | SCU_MODE_FUNC3 | SCU_MODE_HIGHSPEEDSLEW_EN },
+ };
+ Chip_SCU_SetPinMuxing(trace_pinmux, sizeof(trace_pinmux) / sizeof(PINMUX_GRP_T));
+}
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/lpc43/boards/lpcxpresso43s67/board.h b/hw/bsp/lpc43/boards/lpcxpresso43s67/board.h
index 4427905e8..6a317b5dc 100644
--- a/hw/bsp/lpc43/boards/lpcxpresso43s67/board.h
+++ b/hw/bsp/lpc43/boards/lpcxpresso43s67/board.h
@@ -71,6 +71,12 @@ static const PINMUX_GRP_T pinmuxing[] = {
{0x2, 5, SCU_MODE_INBUFF_EN | SCU_MODE_PULLUP | SCU_MODE_FUNC4 },
};
+
+// TRACE_ETM builds: no trace header is wired out on the LPCXpresso43S67 -
+// provide the no-op the family init expects (see mcb1800/ea4357 for a
+// board that routes the trace pins)
+static inline void board_trace_pinmux(void) {}
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/lpc43/family.c b/hw/bsp/lpc43/family.c
index 5aff49704..7f0722a33 100644
--- a/hw/bsp/lpc43/family.c
+++ b/hw/bsp/lpc43/family.c
@@ -59,6 +59,30 @@ void SystemInit(void);
// Invoked by startup code
void SystemInit(void)
{
+#if defined(__ICCARM__) && !defined(DONT_RESET_ON_RESTART)
+ __disable_irq();
+#endif
+
+ if (Chip_CREG_OnChipFlashIsPresent()) {
+ // The boot ROM configures flash for its 96 MHz clock, and debugger core
+ // resets can preserve it. Use safe timing before switching the M4 to 204 MHz.
+ Chip_CREG_SetFLASHAccess(FLASHTIM_SAFE_SETTING);
+ __DSB();
+ __ISB();
+ }
+
+#if defined(__ICCARM__) && !defined(DONT_RESET_ON_RESTART)
+ // A debugger restart resets the M4 core, but can leave LPC43 peripherals and
+ // pending interrupts active. Match the GCC startup sequence, which the IAR
+ // startup lacks, before the C runtime can reuse peripheral DMA memory.
+ LPC_RGU->RESET_CTRL[0] = 0x10DF1000u;
+ LPC_RGU->RESET_CTRL[1] = 0x01DFF7FFu;
+ for (uint32_t i = 0; i < 8; i++) {
+ NVIC->ICPR[i] = UINT32_MAX;
+ }
+ __enable_irq();
+#endif
+
#ifdef __USE_LPCOPEN
unsigned int *pSCB_VTOR = (unsigned int *) 0xE000ED08;
@@ -89,7 +113,13 @@ void SystemInit(void)
// Chip_SCU_ClockPinMuxSet(pinclockmuxing[i].pinnum, pinclockmuxing[i].modefunc);
// }
+#ifdef TRACE_ETM
+ // Trace clock is limited to 60MHz, limit CPU clock to 120MHz
+ Chip_SetupCoreClock(CLKIN_CRYSTAL, 120000000UL, true);
+ board_trace_pinmux(); // after clock setup so TRACECLK starts at its final frequency
+#else
Chip_SetupXtalClocking();
+#endif
}
void board_init(void)
diff --git a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake
index b3d6ec722..d7992eec6 100644
--- a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake
+++ b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake
@@ -8,10 +8,6 @@ set(JLINK_OPTION "-USB 000727031389")
set(PYOCD_TARGET LPC55S28)
set(NXPLINK_DEVICE LPC55S28:LPCXpresso55S28)
-# device fullspeed, host highspeed
-set(RHPORT_DEVICE 0)
-set(RHPORT_HOST 1)
-
function(update_board TARGET)
target_compile_definitions(${TARGET} PUBLIC
CPU_LPC55S28JBD100
diff --git a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.mk b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.mk
index db2e11fd7..aecb5a100 100644
--- a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.mk
+++ b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.mk
@@ -2,9 +2,9 @@ MCU_VARIANT = LPC55S28
MCU_CORE = LPC55S28
MCU_DRIVER_VARIANT = LPC55S69
-# device fullspeed, host highspeed
-RHPORT_DEVICE ?= 0
-RHPORT_HOST ?= 1
+# device highspeed, host fullspeed
+RHPORT_DEVICE ?= 1
+RHPORT_HOST ?= 0
CFLAGS += -DCPU_LPC55S28JBD100
diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c
index e021caf35..11bf86827 100644
--- a/hw/bsp/lpc55/family.c
+++ b/hw/bsp/lpc55/family.c
@@ -170,6 +170,14 @@ uint32_t board_button_read(void) {
return BUTTON_STATE_ACTIVE == GPIO_PinRead(GPIO, BUTTON_PORT, BUTTON_PIN);
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ // 128-bit UUID in the flash PFR region at 0x0009FC70 (UM11126 rev 2.1 section 48.8)
+ const uint8_t* uuid = (const uint8_t*) 0x0009FC70;
+ size_t const len = tu_min32(max_len, 16);
+ memcpy(id, uuid, len);
+ return len;
+}
+
int board_uart_read(uint8_t* buf, int len) {
(void) buf;
(void) len;
diff --git a/hw/bsp/lpc55/family.mk b/hw/bsp/lpc55/family.mk
index a9b6f6af1..a640cc793 100644
--- a/hw/bsp/lpc55/family.mk
+++ b/hw/bsp/lpc55/family.mk
@@ -36,6 +36,8 @@ ifeq ($(RHPORT_HOST), 1)
SRC_C += $(TOP)/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.c
else
CFLAGS += -DBOARD_TUH_MAX_SPEED=OPT_MODE_FULL_SPEED
+ # host on port 0 uses the OHCI controller (mirrors family.cmake)
+ SRC_C += $(TOP)/src/portable/ohci/ohci.c
endif
# mcu driver cause following warnings
diff --git a/hw/bsp/mcx/family.cmake b/hw/bsp/mcx/family.cmake
index 89e2aadf2..00c8c4ead 100644
--- a/hw/bsp/mcx/family.cmake
+++ b/hw/bsp/mcx/family.cmake
@@ -94,10 +94,19 @@ function(family_configure_example TARGET RTOS)
family_add_tinyusb(${TARGET} OPT_MCU_MCXA15)
endif()
+ # PORT is set per board (board.cmake), so pick the driver at configure time. Spelled out
+ # rather than $<IF:${PORT},...> so the port path stays greppable: tools/ci_select.py
+ # maps a portable-driver change to the families whose build file names that directory.
+ if (PORT)
+ set(PORT_SRC ${TOP}/src/portable/chipidea/ci_hs/dcd_ci_hs.c)
+ else ()
+ set(PORT_SRC ${TOP}/src/portable/chipidea/ci_fs/dcd_ci_fs.c)
+ endif ()
+
target_sources(${TARGET} PUBLIC
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- ${TOP}/src/portable/chipidea/$<IF:${PORT},ci_hs/dcd_ci_hs.c,ci_fs/dcd_ci_fs.c>
+ ${PORT_SRC}
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
)
target_include_directories(${TARGET} PUBLIC
diff --git a/hw/bsp/nrf/boards/nrf52840dk/ozone/nrf52840.jdebug b/hw/bsp/nrf/boards/nrf52840dk/ozone/nrf52840.jdebug
index fa7ab9e23..40f28baa9 100644
--- a/hw/bsp/nrf/boards/nrf52840dk/ozone/nrf52840.jdebug
+++ b/hw/bsp/nrf/boards/nrf52840dk/ozone/nrf52840.jdebug
@@ -21,7 +21,7 @@ void OnProjectLoad (void) {
Project.SetTracePortWidth (4);
// User settings
- File.Open ("../../../../../../examples/device/cdc_msc/cmake-build-pca10056/cdc_msc.elf");
+ File.Open ("../../../../../../examples/cmake-build-nrf52840dk/device/cdc_msc/cdc_msc.elf");
}
/*********************************************************************
diff --git a/hw/bsp/nrf/boards/nrf5340dk/ozone/nrf5340.jdebug b/hw/bsp/nrf/boards/nrf5340dk/ozone/nrf5340.jdebug
index 4ad0376a4..34b1841b0 100644
--- a/hw/bsp/nrf/boards/nrf5340dk/ozone/nrf5340.jdebug
+++ b/hw/bsp/nrf/boards/nrf5340dk/ozone/nrf5340.jdebug
@@ -29,9 +29,13 @@ void OnProjectLoad (void) {
Project.SetTraceSource ("Trace Pins");
Project.SetTracePortWidth (4);
+ // +3 ns sample point: the DK's analog-switch/SWO stubs make TD=0 marginal
+ // (Ozone sends TraceSampleAdjust TD=0 when no timing is set); solid across
+ // the +2..+4 ns band with SB27/SB28 cut, SB57 (SWO) left intact
+ Project.SetTraceTiming (3000, 3000, 3000, 3000);
// User settings
- File.Open ("../../../../../../examples/device/cdc_msc/cmake-build-pca10095/cdc_msc.elf");
+ File.Open ("../../../../../../examples/cmake-build-nrf5340dk/device/cdc_msc/cdc_msc.elf");
}
/*********************************************************************
diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c
index 31a6bac9e..3cef4dac3 100644
--- a/hw/bsp/nrf/family.c
+++ b/hw/bsp/nrf/family.c
@@ -165,6 +165,12 @@ static nrfx_gpiote_t _gpiote = NRFX_GPIOTE_INSTANCE(0);
//
//--------------------------------------------------------------------+
void board_init(void) {
+#if defined(TRACE_ETM) && defined(NRF5340_XXAA)
+ // SystemInit (ENABLE_TRACE) sets the TAD trace port to 64 MHz, which is
+ // marginal through the DK's switch stubs - 16 MHz streams reliably (matches the validated nrf52840dk) and is
+ // ample bandwidth for the 64 MHz core
+ NRF_TAD_S->TRACEPORTSPEED = TAD_TRACEPORTSPEED_TRACEPORTSPEED_16MHz;
+#endif
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
// stop LF clock just in case we jump from application without reset
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
diff --git a/hw/bsp/py32f0/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/py32f0/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..6b3ae0cd5
--- /dev/null
+++ b/hw/bsp/py32f0/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,108 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef FREERTOS_CONFIG_H_
+#define FREERTOS_CONFIG_H_
+
+#ifndef __IASMARM__
+ #include "py32f0xx.h"
+#endif
+
+#define configENABLE_MPU 0
+#define configENABLE_FPU 0
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE 1024
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ 1000
+#define configMAX_PRIORITIES 5
+#define configMINIMAL_STACK_SIZE 128
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION * 4 * 1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 4
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
+
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCHECK_HANDLER_INSTALLATION 0
+
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1
+#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
+
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+#define configPRIO_BITS __NVIC_PRIO_BITS
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ( ( 1 << configPRIO_BITS ) - 1 )
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
+#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
+
+#endif
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake b/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake
new file mode 100644
index 000000000..e759f4af1
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake
@@ -0,0 +1,12 @@
+set(PYOCD_TARGET py32f071xb)
+set(PY32_SERIES PY32F071)
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/py32f071xb.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ PY32F071xB
+ CFG_EXAMPLE_MSC_READONLY
+ CFG_EXAMPLE_MSC_DUAL_READONLY
+ CFG_EXAMPLE_VIDEO_READONLY
+ )
+endfunction()
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.h b/hw/bsp/py32f0/boards/py32f071_dev_board/board.h
new file mode 100644
index 000000000..ddd67bb6a
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.h
@@ -0,0 +1,75 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define LED_PORT GPIOB
+#define LED_PIN GPIO_PIN_2
+#define LED_STATE_ON 0
+
+#define BUTTON_PORT GPIOB
+#define BUTTON_PIN GPIO_PIN_0
+#define BUTTON_STATE_ACTIVE 0
+
+static inline void board_py32f0_clock_init(void) {
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI |
+ RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+ RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_16MHz;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSEFreq = RCC_HSE_16_32MHz;
+ RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
+ RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL2;
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ while (1) {}
+ }
+
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
+ while (1) {}
+ }
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk b/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk
new file mode 100644
index 000000000..e7fbc338d
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk
@@ -0,0 +1,12 @@
+PY32_SERIES = PY32F071
+
+CFLAGS += \
+ -DPY32F071xB \
+ -DCFG_EXAMPLE_MSC_READONLY \
+ -DCFG_EXAMPLE_MSC_DUAL_READONLY \
+ -DCFG_EXAMPLE_VIDEO_READONLY
+
+LD_FILE = $(BOARD_PATH)/py32f071xb.ld
+PYOCD_TARGET = py32f071xb
+
+flash: flash-pyocd
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h
new file mode 100644
index 000000000..e513bf8cb
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h
@@ -0,0 +1,105 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef PY32F071_HAL_CONF_H_
+#define PY32F071_HAL_CONF_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define HAL_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+#if !defined(HSI_VALUE)
+ #define HSI_VALUE ((uint32_t) 8000000)
+#endif
+
+#if !defined(HSE_VALUE)
+ #define HSE_VALUE ((uint32_t) 24000000)
+#endif
+
+#if !defined(HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t) 200)
+#endif
+
+#if !defined(LSI_VALUE)
+ #define LSI_VALUE ((uint32_t) 32768)
+#endif
+
+#if !defined(LSE_VALUE)
+ #define LSE_VALUE ((uint32_t) 32768)
+#endif
+
+#if !defined(LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT ((uint32_t) 5000)
+#endif
+
+#define VDD_VALUE ((uint32_t) 3300)
+#define TICK_INT_PRIORITY ((uint32_t) 3)
+#define USE_RTOS 0
+#define PREFETCH_ENABLE 0
+
+#ifdef HAL_MODULE_ENABLED
+ #include "py32f0xx_hal.h"
+#endif
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "py32f071_hal_rcc.h"
+#endif
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "py32f071_hal_flash.h"
+#endif
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "py32f071_hal_gpio.h"
+#endif
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "py32f071_hal_pwr.h"
+#endif
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "py32f071_hal_cortex.h"
+#endif
+
+#ifdef USE_FULL_ASSERT
+void assert_failed(uint8_t *file, uint32_t line);
+ #define assert_param(expr) ((expr) ? (void) 0U : assert_failed((uint8_t *) __FILE__, __LINE__))
+#else
+ #define assert_param(expr) ((void) 0U)
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld
new file mode 100644
index 000000000..bb6b88d2c
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld
@@ -0,0 +1,122 @@
+ENTRY(Reset_Handler)
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+_Min_Heap_Size = 0x200;
+_Min_Stack_Size = 0x400;
+
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
+
+SECTIONS
+{
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ . = ALIGN(4);
+ } >FLASH
+
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text)
+ *(.text*)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.eh_frame)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ . = ALIGN(4);
+ _etext = .;
+ } >FLASH
+
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata)
+ *(.rodata*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } >FLASH
+
+ .ARM :
+ {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN(__preinit_array_start = .);
+ KEEP(*(.preinit_array*))
+ PROVIDE_HIDDEN(__preinit_array_end = .);
+ } >FLASH
+
+ .init_array :
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array*))
+ PROVIDE_HIDDEN(__init_array_end = .);
+ } >FLASH
+
+ .fini_array :
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT(.fini_array.*)))
+ KEEP(*(.fini_array*))
+ PROVIDE_HIDDEN(__fini_array_end = .);
+ } >FLASH
+
+ _sidata = LOADADDR(.data);
+
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data)
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM AT> FLASH
+
+ . = ALIGN(4);
+ .bss :
+ {
+ _sbss = .;
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ __bss_end__ = _ebss;
+ } >RAM
+
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE(end = .);
+ PROVIDE(_end = .);
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /DISCARD/ :
+ {
+ libc.a(*)
+ libm.a(*)
+ libgcc.a(*)
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/py32f0/family.c b/hw/bsp/py32f0/family.c
new file mode 100644
index 000000000..1428b1fa9
--- /dev/null
+++ b/hw/bsp/py32f0/family.c
@@ -0,0 +1,133 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, 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: Puya
+*/
+
+#include "py32f0xx_hal.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+void USB_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+void USBD_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+void HAL_MspInit(void) {
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+}
+
+void board_init(void) {
+ HAL_Init();
+ board_py32f0_clock_init();
+
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ SysTick_Config(SystemCoreClock / 1000);
+#elif CFG_TUSB_OS == OPT_OS_FREERTOS
+ SysTick->CTRL &= ~1U;
+ NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+#endif
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ GPIO_InitStruct.Pin = LED_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
+ board_led_write(false);
+
+ GPIO_InitStruct.Pin = BUTTON_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
+
+ __HAL_RCC_USB_CLK_ENABLE();
+}
+
+void board_led_write(bool state) {
+ GPIO_PinState pin_state = (GPIO_PinState) (state ? LED_STATE_ON : (1 - LED_STATE_ON));
+ HAL_GPIO_WritePin(LED_PORT, LED_PIN, pin_state);
+}
+
+uint32_t board_button_read(void) {
+ return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t * py32_uuid = (volatile uint32_t *) UID_BASE;
+ uint32_t* id32 = (uint32_t*) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = py32_uuid[0];
+ id32[1] = py32_uuid[1];
+ id32[2] = py32_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) {
+ (void) buf; (void) len;
+ return -1;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ HAL_IncTick();
+ system_ticks++;
+}
+
+uint32_t tusb_time_millis_api(void) {
+ return system_ticks;
+}
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+void _init(void);
+void _init(void) {
+}
diff --git a/hw/bsp/py32f0/family.cmake b/hw/bsp/py32f0/family.cmake
new file mode 100644
index 000000000..df6dec42b
--- /dev/null
+++ b/hw/bsp/py32f0/family.cmake
@@ -0,0 +1,89 @@
+include_guard()
+
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+if (NOT DEFINED MCU_VARIANT)
+ set(MCU_VARIANT PY32F071)
+endif ()
+string(TOLOWER ${MCU_VARIANT} PY32_SERIES_LOWER)
+set(PY32_SDK_NAME ${MCU_VARIANT}_Firmware)
+set(PY32_TEMPLATE ${MCU_VARIANT}xx_Templates)
+set(PY32_STARTUP startup_${PY32_SERIES_LOWER}xx.s)
+set(PY32_SYSTEM_SOURCE system_${PY32_SERIES_LOWER}.c)
+set(PY32_HAL_PREFIX ${PY32_SERIES_LOWER})
+
+set(PY32_SDK ${TOP}/hw/mcu/puya/${PY32_SDK_NAME})
+set(PY32_HAL ${PY32_SDK}/Drivers/${MCU_VARIANT}_HAL_Driver)
+set(PY32_CMSIS ${PY32_SDK}/Drivers/CMSIS/Device/${MCU_VARIANT})
+
+set(CMAKE_SYSTEM_CPU cortex-m0plus CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS PY32F0 CACHE INTERNAL "")
+
+set(STARTUP_FILE_GNU ${PY32_SDK}/Templates/${PY32_TEMPLATE}/EIDE/${PY32_STARTUP})
+set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+set(LD_FILE_Clang ${LD_FILE_GNU})
+
+function(family_add_board BOARD_TARGET)
+ add_library(${BOARD_TARGET} STATIC
+ ${PY32_SDK}/Templates/${PY32_TEMPLATE}/Src/${PY32_SYSTEM_SOURCE}
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_cortex.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_flash.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_gpio.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_pwr.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_rcc.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_rcc_ex.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${PY32_SDK}/Drivers/CMSIS/Include
+ ${PY32_CMSIS}/Include
+ ${PY32_HAL}/Inc
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+ target_compile_definitions(${BOARD_TARGET} PRIVATE
+ USE_HAL_DRIVER
+ )
+ update_board(${BOARD_TARGET})
+endfunction()
+
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+ family_add_tinyusb(${TARGET} OPT_MCU_PY32F0)
+
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.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")
+ message(FATAL_ERROR "Clang is not supported")
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ message(FATAL_ERROR "IAR is not supported")
+ endif ()
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ set_source_files_properties(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c PROPERTIES COMPILE_FLAGS "-Wno-missing-prototypes")
+ endif ()
+ set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES
+ SKIP_LINTING ON
+ COMPILE_OPTIONS -w)
+
+ family_add_bin_hex(${TARGET})
+ family_flash_pyocd(${TARGET})
+endfunction()
diff --git a/hw/bsp/py32f0/family.mk b/hw/bsp/py32f0/family.mk
new file mode 100644
index 000000000..b01a9eefa
--- /dev/null
+++ b/hw/bsp/py32f0/family.mk
@@ -0,0 +1,58 @@
+UF2_FAMILY_ID = 0x0
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+MCU_VARIANT ?= PY32F071
+PY32_SERIES_LOWER = $(subst PY32F,py32f,$(MCU_VARIANT))
+PY32_SDK_NAME = $(MCU_VARIANT)_Firmware
+PY32_TEMPLATE = $(MCU_VARIANT)xx_Templates
+PY32_STARTUP = startup_$(PY32_SERIES_LOWER)xx.s
+PY32_SYSTEM_SOURCE = system_$(PY32_SERIES_LOWER).c
+PY32_HAL_PREFIX = $(PY32_SERIES_LOWER)
+
+SDK_DIR = hw/mcu/puya/$(PY32_SDK_NAME)
+HAL_DIR = $(SDK_DIR)/Drivers/$(MCU_VARIANT)_HAL_Driver
+CMSIS_DIR = $(SDK_DIR)/Drivers/CMSIS
+CMSIS_DEVICE_DIR = $(CMSIS_DIR)/Device/$(MCU_VARIANT)
+
+DEPS_SUBMODULES += $(SDK_DIR)
+
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_PY32F0 \
+ -DUSE_HAL_DRIVER
+
+# Puya HAL leaves some CMSIS-compatible callback parameters intentionally unused.
+CFLAGS += -Wno-error=unused-parameter
+
+MCU_DIR = $(SDK_DIR)
+
+SRC_C += \
+ src/portable/mentor/musb/dcd_musb.c \
+ hw/bsp/py32f0/family.c \
+ $(SDK_DIR)/Templates/$(PY32_TEMPLATE)/Src/$(PY32_SYSTEM_SOURCE) \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_cortex.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_flash.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_gpio.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_pwr.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_rcc.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_rcc_ex.c
+
+SRC_S += $(SDK_DIR)/Templates/$(PY32_TEMPLATE)/EIDE/$(PY32_STARTUP)
+
+INC += \
+ $(TOP)/hw/bsp/py32f0 \
+ $(TOP)/$(CMSIS_DIR)/Include \
+ $(TOP)/$(CMSIS_DEVICE_DIR)/Include \
+ $(TOP)/$(HAL_DIR)/Inc \
+ $(TOP)/hw/bsp/py32f0/boards/$(BOARD)
+
+SKIP_NANOLIB = 1
+
+LDFLAGS += \
+ -nostdlib -nostartfiles \
+ --specs=nosys.specs --specs=nano.specs \
+ -Wl,--gc-sections \
+ -Wl,--print-memory-usage
+
+CPU_CORE ?= cortex-m0plus
diff --git a/hw/bsp/ra/boards/ra6m5_ek/ozone/ra6m5.jdebug b/hw/bsp/ra/boards/ra6m5_ek/ozone/ra6m5.jdebug
index ca18fed7c..466658f39 100644
--- a/hw/bsp/ra/boards/ra6m5_ek/ozone/ra6m5.jdebug
+++ b/hw/bsp/ra/boards/ra6m5_ek/ozone/ra6m5.jdebug
@@ -15,7 +15,7 @@ void OnProjectLoad (void) {
Project.SetDevice ("R7FA6M5BH");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
- Project.SetTIFSpeed ("50 MHz");
+ Project.SetTIFSpeed ("4 MHz"); // 50 MHz SWD gave intermittent "Failed to initialize DAP"
Project.SetTraceSource ("Trace Pins");
Project.SetTracePortWidth (4);
diff --git a/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1.jdebug b/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1.jdebug
index 242a15db9..02d568240 100644
--- a/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1.jdebug
+++ b/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1.jdebug
@@ -10,10 +10,11 @@
*/
void OnProjectLoad (void) {
Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
Project.SetDevice ("R7FA8M1AH");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
- Project.SetTIFSpeed ("50 MHz");
+ Project.SetTIFSpeed ("4 MHz"); // 50 MHz SWD gave intermittent "Failed to initialize DAP"
Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M85F.svd");
Project.AddSvdFile ("../../../../../../../cmsis-svd-data/data/Renesas/R7FA6M5BH.svd");
@@ -32,7 +33,7 @@ void OnProjectLoad (void) {
void BeforeTargetConnect (void) {
// Trace pin init is done by J-Link script file as J-Link script files are IDE independent
//Project.SetJLinkScript("../../../debug.jlinkscript");
- Project.SetJLinkScript ("$(ProjectDir)/Renesas_RA8_TracePins.pex");
+ Project.SetJLinkScript ("./ra8m1_trace.JLinkScript");
}
/*********************************************************************
@@ -40,12 +41,14 @@ void BeforeTargetConnect (void) {
* AfterTargetConnect
*
* Function description
-* Event handler routine. Optional.
+* Cache the boot-ROM range for the trace decoder on --attach sessions
+* too (the download hook that normally does this is skipped on attach).
*
**********************************************************************
*/
-//void AfterTargetConnect (void) {
-//}
+void AfterTargetConnect (void) {
+ Exec.Command("ReadIntoTraceCache 0x0 0x10000");
+}
/*********************************************************************
*
@@ -83,8 +86,12 @@ void BeforeTargetConnect (void) {
*/
void AfterTargetDownload (void) {
_SetupTarget();
+ // RA8 executes chip-ROM code at runtime (seen at ~0x3B20); without this the
+ // trace decoder dies there ("not covered by trace cache" -> unknown packet)
+ Exec.Command("ReadIntoTraceCache 0x0 0x10000");
}
+
/*********************************************************************
*
* BeforeTargetDisconnect
diff --git a/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1_trace.JLinkScript b/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1_trace.JLinkScript
new file mode 100644
index 000000000..3869c1eb7
--- /dev/null
+++ b/hw/bsp/ra/boards/ra8m1_ek/ozone/ra8m1_trace.JLinkScript
@@ -0,0 +1,20 @@
+/* RA8M1 pin trace: CSTF funnel and TMC are off the core ROM table (AP1) -
+ * declare them or trace init cannot route the M85 ETM stream (addresses per
+ * SEGGER's RA8 trace example script). Pins + TRCKCR belong to firmware
+ * (trace_etm_init): the SEGGER pex also muxed them at trace start, and its
+ * clock choice fought the firmware's mid-run = decoder desync.
+ */
+int ConfigTargetSettings(void) {
+ JLINK_ExecCommand("CORESIGHT_SetCSTFBaseAddr = 0x80013000 ForceUnlock = 1 APIndex = 1");
+ JLINK_ExecCommand("CORESIGHT_SetTMCBaseAddr = 0x80014000 ForceUnlock = 1 APIndex = 1");
+ return 0;
+}
+
+/* Replace J-Link's built-in RA8 trace start, which enables the trace clock
+ * from reset - bsp_clock_init's MOCO -> 480 MHz PLL switch would then step
+ * TRCLK mid-stream and desync the decoder. The firmware's trace_etm_init
+ * enables TRCKCR at the final clock instead.
+ */
+int OnTraceStart(void) {
+ return 0;
+}
diff --git a/hw/bsp/ra/boards/ra8m1_ek/ra_gen/bsp_clock_cfg.h b/hw/bsp/ra/boards/ra8m1_ek/ra_gen/bsp_clock_cfg.h
index f2f1ae0c9..25638f02b 100644
--- a/hw/bsp/ra/boards/ra8m1_ek/ra_gen/bsp_clock_cfg.h
+++ b/hw/bsp/ra/boards/ra8m1_ek/ra_gen/bsp_clock_cfg.h
@@ -51,6 +51,9 @@
#define BSP_CFG_CANFDCLK_DIV (BSP_CLOCKS_CANFD_CLOCK_DIV_8) /* CANFDCLK Div /8 */
#define BSP_CFG_I3CCLK_DIV (BSP_CLOCKS_I3C_CLOCK_DIV_3) /* I3CCLK Div /3 */
#define BSP_CFG_UCK_DIV (BSP_CLOCKS_USB_CLOCK_DIV_5) /* UCK Div /5 */
-#define BSP_CFG_U60CK_DIV (BSP_CLOCKS_USB_CLOCK_DIV_8) /* U60CK Div /8 */
+/* U60CK Div /8: PLL1P 480 MHz -> 60 MHz. Hand-fixed: Smart Configurator emitted the USB_ macro
+ * namespace (BSP_CLOCKS_USB_CLOCK_DIV_8 = 7, rejected by USB60CKDIVCR -> link clock ran at
+ * 480 MHz); configuration.xml already says u60ck.div.8, so keep the USB60_ macro if regenerating. */
+#define BSP_CFG_U60CK_DIV (BSP_CLOCKS_USB60_CLOCK_DIV_8)
#define BSP_CFG_OCTA_DIV (BSP_CLOCKS_OCTA_CLOCK_DIV_4) /* OCTASPICLK Div /4 */
#endif /* BSP_CLOCK_CFG_H_ */
diff --git a/hw/bsp/ra/family.c b/hw/bsp/ra/family.c
index c8a4d33d9..307644972 100644
--- a/hw/bsp/ra/family.c
+++ b/hw/bsp/ra/family.c
@@ -99,13 +99,32 @@ void board_init(void) {
R_IOPORT_Open(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);
#ifdef TRACE_ETM
- // TRCKCR is protected by PRCR bit0 register
- R_SYSTEM->PRCR = (uint16_t) (BSP_PRV_PRCR_KEY | 0x01);
+ // TRCKCR is only writable while a debugger is connected (RA HUM) - a
+ // standalone boot must skip trace init or the write wedges the chip into
+ // an un-attachable crash loop (recover: power-cycle + immediate erase)
+ if (DCB->DHCSR & DCB_DHCSR_C_DEBUGEN_Msk) {
+ // TRCKCR is protected by PRCR bit0 register
+ R_SYSTEM->PRCR = (uint16_t) (BSP_PRV_PRCR_KEY | 0x01);
- // Enable trace clock (max 100Mhz). Since PLL/CPU is 200Mhz, clock div = 2
- R_SYSTEM->TRCKCR = R_SYSTEM_TRCKCR_TRCKEN_Msk | 0x01;
+ // TCLK pin = TRCLK/2; set the divider with TRCKEN=0 first (HUM procedure).
+ // Values are the empirical per-board ceilings.
+#if defined(BSP_MCU_GROUP_RA8M1)
+ // 480 MHz CPU: /4 -> 120 MHz TRCLK, 60 MHz pin - chip max, clean on
+ // EK-RA8M1 with the committed empty-OnTraceStart JLinkScript (which
+ // defers the trace clock to firmware; without it the FSP MOCO->PLL
+ // switch steps the clock mid-stream and any divider fails)
+ R_SYSTEM->TRCKCR = 0x02;
+ R_SYSTEM->TRCKCR = R_SYSTEM_TRCKCR_TRCKEN_Msk | 0x02;
+#else
+ // RA6M5 200 MHz CPU: /4 -> 50 MHz TRCLK, 25 MHz pin. /2 (50 MHz pin) is
+ // silent on the EK-RA6M5 in every combination - board path ceiling,
+ // reconfirmed with J9 closed and the OnTraceStart override
+ R_SYSTEM->TRCKCR = 0x02;
+ R_SYSTEM->TRCKCR = R_SYSTEM_TRCKCR_TRCKEN_Msk | 0x02;
+#endif
- R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_KEY;
+ R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_KEY;
+ }
#endif
#if CFG_TUSB_OS == OPT_OS_FREERTOS
diff --git a/hw/bsp/rp2040/boards/pico2_etm_trace/board.cmake b/hw/bsp/rp2040/boards/pico2_etm_trace/board.cmake
new file mode 100644
index 000000000..53f9132b5
--- /dev/null
+++ b/hw/bsp/rp2040/boards/pico2_etm_trace/board.cmake
@@ -0,0 +1,35 @@
+set(PICO_PLATFORM rp2350-arm-s)
+set(PICO_BOARD pico2)
+
+# ETM trace is wired on this carrier only (GP1-5 -> MIPI-20), so the trace
+# build flag lives here rather than being a global -D anyone can pass: on a
+# board whose PIO-USB D+ sits on GP1 (e.g. adafruit_fruit_jam) it would fight
+# the trace clock.
+set(TRACE_ETM 1)
+
+# Point the pico-sdk's own defaults at the carrier's wiring: pico2.h guards
+# every PICO_DEFAULT_* with #ifndef, so these win. Without them anything that
+# talks to the SDK directly instead of the TinyUSB BSP (e.g. stdio_init_all()
+# in examples/device/cdc_uac2) would mux GP0/GP1 for UART - and GP1 is
+# TRACECLK, so it would silently kill the trace clock mid-capture.
+add_compile_definitions(
+ PICO_DEFAULT_UART_TX_PIN=12
+ PICO_DEFAULT_UART_RX_PIN=13
+ PICO_DEFAULT_LED_PIN=10
+ PICO_DEFAULT_I2C=0 # STEMMA-QT / Qwiic port on GP8/9;
+ PICO_DEFAULT_I2C_SDA_PIN=8 # the sdk default GP4/5 is TRACEDATA2/3
+ PICO_DEFAULT_I2C_SCL_PIN=9
+)
+
+# the carrier's MIPI-20 is driven by a J-Trace; uncomment (or pass
+# -DJLINK_OPTION=...) to pin one probe by USB nickname/serial when several
+# J-Links are attached during hardware validation
+#set(JLINK_OPTION "-USB jtrace")
+
+# Clock: the rp2350 pico-sdk default, 150 MHz -> 75 MHz TRACECLK (clk_sys/2),
+# validated on the trace motherboard: cdc_msc enumeration burst 3/3, zero
+# overflow, +1 ns data sampling (idle eye -1000..+2000 ps; committed in the
+# ozone reference). Nothing may switch clk_sys at runtime - that truncates a
+# capture at the switch. Other validated rates (156000, 180000, and 240000 =
+# the J-Trace PRO V2 ceiling) need PLL_SYS_* from the SDK's vcocalc.py; see
+# the etm-trace skill's boards.md.
diff --git a/hw/bsp/rp2040/boards/pico2_etm_trace/board.h b/hw/bsp/rp2040/boards/pico2_etm_trace/board.h
new file mode 100644
index 000000000..863d0e6b9
--- /dev/null
+++ b/hw/bsp/rp2040/boards/pico2_etm_trace/board.h
@@ -0,0 +1,80 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: Pico 2 ETM Trace Carrier
+ url: https://github.com/hathach/pcb/tree/main/pico2_trace_motherboard
+*/
+
+// Raspberry Pi Pico 2 seated on the "pico2 trace motherboard" carrier: a
+// MIPI-20 Cortex Debug+ETM adapter (SWD + 4-bit trace) plus a TinyUSB test
+// bench. Same RP2350 module as raspberry_pi_pico2, different pin map: the
+// carrier keeps GP1-5 free for TRACECLK/TRACEDATA0-3 and moves the console,
+// LED, button and USB control pins out of the way.
+//
+// Carrier pin map (only the pins the BSP uses are defined below):
+// 0 GND guard (JP2) 1 TRACECLK
+// 2-5 TRACEDATA0-3 6 GND guard (JP3)
+// 8/9 I2C0 SDA/SCL (STEMMA-QT) 10 user LED
+// 11 device D+ pull-up enable 12/13 UART0 TX/RX (console)
+// 14 user button (to GND, unused - BSP uses BOOTSEL)
+// 15 host VBUS fault
+// 16 native VBUS-detect tap 17 host VBUS enable
+// 18/19 PIO-USB device D+/D- (J9) 20/21 PIO-USB host D+/D- (J5)
+// 26 VBUS current sense (ADC) 27 J9 device VBUS-detect
+
+#ifndef TUSB_BOARD_H
+#define TUSB_BOARD_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// LED, UART (button: the family BSP uses BOOTSEL, like every rp2040 board)
+//--------------------------------------------------------------------+
+#define LED_PIN 10
+#define LED_STATE_ON 1
+
+// console is on GP12/13, NOT the pico default GP0/1: GP1 is TRACECLK, so the
+// console stays full-duplex while tracing
+#define UART_DEV 0 // uart0 (index, see uart_get_instance)
+#define UART_TX_PIN 12
+#define UART_RX_PIN 13
+
+//--------------------------------------------------------------------+
+// PIO_USB
+//--------------------------------------------------------------------+
+// host port J5 (USB-A): D+ = GP20, D- = GP21, load switch enable = GP17
+#define PICO_DEFAULT_PIO_USB_DP_PIN 20
+#define PICO_DEFAULT_PIO_USB_VBUSEN_PIN 17
+#define PICO_DEFAULT_PIO_USB_VBUSEN_STATE 1
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/rp2040/boards/pico2_etm_trace/ozone/rp2350.jdebug b/hw/bsp/rp2040/boards/pico2_etm_trace/ozone/rp2350.jdebug
new file mode 100644
index 000000000..fd5d589f2
--- /dev/null
+++ b/hw/bsp/rp2040/boards/pico2_etm_trace/ozone/rp2350.jdebug
@@ -0,0 +1,79 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* Board pico2_etm_trace = a Pico 2 seated on the pico2 trace motherboard
+* carrier (MIPI-20, source-terminated), GPIO1-5 to the MIPI20:
+* TRACECLK=GPIO1->12, D0=GPIO2->14, D1=GPIO3->16, D2=GPIO4->18,
+* D3=GPIO5->20. Firmware needs NO trace-specific code: J-Link's
+* built-in RP2350 device script declares the off-ROM-table trace
+* components (funnel/TPIU/ETM) and re-arms the whole chip-side path
+* via OnTraceStart at every resume - do NOT set a custom JLinkScript
+* here (it replaces that built-in script and J-Link then fails with
+* "Required trace components for pin trace not found"). TRACE_ETM (set
+* by this board's own board.cmake) clears TIMER0/1 DBGPAUSE - J-Link
+* does not, and the reset default freezes the us-timer while a core is
+* debug-halted - and adds compile-time checks that no console/I2C pin
+* lands on the trace pins GP1-5; the console is full-duplex on GP12/13.
+* clk_sys is the rp2350 pico-sdk default
+* 150 MHz (75 MHz TRACECLK) and nothing may re-switch it at runtime:
+* a mid-stream step silently truncates the capture.
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
+ Project.SetSWO (0);
+ // +1 ns data sampling: at 75 MHz TRACECLK (DDR) on the trace motherboard
+ // the idle eye spans -1000..+2000 ps and cdc_msc passes 3/3 at +1000
+ // (+3000 dead; TD aliases modulo the 6.67 ns UI)
+ Project.SetTraceTiming (1000, 1000, 1000, 1000);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 150000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M33F.svd");
+
+ Project.SetDevice ("RP2350_M33_0");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("25 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-pico2_etm_trace/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ // intentionally empty: the RP2350 bootrom must run to validate the
+ // IMAGE_DEF and hand over to the app - setting SP/PC from the vector
+ // table bypasses it and the pico-sdk runtime never comes up
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ // intentionally empty: the RP2350 bootrom must run to validate the
+ // IMAGE_DEF and hand over to the app - setting SP/PC from the vector
+ // table bypasses it and the pico-sdk runtime never comes up
+}
diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c
index 7437707da..3c5022eb6 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -153,27 +153,58 @@ static stdio_driver_t stdio_rtt = {
.in_chars = stdio_rtt_read
};
-void stdio_rtt_init(void) {
+static void stdio_rtt_init(void) {
stdio_set_driver_enabled(&stdio_rtt, true);
}
#endif
-//--------------------------------------------------------------------+
-//
-//--------------------------------------------------------------------+
+#if defined(TRACE_ETM) && defined(PICO_RP2350) && PICO_RP2350 == 1
+// ETM trace owns GP1-5 (GP1 = TRACECLK, GP2-5 = TRACEDATA0-3): muxing any of
+// them away - even briefly - gaps the trace clock/data and desyncs the probe.
+#define TRACE_PIN_CONFLICT(pin) ((pin) >= 1 && (pin) <= 5)
+// board_init() muxes UART_TX_PIN/UART_RX_PIN, which are defined whenever UART_DEV is
+#ifdef UART_DEV
+ #if TRACE_PIN_CONFLICT(UART_TX_PIN) || TRACE_PIN_CONFLICT(UART_RX_PIN)
+ #error "TRACE_ETM: UART TX/RX sits on a trace pin (GP1-5) - route the console elsewhere (pico2_etm_trace uses GP12/13)"
+ #endif
+#endif
+// stdio_init_all() muxes the sdk defaults even when the BSP console is elsewhere
+#if defined(LIB_PICO_STDIO_UART) && defined(PICO_DEFAULT_UART_TX_PIN) && \
+ (TRACE_PIN_CONFLICT(PICO_DEFAULT_UART_TX_PIN) || TRACE_PIN_CONFLICT(PICO_DEFAULT_UART_RX_PIN))
+ #error "TRACE_ETM: pico-sdk default UART (stdio_init_all) sits on a trace pin (GP1-5)"
+#endif
+#if defined(PICO_DEFAULT_I2C_SDA_PIN) && (TRACE_PIN_CONFLICT(PICO_DEFAULT_I2C_SDA_PIN) || TRACE_PIN_CONFLICT(PICO_DEFAULT_I2C_SCL_PIN))
+ // #pragma message, not #warning: examples build with -Werror, and this is
+ // only a hazard if the app actually uses i2c_default
+ #pragma message("TRACE_ETM: default I2C SDA/SCL sits on a trace pin (GP1-5) - using i2c_default will corrupt the trace stream (pico2_etm_trace routes I2C to GP8/9)")
+#endif
+
+// A debugger session leaves a core halted (Ozone captures halt at the end,
+// openocd halts both cores to flash), and TIMER's reset default pauses the
+// us-timer whenever EITHER core is debug-halted - J-Link's RP2350 script does
+// NOT clear it (verified: DBGPAUSE still reads 0x7, TIMERAWL frozen while
+// halted). tusb_time_millis_api()/sleep_ms() then spin forever and the board
+// looks dead, so free the timer for trace builds, which always run under a
+// probe.
+static void trace_etm_init(void) {
+ *(volatile uint32_t*) 0x400B002Cu = 0; // TIMER0 DBGPAUSE
+ *(volatile uint32_t*) 0x400B802Cu = 0; // TIMER1 DBGPAUSE
+}
+#else
+ #define trace_etm_init()
+#endif
+
void board_init(void)
{
+ trace_etm_init();
+
#if (CFG_TUH_ENABLED && CFG_TUH_RPI_PIO_USB) || (CFG_TUD_ENABLED && CFG_TUD_RPI_PIO_USB)
- // Set the system clock to a multiple of 12mhz for bit-banging USB with pico-usb
- #if defined(PICO_RP2350) && PICO_RP2350 == 1
- set_sys_clock_khz(156000, true); // rp2350 default is 150Mhz
- #else
+ // rp2350 runs the pico-sdk stock 150 MHz (a runtime switch also truncates ETM
+ // capture). rp2040 keeps 120 MHz: soak-tested — the stock 125 MHz collapses
+ // PIO-USB bulk-OUT (device NAKs ~600:1, wire-measured, zero CRC errors).
+ #if !(defined(PICO_RP2350) && PICO_RP2350 == 1)
set_sys_clock_khz(120000, true); // rp2040 default is 125Mhz
#endif
- // set_sys_clock_khz(180000, true);
- // set_sys_clock_khz(192000, true);
- // set_sys_clock_khz(240000, true);
- // set_sys_clock_khz(264000, true);
#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN
gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN);
@@ -201,8 +232,8 @@ void board_init(void)
#endif
#ifdef UART_DEV
- bi_decl(bi_2pins_with_func(UART_TX_PIN, UART_RX_PIN, GPIO_FUNC_UART));
uart_inst = uart_get_instance(UART_DEV);
+ bi_decl(bi_2pins_with_func(UART_TX_PIN, UART_RX_PIN, GPIO_FUNC_UART));
stdio_uart_init_full(uart_inst, CFG_BOARD_UART_BAUDRATE, UART_TX_PIN, UART_RX_PIN);
#endif
diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake
index aab9a4fae..57be416a2 100644
--- a/hw/bsp/rp2040/family.cmake
+++ b/hw/bsp/rp2040/family.cmake
@@ -28,6 +28,8 @@ elseif (PICO_PLATFORM STREQUAL "rp2350-arm-s" OR PICO_PLATFORM STREQUAL "rp2350"
set(OPENOCD_TARGET rp2350)
elseif (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(JLINK_DEVICE rp2350_riscv_0)
+ # rp2350-riscv.cfg needs the raspberrypi/openocd fork: mainline's riscv
+ # target does not take the -dap/-ap-num the config uses
set(OPENOCD_TARGET rp2350-riscv)
endif()
@@ -124,7 +126,6 @@ target_sources(tinyusb_host_base INTERFACE
${TOP}/src/class/midi/midi_host.c
${TOP}/src/class/midi/midi2_host.c
${TOP}/src/class/msc/msc_host.c
- ${TOP}/src/class/vendor/vendor_host.c
)
# Sometimes have to do host specific actions in mostly common functions
diff --git a/hw/bsp/samd2x_l2x/family.cmake b/hw/bsp/samd2x_l2x/family.cmake
index 76371ccdc..2edcea0cd 100644
--- a/hw/bsp/samd2x_l2x/family.cmake
+++ b/hw/bsp/samd2x_l2x/family.cmake
@@ -106,7 +106,6 @@ function(family_configure_example TARGET RTOS)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
${TOP}/src/portable/microchip/samd/dcd_samd.c
- ${TOP}/src/portable/microchip/samd/hcd_samd.c
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
)
# Add HCD support for SAMD21 (has host capability)
diff --git a/hw/bsp/samd5x_e5x/boards/same54_xplained/ozone/same54.jdebug b/hw/bsp/samd5x_e5x/boards/same54_xplained/ozone/same54.jdebug
new file mode 100644
index 000000000..a0f8d5c3d
--- /dev/null
+++ b/hw/bsp/samd5x_e5x/boards/same54_xplained/ozone/same54.jdebug
@@ -0,0 +1,89 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* SAM E54 Xplained Pro carries a populated 20-pin Cortex Debug+ETM
+* connector (Table 5-11): TRACECLK=PC27, D0=PC28, D1=PC26, D2=PC25,
+* D3=PC24 - no rework needed. Firmware must be built with TRACE_ETM=1
+* (mux function H on those pins in board_init); TPIU/ETM are
+* ROM-table-discoverable so no J-Link script is required.
+* Trace clock is CPU/2 = 60 MHz at the stock 120 MHz core.
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 120000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M4F.svd");
+
+ Project.SetDevice ("ATSAME54P20");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-same54_xplained/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
diff --git a/hw/bsp/samd5x_e5x/family.c b/hw/bsp/samd5x_e5x/family.c
index 71ef2d6ce..a2c3b70de 100644
--- a/hw/bsp/samd5x_e5x/family.c
+++ b/hw/bsp/samd5x_e5x/family.c
@@ -87,6 +87,31 @@ void USB_3_Handler(void) { USB_Any_Handler(); }
static void max3421_init(void);
#endif
+#if defined(TRACE_ETM)
+// same54_xplained routes 4-bit trace to its 20-pin Cortex Debug+ETM header:
+// TRACECLK=PC27, D0=PC28, D1=PC26, D2=PC25, D3=PC24 - all peripheral
+// function H (CM4 trace). TPIU/ETM are ROM-table-discoverable; the debugger
+// arms them, firmware only muxes the pins.
+static void trace_etm_init(void) {
+ // the CM4 trace unit runs from its own GCLK channel (47): feed it GCLK0
+ // (CPU clock) - without this the pins mux fine but the port stays silent
+ GCLK->PCHCTRL[47].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
+ while (!(GCLK->PCHCTRL[47].reg & GCLK_PCHCTRL_CHEN)) {}
+
+ const uint8_t pin[] = {24, 25, 26, 27, 28};
+ for (unsigned i = 0; i < 5; i++) {
+ PORT->Group[2].PINCFG[pin[i]].reg = PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR;
+ if (pin[i] & 1) {
+ PORT->Group[2].PMUX[pin[i] >> 1].bit.PMUXO = 7; // function H
+ } else {
+ PORT->Group[2].PMUX[pin[i] >> 1].bit.PMUXE = 7;
+ }
+ }
+}
+#else
+ #define trace_etm_init()
+#endif
+
void board_init(void) {
// Clock init ( follow hpl_init.c )
hri_nvmctrl_set_CTRLA_RWS_bf(NVMCTRL, 0);
@@ -104,6 +129,8 @@ void board_init(void) {
// Init 1ms tick timer (samd SystemCoreClock may not correct)
SystemCoreClock = CONF_CPU_FREQUENCY;
+ trace_etm_init();
+
#if CFG_TUSB_OS == OPT_OS_NONE
SysTick_Config(CONF_CPU_FREQUENCY / 1000);
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
diff --git a/hw/bsp/same7x/boards/same70_xplained/board.h b/hw/bsp/same7x/boards/same70_xplained/board.h
index 85e23deb8..86edf606f 100644
--- a/hw/bsp/same7x/boards/same70_xplained/board.h
+++ b/hw/bsp/same7x/boards/same70_xplained/board.h
@@ -52,6 +52,10 @@ extern "C" {
#define UART_PORT_CLOCK ID_USART1
#define BOARD_USART USART1
+// TRACE_ETM: this board wires the KSZ8081 PHY reset to PC10; the family
+// trace init holds it in reset (RMII rx lines share the trace pads)
+#define TRACE_ETM_QUIET_ENET_PHY 1
+
static inline void board_vbus_set(uint8_t rhport, bool state) {
(void) rhport;
(void) state;
diff --git a/hw/bsp/same7x/boards/same70_xplained/ozone/same70.jdebug b/hw/bsp/same7x/boards/same70_xplained/ozone/same70.jdebug
new file mode 100644
index 000000000..f024f0ceb
--- /dev/null
+++ b/hw/bsp/same7x/boards/same70_xplained/ozone/same70.jdebug
@@ -0,0 +1,115 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* SAM E70 Xplained: solder a 20-pin 50-mil header on the J403 ETM footprint
+* (bottom side). TRACECLK=PD8 (peripheral D), TRACED0-3=PD4-7 (peripheral C),
+* shared with the Ethernet PHY - no Ethernet while tracing. TRACE_ETM=1
+* builds mux the pins and clock the TPIU from PCK3=MCK; TPIU/ETM are
+* ROM-table-discoverable so no J-Link script is required.
+* Trace clock pin is PCK3/2 = 75 MHz at the stock 300 MHz core (MCK 150).
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 300000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M7F.svd");
+
+ Project.SetDevice ("ATSAME70Q21B");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-same70_xplained/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+
+ // TPIU trace clock = PCK3; it must run BEFORE Ozone arms the trace
+ // components (TPIU programming while PCK3 is stopped is lost and the port
+ // emits unformatted garbage). A target reset wipes the PMC, so this runs
+ // in the post-reset/post-download hooks, not AfterTargetConnect.
+ Target.WriteU32 (0x400E064C, 0x00000014); // PMC_PCK3: CSS=MCK, PRESS=/2
+ Target.WriteU32 (0x400E0600, 0x00000800); // PMC_SCER: PCK3 on
+ // wait for PCKRDY3 (bounded) before Ozone arms the trace components
+ int i;
+ i = 0;
+ while (((Target.ReadU32 (0x400E0668) & 0x00000800) == 0) && (i < 100)) {
+ i = i + 1;
+ }
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+
+ // TPIU trace clock = PCK3; it must run BEFORE Ozone arms the trace
+ // components (TPIU programming while PCK3 is stopped is lost and the port
+ // emits unformatted garbage). A target reset wipes the PMC, so this runs
+ // in the post-reset/post-download hooks, not AfterTargetConnect.
+ Target.WriteU32 (0x400E064C, 0x00000014); // PMC_PCK3: CSS=MCK, PRESS=/2
+ Target.WriteU32 (0x400E0600, 0x00000800); // PMC_SCER: PCK3 on
+ // wait for PCKRDY3 (bounded) before Ozone arms the trace components
+ int i;
+ i = 0;
+ while (((Target.ReadU32 (0x400E0668) & 0x00000800) == 0) && (i < 100)) {
+ i = i + 1;
+ }
+}
diff --git a/hw/bsp/same7x/family.c b/hw/bsp/same7x/family.c
index d02e6c5f1..8ec6a708b 100644
--- a/hw/bsp/same7x/family.c
+++ b/hw/bsp/same7x/family.c
@@ -62,6 +62,38 @@ void board_init(void) {
/* Disable Watchdog */
hri_wdt_set_MR_WDDIS_bit(WDT);
+#if defined(TRACE_ETM)
+ // same70_xplained J403 (Cortex Debug+ETM footprint, bottom side) carries
+ // 4-bit trace: TRACECLK=PD8 (peripheral D), TRACED0-3=PD4-7 (peripheral C).
+#ifdef TRACE_ETM_QUIET_ENET_PHY
+ // The trace pins double as the Ethernet PHY's RMII receive lines
+ // (PD4=CRS_DV, PD5/6=RXD0/1, PD7=RXER - PHY OUTPUTS): hold the KSZ8081 in
+ // reset or it drives against the trace stream. The reset net is a BOARD
+ // property (same70_xplained: PHY_RESET=PC10), hence the board.h gate.
+ _pmc_enable_periph_clock(ID_PIOC);
+ gpio_set_pin_level(GPIO(GPIO_PORTC, 10), false);
+ gpio_set_pin_direction(GPIO(GPIO_PORTC, 10), GPIO_DIRECTION_OUT);
+ gpio_set_pin_function(GPIO(GPIO_PORTC, 10), GPIO_PIN_FUNCTION_OFF);
+#endif
+
+ // The TPIU is clocked from PCK3 (datasheet 16.7.4) - run it from MCK.
+ // skip if the debugger already started PCK3 (reprogramming glitches the
+ // clock mid-stream and desyncs the decoder)
+ uint32_t const pck3 = PMC_PCK_CSS_MCK | PMC_PCK_PRES(1); // MCK/2 = 75 MHz -> 37.5 MHz pin
+ if (PMC->PMC_PCK[3] != pck3 || !(PMC->PMC_SR & PMC_SR_PCKRDY3)) {
+ PMC->PMC_PCK[3] = pck3;
+ PMC->PMC_SCER = PMC_SCER_PCK3;
+ while (!(PMC->PMC_SR & PMC_SR_PCKRDY3)) {}
+ }
+ _pmc_enable_periph_clock(ID_PIOD);
+ uint32_t const clk_pin = PIO_PD8D_TPIU_TRACECLK;
+ uint32_t const dat_pin = PIO_PD4C_TPIU_TRACED0 | PIO_PD5C_TPIU_TRACED1 |
+ PIO_PD6C_TPIU_TRACED2 | PIO_PD7C_TPIU_TRACED3;
+ PIOD->PIO_ABCDSR[0] = (PIOD->PIO_ABCDSR[0] | clk_pin) & ~dat_pin; // D=11, C=01
+ PIOD->PIO_ABCDSR[1] |= clk_pin | dat_pin;
+ PIOD->PIO_PDR = clk_pin | dat_pin; // hand the pins to the peripheral
+#endif
+
#ifdef LED_PIN
_pmc_enable_periph_clock(LED_PORT_CLOCK);
gpio_set_pin_level(LED_PIN, LED_STATE_OFF);
diff --git a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h
index 18c13017a..959dc4828 100644
--- a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h
+++ b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h
@@ -88,7 +88,12 @@ static inline void SystemClock_Config(void) {
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLL1_SOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
+ #ifdef TRACE_ETM
+ RCC_OscInitStruct.PLL.PLLN = 100; // 100 MHz core: the Nucleo trace path (CN5 via solder bridges)
+ // corrupts the trace stream at higher TRACECLK (= SYSCLK/2)
+ #else
RCC_OscInitStruct.PLL.PLLN = 250;
+ #endif
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
diff --git a/hw/bsp/stm32h5/boards/stm32h563nucleo/ozone/stm32h563.jdebug b/hw/bsp/stm32h5/boards/stm32h563nucleo/ozone/stm32h563.jdebug
new file mode 100644
index 000000000..04f4e4582
--- /dev/null
+++ b/hw/bsp/stm32h5/boards/stm32h563nucleo/ozone/stm32h563.jdebug
@@ -0,0 +1,113 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* Nucleo-H563ZI trace: PE2-PE6 reach the MIPI-20 connector (CN5) only
+* with SB8, SB9, SB64, SB68, SB70, SB71, SB78 removed (MB1404 UM).
+* Firmware must be built with TRACE_ETM=1 (trace pin + DBGMCU init).
+*
+* The trace path through the solder bridges is signal-marginal: reliable
+* only at 100 MHz core (TRACE_ETM builds select this automatically in
+* board.h), port width 1 and +5 ns sample timing (validated empirically;
+* width 4 or 250 MHz core corrupts the stream within ~100 ms).
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (1);
+ Project.SetTraceTiming (5000, 5000, 5000, 5000);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 100000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M33F.svd");
+
+ Project.SetDevice ("STM32H563ZI");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-stm32h563nucleo/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetConnect
+*
+* Function description
+* Enable the trace clock domain (DBGMCU_CR: TRACE_IOEN | TRACE_CLKEN |
+* TRACE_MODE=4-bit) BEFORE Ozone touches the trace CoreSight components.
+* On STM32H5 an access to unclocked trace components hangs the debug AP
+* ("Failed to read target status") until the board is power-cycled.
+*
+**********************************************************************
+*/
+void AfterTargetConnect (void) {
+ unsigned int cr;
+ cr = Target.ReadU32(0x44024004); // DBGMCU_CR
+ // clock the domain (CLKEN|MODE=4-bit) but keep the pins OFF (clear IOEN):
+ // the pins must only go live via firmware trace_etm_init() AFTER the system
+ // clock switch, or the mid-trace frequency change desyncs the decoder.
+ Target.WriteU32(0x44024004, (cr & 0xFFFFFFEF) | 0xE0);
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
diff --git a/hw/bsp/stm32h5/family.c b/hw/bsp/stm32h5/family.c
index 867171734..36a95ac8c 100644
--- a/hw/bsp/stm32h5/family.c
+++ b/hw/bsp/stm32h5/family.c
@@ -99,6 +99,24 @@ static UART_HandleTypeDef UartHandle = {
};
#endif
+#ifdef TRACE_ETM
+static void trace_etm_init(void) {
+ // H5 trace pins are PE2 to PE6 (Nucleo-144: requires trace solder-bridge config, see board docs)
+ GPIO_InitTypeDef gpio_init;
+ gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ gpio_init.Alternate = GPIO_AF0_TRACE;
+ HAL_GPIO_Init(GPIOE, &gpio_init);
+
+ // Enable trace port + clock, synchronous 4-bit mode
+ DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_CLKEN | DBGMCU_CR_TRACE_MODE;
+}
+#else
+#define trace_etm_init()
+#endif
+
void board_init(void) {
// Cache UID before ICACHE is enabled (STM32H5 errata: reading UID_BASE with ICACHE causes hard fault)
volatile uint32_t* stm32_uuid = (volatile uint32_t*) UID_BASE;
@@ -127,6 +145,8 @@ void board_init(void) {
__HAL_RCC_GPIOI_CLK_ENABLE();
#endif
+ trace_etm_init();
+
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
diff --git a/hw/bsp/stm32h5/linker/stm32h533xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h533xx_flash.icf
new file mode 100644
index 000000000..dc97788ae
--- /dev/null
+++ b/hw/bsp/stm32h5/linker/stm32h533xx_flash.icf
@@ -0,0 +1,32 @@
+/*###ICF### Section handled by ICF editor, don't touch! ****/
+/*-Editor annotation file-*/
+/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
+/*-Specials-*/
+define symbol __ICFEDIT_intvec_start__ = 0x08000000;
+/*-Memory Regions-*/
+define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
+define symbol __ICFEDIT_region_ROM_end__ = 0x0807FFFF;
+define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
+define symbol __ICFEDIT_region_RAM_end__ = 0x20043FFF;
+
+/*-Sizes-*/
+define symbol __ICFEDIT_size_cstack__ = 0x1000;
+define symbol __ICFEDIT_size_heap__ = 0x200;
+/**** End of ICF editor section. ###ICF###*/
+
+
+define memory mem with size = 4G;
+define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
+define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
+
+define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
+define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
+
+initialize by copy { readwrite };
+do not initialize { section .noinit };
+
+place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
+
+place in ROM_region { readonly };
+place in RAM_region { readwrite,
+ block CSTACK, block HEAP };
diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/ozone/stm32h743.jdebug b/hw/bsp/stm32h7/boards/stm32h743eval/ozone/stm32h743.jdebug
index 32a8155c1..f9780147d 100644
--- a/hw/bsp/stm32h7/boards/stm32h743eval/ozone/stm32h743.jdebug
+++ b/hw/bsp/stm32h7/boards/stm32h743eval/ozone/stm32h743.jdebug
@@ -10,6 +10,7 @@
*/
void OnProjectLoad (void) {
Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
Project.SetTraceTiming (100, 100, 100, 100);
Project.SetSWO (0);
Edit.SysVar (VAR_TRACE_CORE_CLOCK, 200000000);
@@ -22,7 +23,7 @@ void OnProjectLoad (void) {
Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("50 MHz");
- File.Open ("../../../../../../examples/device/cdc_msc/cmake-build-stm32h743eval/cdc_msc.elf");
+ File.Open ("../../../../../../examples/cmake-build-stm32h743eval/device/cdc_msc/cdc_msc.elf");
// File.Open ("../../../../../../examples/cmake-build-stm32h743eval_host1/host/cdc_msc_hid/cdc_msc_hid.elf");
}
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.h b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.h
index 996eb1515..098fc0bed 100644
--- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.h
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.h
@@ -123,7 +123,13 @@ static inline void SystemClock_Config(void)
RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL1.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL1.PLLM = 12;
+#ifdef TRACE_ETM
+ // 300 MHz core -> 50 MHz trace clock: at 600 MHz the stream survives idle
+ // but dies (unknown trace packet) during IRQ-heavy bursts, e.g. USB traffic
+ RCC_OscInitStruct.PLL1.PLLN = 150;
+#else
RCC_OscInitStruct.PLL1.PLLN = 300;
+#endif
RCC_OscInitStruct.PLL1.PLLP = 1;
RCC_OscInitStruct.PLL1.PLLQ = 2;
RCC_OscInitStruct.PLL1.PLLR = 2;
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3.jdebug b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3.jdebug
new file mode 100644
index 000000000..f6658d2d7
--- /dev/null
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3.jdebug
@@ -0,0 +1,94 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* Nucleo-H7S3L8 wires 4-bit trace to the CN1 MIPI20 natively (no rework):
+* TRACE_CLK/D0 = PE2/PE3, TRACE_D1/D2/D3 = PG14/PD2/PC12 (MB1737 Table 7).
+* Firmware must be built with TRACE_ETM=1 (trace pin mux + DBGMCU
+* DBGCKEN/TRACECLKEN in board_init).
+*
+* TRACE_ETM builds run a 300 MHz core (board.h) -> 50 MHz trace clock
+* (cpu/3/2). Width 2 on the stub-free D0/D1 lines: SB11/SB12 (default ON)
+* stub D2/D3 onto Zio CN8 and the 4-bit stream dies under IRQ-heavy USB
+* traffic (idle is clean) - remove SB11/SB12 to try width 4 / 600 MHz.
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ // declares the off-ROM-table CSTF/TMC/TPIU (see the script header)
+ Project.SetJLinkScript ("./stm32h7s3_trace.JLinkScript");
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (2);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 300000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M7F.svd");
+
+ Project.SetDevice ("STM32H7S3L8");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-stm32h7s3nucleo/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3_trace.JLinkScript b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3_trace.JLinkScript
new file mode 100644
index 000000000..5ef4f164d
--- /dev/null
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/ozone/stm32h7s3_trace.JLinkScript
@@ -0,0 +1,11 @@
+/* STM32H7RS pin trace: the CSTF funnel, TMC (ETF) and TPIU are not in the
+ * core ROM table - declare them or J-Link aborts trace init with "Required
+ * trace components for pin trace not found!" (addresses per SEGGER's
+ * NUCLEO-H7S3L8 trace example script; AP0).
+ */
+int ConfigTargetSettings(void) {
+ JLINK_ExecCommand("CORESIGHT_SetCSTFBaseAddr = 0x5C013000 ForceUnlock = 1 APIndex = 0");
+ JLINK_ExecCommand("CORESIGHT_SetTMCBaseAddr = 0x5C014000 ForceUnlock = 1 APIndex = 0");
+ JLINK_ExecCommand("CORESIGHT_SetTPIUBaseAddr = 0x5C015000 ForceUnlock = 1 APIndex = 0");
+ return 0;
+}
diff --git a/hw/bsp/stm32h7rs/family.c b/hw/bsp/stm32h7rs/family.c
index b0841c947..385b3c929 100644
--- a/hw/bsp/stm32h7rs/family.c
+++ b/hw/bsp/stm32h7rs/family.c
@@ -98,17 +98,24 @@ void OTG_HS_IRQHandler(void) {
#ifdef TRACE_ETM
void trace_etm_init(void) {
- // H7 trace pin is PE2 to PE6
- GPIO_InitTypeDef gpio_init;
- gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
+ // Nucleo-H7S3L8 routes 4-bit trace to the CN1 MIPI20: TRACE_CLK/D0 on
+ // PE2/PE3, TRACE_D1/D2/D3 on the PG14/PD2/PC12 alternates (MB1737 Table 7).
+ // No pull: pull-ups degrade the edges at the 100 MHz trace clock (= cpu/3/2)
+ GPIO_InitTypeDef gpio_init;
gpio_init.Mode = GPIO_MODE_AF_PP;
- gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init.Alternate = GPIO_AF0_TRACE;
+ gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3;
HAL_GPIO_Init(GPIOE, &gpio_init);
+ gpio_init.Pin = GPIO_PIN_14;
+ HAL_GPIO_Init(GPIOG, &gpio_init);
+ gpio_init.Pin = GPIO_PIN_2;
+ HAL_GPIO_Init(GPIOD, &gpio_init);
+ gpio_init.Pin = GPIO_PIN_12;
+ HAL_GPIO_Init(GPIOC, &gpio_init);
- // Enable trace clk, also in D1 and D3 domain
- DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN;
+ DBGMCU->CR |= DBGMCU_CR_DBGCKEN | DBGMCU_CR_TRACECLKEN;
}
#else
#define trace_etm_init()
diff --git a/hw/bsp/stm32l4/boards/stm32l412nucleo/board.h b/hw/bsp/stm32l4/boards/stm32l412nucleo/board.h
index a5250eda9..7f63ec431 100644
--- a/hw/bsp/stm32l4/boards/stm32l412nucleo/board.h
+++ b/hw/bsp/stm32l4/boards/stm32l412nucleo/board.h
@@ -64,9 +64,10 @@
* AHB Prescaler = 1
* APB1 Prescaler = 1
* APB2 Prescaler = 1
- * MSI Frequency(Hz) = 8000000
- * PLL_M = 1
- * PLL_N = 10
+ * MSI Frequency(Hz) = 48000000
+ * LSE Frequency(Hz) = 32768
+ * PLL_M = 6
+ * PLL_N = 20
* PLL_Q = 2
* PLL_R = 2
* VDD(V) = 3.3
@@ -78,29 +79,35 @@ static inline void board_clock_init(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_CRSInitTypeDef RCC_CRSInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
+ /* HAL clock setup reconfigures its tick while MSI is the reset SYSCLK. */
+ HAL_InitTick((1UL << __NVIC_PRIO_BITS) - 1UL);
+
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI;
- RCC_OscInitStruct.HSIState = RCC_HSI_ON;
- RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
- RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
+ RCC_OscInitStruct.LSEState = RCC_LSE_ON;
+ RCC_OscInitStruct.MSIState = RCC_MSI_ON;
+ RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
- RCC_OscInitStruct.PLL.PLLM = 1;
- RCC_OscInitStruct.PLL.PLLN = 10;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
+ RCC_OscInitStruct.PLL.PLLM = 6;
+ RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
+ /* Stabilize MSI against the on-board 32.768 kHz LSE crystal. */
+ HAL_RCCEx_EnableMSIPLLMode();
+
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
@@ -112,24 +119,9 @@ static inline void board_clock_init(void)
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
- /** Enable the SYSCFG APB clock
- */
- __HAL_RCC_CRS_CLK_ENABLE();
-
- /** Configures CRS
- */
- RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;
- RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;
- RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;
- RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000,1000);
- RCC_CRSInitStruct.ErrorLimitValue = 34;
- RCC_CRSInitStruct.HSI48CalibrationValue = 32;
-
- HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);
-
- /* Select HSI48 output as USB clock source */
+ /* Use the same LSE-trimmed MSI source for USB and the CPU PLL. */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
- PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
+ PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_MSI;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* Select PLL output as UART clock source */
diff --git a/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h
index be9ea7a31..873c004d9 100644
--- a/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h
+++ b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h
@@ -152,7 +152,13 @@ static void SystemClock_Config(void) {
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK4 | RCC_CLOCKTYPE_PCLK5);
RCC_ClkInitStruct.CPUCLKSource = RCC_CPUCLKSOURCE_IC1;
RCC_ClkInitStruct.IC1Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+#ifdef TRACE_ETM
+ // 300 MHz CPU -> 37.5 MHz TPIU clock (fixed cpu/8): at 600 MHz the trace
+ // stream dies with unknown-packet decode errors in the startup burst
+ RCC_ClkInitStruct.IC1Selection.ClockDivider = 4;
+#else
RCC_ClkInitStruct.IC1Selection.ClockDivider = 2;
+#endif
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_IC2_IC6_IC11;
RCC_ClkInitStruct.IC2Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
RCC_ClkInitStruct.IC2Selection.ClockDivider = 3;
diff --git a/hw/bsp/stm32n6/boards/stm32n657nucleo/ozone/stm32n657.jdebug b/hw/bsp/stm32n6/boards/stm32n657nucleo/ozone/stm32n657.jdebug
new file mode 100644
index 000000000..16eead280
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n657nucleo/ozone/stm32n657.jdebug
@@ -0,0 +1,94 @@
+/*********************************************************************
+*
+* OnProjectLoad
+*
+* Function description
+* Project load routine. Required.
+*
+* Notes
+* Nucleo-N657X0-Q wires 4-bit trace to the CN1 MIPI20 natively (SB36/38/
+* 39/40/41 fitted by default): TRACE_CLK = PB3, D0/D1/D2/D3 =
+* PE3/PB0/PB6/PB7 (MB1940 Table 5). No J-Link script needed - the N6
+* trace components sit behind a ROM table J-Link discovers natively.
+*
+* BOOT1 (JP2) must select Development boot (BOOT1 = 1): the N657 is
+* flashless, the app is a RAM image (AXISRAM2) loaded by the debugger,
+* and in flash boot the bootROM parks the chip un-attachable.
+* Firmware must be built with TRACE_ETM=1 (pin mux + DBGMCU
+* DBGCLKEN/TRACECLKEN). Trace clock = cpu/8. TRACE_ETM builds run a 300 MHz core (board.h) ->
+* 37.5 MHz TPIU clock: 600 MHz kills the stream in the startup burst.
+*
+**********************************************************************
+*/
+void OnProjectLoad (void) {
+ Project.SetTraceSource ("Trace Pins");
+ Project.SetTracePortWidth (4);
+ Project.SetSWO (0);
+ Edit.SysVar (VAR_TRACE_CORE_CLOCK, 300000000);
+ Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M55F.svd");
+
+ Project.SetDevice ("STM32N657X0");
+ Project.SetHostIF ("USB", "");
+ Project.SetTargetIF ("SWD");
+ Project.SetTIFSpeed ("4 MHz");
+
+ File.Open ("../../../../../../examples/cmake-build-stm32n657nucleo/device/cdc_msc/cdc_msc.elf");
+}
+
+/*********************************************************************
+*
+* AfterTargetReset
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetReset (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
+
+/*********************************************************************
+*
+* AfterTargetDownload
+*
+* Function description
+* Event handler routine.
+* - Sets the PC register to program reset value.
+* - Sets the SP register to program reset value on Cortex-M.
+*
+**********************************************************************
+*/
+void AfterTargetDownload (void) {
+ unsigned int SP;
+ unsigned int PC;
+ unsigned int VectorTableAddr;
+
+ VectorTableAddr = Elf.GetBaseAddr();
+
+ if (VectorTableAddr == 0xFFFFFFFF) {
+ Util.Log("Project file error: failed to get program base");
+ } else {
+ SP = Target.ReadU32(VectorTableAddr);
+ Target.SetReg("SP", SP);
+
+ PC = Target.ReadU32(VectorTableAddr + 4);
+ Target.SetReg("PC", PC);
+ }
+}
diff --git a/hw/bsp/stm32n6/family.c b/hw/bsp/stm32n6/family.c
index 80de20c6a..9d3faa1f2 100644
--- a/hw/bsp/stm32n6/family.c
+++ b/hw/bsp/stm32n6/family.c
@@ -110,6 +110,27 @@ void USB1_OTG_HS_IRQHandler(void) {
tusb_int_handler(0, true);
}
+#ifdef TRACE_ETM
+static void trace_etm_init(void) {
+ // Nucleo-N657X0-Q routes 4-bit trace to the CN1 MIPI20 natively:
+ // TRACE_CLK = PB3, D0 = PE3, D1 = PB0, D2 = PB6, D3 = PB7 (MB1940 Table 5)
+ GPIO_InitTypeDef gpio_init;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Pull = GPIO_NOPULL;
+ gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ gpio_init.Alternate = GPIO_AF0_TRACE;
+ gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7;
+ HAL_GPIO_Init(GPIOB, &gpio_init);
+ gpio_init.Pin = GPIO_PIN_3;
+ HAL_GPIO_Init(GPIOE, &gpio_init);
+
+ // trace clock (ck_cpu_tpiu) is a fixed cpu/8 - just enable it
+ DBGMCU->CR |= DBGMCU_CR_DBGCLKEN | DBGMCU_CR_TRACECLKEN;
+}
+#else
+ #define trace_etm_init()
+#endif
+
void board_init(void) {
/* Enable BusFault and SecureFault handlers (HardFault is default) */
SCB->SHCSR |= (SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_SECUREFAULTENA_Msk);
@@ -148,6 +169,7 @@ void board_init(void) {
for (uint8_t i = 0; i < TU_ARRAY_SIZE(board_pindef); i++) {
HAL_GPIO_Init(board_pindef[i].port, &board_pindef[i].pin_init);
}
+ trace_etm_init();
NVIC_SetPriority(UCPD1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(UCPD1_IRQn);