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.
This commit is contained in:
hathach
2026-07-24 15:28:52 +07:00
parent 927f12415e
commit 3b7ef31593
3 changed files with 138 additions and 0 deletions

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);