LPC55S69: Core 1 never starts despite fully verified CPBOOT/CPUCTRL/CPUCFG sequence

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

LPC55S69: Core 1 never starts despite fully verified CPBOOT/CPUCTRL/CPUCFG sequence

24 次查看
ryan714
Contributor I

LPC55S69: Core 1 never begins execution despite fully verified boot sequence (MCMGR and hand-written register writes both fail identically)

Environment

  • Board: LPC55S69-EVK (LPCXpresso55S69), LPC55S69JBD100
  • IDE: MCUXpresso IDE v25.6 [Build 136] [2025-06-27]
  • OS: Linux (openSUSE)
  • Toolchain: GNU ARM Embedded (bundled), GCC 14.2.1
  • Debug probe: onboard LPC-Link2, LinkServer backend
  • SDK components used: driver.flexcomm, driver.mailbox, middleware.multicore.mcmgr_lpc55s69, freertos_kernel + cm33_non_trustzone_port (master only)

Summary

Core 0 (master, cm33_core0) runs correctly. Core 1 (slave, cm33_core1, role M33SLAVE) never appears to execute even the first instruction of its own main(), despite every element of the boot sequence being independently verified correct at the register and memory level, across two separate clean-room project builds (one hand-written register sequence, one using NXP's own MCMGR middleware). Both attempts reach an identical dead end.

What Has Been Independently Verified Correct

Attempt 1 — Hand-written boot sequence

  • SYSCON->CPBOOT set to the real, linker-confirmed address of the embedded slave image (verified via objdump -h section VMA, cross-checked against nm symbol addresses — not a symbol that resolves to 0x0, an actual non-zero embed location)
  • SYSCON->CPUCTRL read back as 0x08 (bit 3 CPU1CLKEN set, bit 5 CPU1RSTEN clear) immediately after the release write, captured in-band (written into shared memory by the same function that performed the write, not read later via a possibly-stale debugger session)
  • SYSCON->CPUCFG bit 2 (CPU1ENABLE) confirmed set (0x04)
  • Vector table at the confirmed boot address independently verified valid: initial stack pointer computed correctly (top of Core 1's relocated SRAM region), reset vector address matches the real ResetISR symbol from nm (confirmed by disassembling the target address and finding genuine, sensible Cortex-M startup code: cpsid i → SystemInit() → data_init/bss_init loops → cpsie i → __main → _initio → application main())
  • Confirmed shared-memory struct resolves to the identical physical address in both cores' independently compiled .map files
  • Confirmed Core 1's private SRAM/stack region does not overlap Core 0's (relocated to a separate physical SRAM bank)
  • Confirmed the embedded slave image's .data section (non-zero-initialized globals) does not land inside Core 0's live memory (required a custom linker script fragment using INSERT BEFORE .data, since the default linker script has no placement rule for the objcopy-renamed multicore section and it otherwise falls into Core 0's SRAM as an "orphan section")

Despite all of the above, a diagnostic value written as the literal first line of Core 1's main() (into memory confirmed shared and correctly addressed) never changes from its initial value.

Attempt 2 — Fresh project using NXP's mcmgr_lpc55s69 middleware

Rebuilt from scratch using MCMGR_Init() / MCMGR_StartCore() / MCMGR_TriggerEvent() instead of hand-written register writes, to rule out a mistake in our own register sequence.

  • Read mcmgr_internal_core_api_lpc55s69.c directly: confirmed mcmgr_start_core_internal() performs the same CPUCFG → CPBOOT → CPUCTRL sequence, using the correct SDK macros (SYSCON_CPUCTRL_CPU1RSTEN_MASK, etc.)
  • Discovered MCMGR_Init() (called from main()) does not call MCMGR_EarlyInit() / mcmgr_early_init_internal(). The latter is a separate public function whose own source comment states it is "intended to be called as close to the reset entry as possible, (within the startup sequence in SystemInitHook)" — but nothing in the generated project wires this up automatically. SystemInitHook() is __attribute__((weak)) in the generic device startup file and defaults to an empty stub.
  • Added our own SystemInitHook() override on both cores calling mcmgr_early_init_internal(MCMGR_GetCurrentCore()). Confirmed via .map file that this override genuinely links in as the real function (not the weak stub) on both projects.
  • Re-applied and re-confirmed every fix from Attempt 1 (embed-address stability across iterative rebuilds, .data section redirect via the same linker fragment technique, Core 1 SRAM relocation, CPUCFG/CPBOOT/CPUCTRL register values all identical to Attempt 1's results)
  • MCMGR_BUSY_POLL_COUNT is undefined by default, so MCMGR_StartCore(..., kMCMGR_Start_Synchronous) blocks with no timeout at all in mcmgr.c's internal wait loop (while (s_mcmgrCoresContext[coreNum].state != kMCMGR_RunningCoreState)), confirmed by reading the macro's conditional compilation directly in mcmgr.h

Result: identical outcome. Core 0 blocks forever inside MCMGR_StartCore(). A diagnostic shared-memory value (confirmed identical address in both cores' .map files, in a genuinely shared SRAM bank, .noinit so unaffected by C-runtime init) written as literally the first executable line of Core 1's main() never leaves its initial value of 0.

Question

Given CPUCFG, CPBOOT, and CPUCTRL all read back exactly as the reference implementation (mcmgr_internal_core_api_lpc55s69.c) intends, and the embedded image at the boot address is independently confirmed to be a valid, correctly-linked Cortex-M binary — is there an additional step required to actually start Core 1's instruction fetch on this part that is not captured by these three register writes alone?

Specifically:

  • Is there a known silicon errata for LPC55S69 (any revision) affecting CPBOOT/CPUCTRL-based secondary core boot?
  • Does starting Core 1 genuinely require a debug-probe-level action (e.g., an SWD attach/resume specifically targeting the second SWD device enumerated on this part) in addition to the application-level register sequence? This is suggested by the fact that NXP's own multicore SDK examples (e.g. freertos_message_buffers_secondary_core), when debugged via the IDE's normal single-project "Debug" flow, appear to bring up Core 1 successfully with no separate Launch Group configuration — implying MCUXpresso's debug launch itself may be performing an additional step beyond what application code alone can trigger.
  • Is there a required minimum delay, ordering constraint, or additional register (e.g. in the power/clock domain) between these three writes that isn't reflected in the reference mcmgr_internal_core_api_lpc55s69.c implementation?

Happy to provide full project files, .map files, or a minimal reproduction project on request.

标签 (1)
0 项奖励
回复
0 回复数