summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-24 15:28:52 +0700
committerhathach <[email protected]>2026-07-24 15:56:14 +0700
commit3b7ef31593aeada32667be873f4bd1b6cfadf3cb (patch)
tree15b102e3ca6c606e0f8e3e87d45f7df332be02e3 /hw
parent927f12415ef09b6f590c83660c13491a644b4626 (diff)
stm32h5: TRACE_ETM support and stm32h563nucleo reference
H5 hangs its debug AP if trace CoreSight is touched unclocked (recover = power-cycle): the reference's AfterTargetConnect clocks the DBGMCU trace domain but defers IOEN to firmware, or the mid-boot clock switch desyncs the decoder. Stock solder bridges make the CN5 path marginal: validated config is 100 MHz core, width 1, +5 ns (board.h selects the reduced clock for TRACE_ETM builds); width 4 / 250 MHz retest waits on SB removal.
Diffstat (limited to 'hw')
-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
3 files changed, 138 insertions, 0 deletions
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);