J-Link Version info:
SEGGER J-Link Commander V8.24 (Compiled Mar 26 2025 15:34:49)
DLL version V8.24, compiled Mar 26 2025 15:33:55
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Feb 20 2025 16:24:17
Hardware version: V11.00
Hardware used: Raspberry Pi Pico 2 (ARM mode)
I noticed a drastic loss of performance when debugging with J-Link that went away if I simply reset the MCU after flashing and attached to the running program.
I eventually narrowed it down to the XIP Cache being disabled and I think the following shows the problem using just J-Link Commander.
Given the following JLinkScript:
__constant U32 XIP_CTRL = 0x400C8000;
void XIPCheck(void)
{
U32 value;
value = JLINK_MEM_ReadU32(XIP_CTRL);
JLINK_SYS_Report1("XIP_CTRL = ", value);
}
int HandleBeforeFlashProg(void) { XIPCheck(); return 0; }
int HandleAfterFlashProg(void) { XIPCheck(); return 0; }
int AfterResetTarget(void) { XIPCheck(); return 0; }
Display More
Connecting to the board after powering it up, you can see this register isn't reset to the power on default after the flash program has finished:
Type "connect" to establish a target connection, '?' for help
J-Link>con
Please specify device / core. <Default>: RP2350_M33_0
Type '?' for selection dialog
Device>
Please specify target interface:
J) JTAG (Default)
S) SWD
T) cJTAG
TIF>s
Specify target interface speed [kHz]. <Default>: 4000 kHz
Speed>
Device "RP2350_M33_0" selected.
Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 44us
InitTarget() start
InitTarget() end - Took 12.6ms
Found SW-DP with ID 0x4C013477
DPIDR: 0x4C013477
CoreSight SoC-600 or later (DPv3 detected)
AP map detection skipped. User specified AP map and usage.
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x411FD210. Implementer code: 0x41 (ARM)
Feature set: Mainline
Cache: No cache
Found Cortex-M33 r1p0, Little endian.
FPUnit: 8 code (BP) slots and 0 literal slots
Security extension: implemented
Secure debug: enabled
CoreSight components:
ROMTbl[0] @ E00FF000
[0][0]: E000E000 CID B105900D PID 000BBD21 DEVARCH 47702A04 DEVTYPE 00 Cortex-M33
[0][1]: E0001000 CID B105900D PID 000BBD21 DEVARCH 47701A02 DEVTYPE 00 DWT
[0][2]: E0002000 CID B105900D PID 000BBD21 DEVARCH 47701A03 DEVTYPE 00 FPB
[0][3]: E0000000 CID B105900D PID 000BBD21 DEVARCH 47701A01 DEVTYPE 43 ITM
[0][5]: E0041000 CID B105900D PID 002BBD21 DEVARCH 47724A13 DEVTYPE 13 ETM
[0][6]: E0042000 CID B105900D PID 000BBD21 DEVARCH 47701A14 DEVTYPE 14 CSS600-CTI
Memory zones:
Zone: "Default" Description: Default access mode
Cortex-M33 identified.
J-Link>reset
Reset delay: 0 ms
Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
Reset: ARMv8M core with Security Extension enabled detected. Switch to secure domain.
Reset: Halt core after reset via DEMCR.VC_CORERESET.
Reset: Reset device via AIRCR.SYSRESETREQ.
AfterResetTarget() start
XIP_CTRL = 0x00000083
AfterResetTarget() end - Took 2.04ms
J-Link>erase
No address range specified, 'Erase Chip' will be executed
'erase': Performing implicit reset & halt of MCU.
Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
Reset: ARMv8M core with Security Extension enabled detected. Switch to secure domain.
Reset: Halt core after reset via DEMCR.VC_CORERESET.
Reset: Reset device via AIRCR.SYSRESETREQ.
AfterResetTarget() start
XIP_CTRL = 0x00000083
AfterResetTarget() end - Took 2.55ms
Erasing device...
HandleBeforeFlashProg() start
XIP_CTRL = 0x00000083
HandleBeforeFlashProg() end - Took 2.80ms
J-Link: Flash download: Total time needed: 1.752s (Prepare: 0.173s, Compare: 0.000s, Erase: 1.486s, Program: 0.000s, Verify: 0.000s, Restore: 0.092s)
HandleAfterFlashProg() start
XIP_CTRL = 0x00000000
HandleAfterFlashProg() end - Took 2.72ms
Erasing done.
Display More
Here's where the SDK defines the reset value for this register:
// Register : XIP_CTRL
// Description : Cache control register. Read-only from a Non-secure context.
#define XIP_CTRL_OFFSET _u(0x00000000)
#define XIP_CTRL_BITS _u(0x00000ffb)
#define XIP_CTRL_RESET _u(0x00000083)
See also section 4.4.5 of the RP2350 datasheet.
I did notice a few other peripheral registers didn't match their power on defaults.
Apart from the XIP Cache control register, the differences seem benign but I'm listing them for completeness.
Peripheral | Register | Address | Value after power on | Value after download | Notes |
PPB | FP_CTRL | 0xE0002000 | 0x10000080 | 0x10000081 | Enable flag |
OTP | INTR | 0x40120164 | 0x00000000 | 0x00000010 | Inconsistent repro |
POWMAN | STATE | 0x40100038 | 0x00000000 | 0x00000100 | Req ignored |
POWMAN | INTR | 0x401000E0 | 0x00000000 | 0x00000004 | Req ignored |
WATCHDOG | CTRL | 0x400D8000 | 0x07000000 | 0x07FFFFFF | Timer value, harmless? |
XIP_CTRL | CTRL | 0x400C8000 | 0x00000083 | 0x00000000 | See above |
These were found by running a simple "while(1);" firmware, dumping all the registers with Ozone, comparing and filtering out the non-deterministic registers.
Please let me know if you need more information!