Issue with pyOCD flashing with CMSIS Pack NXP::MCXN947_DFP@25.09.00

Hi,

I’m using pyOCD on Ubuntu 24.04 (Linux) to flash firmware onto the FRDM-MCXN947 board.
When using the latest device pack NXP::MCXN947_DFP@25.09.00, the flashing process fails with the following error:

flash init timed out [__main__]

In contrast, flashing seems to work correctly with the older pack NXP::MCXN947_DFP@19.0.0.

These packs are available in here.

After enabling detailed debug output in pyOCD, I observed that the "WaitForStopAfterReset" debug sequence defined in the NXP.MCXN947_DFP.pdsc file does not execute properly in version 25.09.00.
Manually replacing the "WaitForStopAfterReset" sequence in version 25.09.00 with the corresponding version from 19.0.0 resolves the issue, and flashing succeeds as expected.

Could you please clarify what changes were introduced to the "WaitForStopAfterReset" sequence in NXP::MCXN947_DFP@25.09.00, and why they might cause this behavior with pyOCD?

I was told by NXP that these packs are developed and supported by ARM, hence I am posting this problem in this forum.

Thanks

Parents
  • Just to clarify, at present, Arm only develops and maintains the STM32 packs published in the Open-CMSIS-Pack repository. However, we do occasionally collaborate with or assist other vendors when issues are reported.

    After reproducing and analyzing the behavior, I made the following adjustments that resolved the flashing and debugging issue observed with CMSIS Debugger. For the sequence WaitForStopAfterReset:

    1. Call EnableDebugMailbox when required
      This step ensures that the Debug Mailbox is initialized before any AP or core register accesses. Without this, early writes to the SCS or DHCSR can fail because the debug channel is not yet active.
    2. Handle multiple ResetSystem calls
      In µVision, the debug flow triggers ResetSystem only once. However, CMSIS Debugger performs one ResetSystem during the pre-launch “CMSIS Load” stage and another when the GDB server starts. To prevent re-executing the Mailbox unlock twice, I added this condition checks the AHB-AP DbgStatus bit and only re-enables the Mailbox if it is not already active.
    3. Remove the second while-loop
      The second while-loop was removed because the debug channel has already been enabled at this stage. Keeping it can cause the sequence to be skipped, leading to incorrect halt behavior.

            <sequence name="WaitForStopAfterReset">
              <block>
                __var SCS_Addr    = 0xE000E000;
                __var DHCSR_Addr  = SCS_Addr + 0xDF0;
                __var DFSR_Addr  = SCS_Addr + 0xD30;
              </block>
              <!-- Check AHB-AP CSW DbgStatus to decide if the ROM finished preparation. -->
              <control while="(ReadAP(0) & 0x40) == 0" timeout="500000"/>
              <block>
                __var ap0_disable=0x55aa;
                // Read AP0 CSW
                ap0_disable = ((ReadAP(0x0) & 0x40) == 0);
              </block>
                <control if="ap0_disable">
                <block>Sequence("EnableDebugMailbox");</block>
              </control>
              <block>
                Write32(DHCSR_Addr, 0xA05F0003);  // Halt the core in case it didn't stop at a breakpiont.
                // Clear watch point
                Write32(0xE0001028, 0x0);
                Write32(0xE0001038, 0x0);
                Write32(0xE0001048, 0x0);
                Write32(0xE0001058, 0x0);
              </block>
              <!-- Reset Recovery: Wait for DHCSR.S_RESET_ST bit to clear on read -->
              <control while="(Read32(DHCSR_Addr) & 0x02000000)" timeout="500000"/>
              <control if="(Read32(DHCSR_Addr) & 0x00020000) == 0">
                <block>
                  Write32(DHCSR_Addr, 0xA05F0003);  // Force halt until finding a proper catch. Probably works better from flash.
                </block>
              </control>
            </sequence>

    We will contact NXP and share our proposed solution so they can review and integrate it in future DFP updates.

Reply
  • Just to clarify, at present, Arm only develops and maintains the STM32 packs published in the Open-CMSIS-Pack repository. However, we do occasionally collaborate with or assist other vendors when issues are reported.

    After reproducing and analyzing the behavior, I made the following adjustments that resolved the flashing and debugging issue observed with CMSIS Debugger. For the sequence WaitForStopAfterReset:

    1. Call EnableDebugMailbox when required
      This step ensures that the Debug Mailbox is initialized before any AP or core register accesses. Without this, early writes to the SCS or DHCSR can fail because the debug channel is not yet active.
    2. Handle multiple ResetSystem calls
      In µVision, the debug flow triggers ResetSystem only once. However, CMSIS Debugger performs one ResetSystem during the pre-launch “CMSIS Load” stage and another when the GDB server starts. To prevent re-executing the Mailbox unlock twice, I added this condition checks the AHB-AP DbgStatus bit and only re-enables the Mailbox if it is not already active.
    3. Remove the second while-loop
      The second while-loop was removed because the debug channel has already been enabled at this stage. Keeping it can cause the sequence to be skipped, leading to incorrect halt behavior.

            <sequence name="WaitForStopAfterReset">
              <block>
                __var SCS_Addr    = 0xE000E000;
                __var DHCSR_Addr  = SCS_Addr + 0xDF0;
                __var DFSR_Addr  = SCS_Addr + 0xD30;
              </block>
              <!-- Check AHB-AP CSW DbgStatus to decide if the ROM finished preparation. -->
              <control while="(ReadAP(0) & 0x40) == 0" timeout="500000"/>
              <block>
                __var ap0_disable=0x55aa;
                // Read AP0 CSW
                ap0_disable = ((ReadAP(0x0) & 0x40) == 0);
              </block>
                <control if="ap0_disable">
                <block>Sequence("EnableDebugMailbox");</block>
              </control>
              <block>
                Write32(DHCSR_Addr, 0xA05F0003);  // Halt the core in case it didn't stop at a breakpiont.
                // Clear watch point
                Write32(0xE0001028, 0x0);
                Write32(0xE0001038, 0x0);
                Write32(0xE0001048, 0x0);
                Write32(0xE0001058, 0x0);
              </block>
              <!-- Reset Recovery: Wait for DHCSR.S_RESET_ST bit to clear on read -->
              <control while="(Read32(DHCSR_Addr) & 0x02000000)" timeout="500000"/>
              <control if="(Read32(DHCSR_Addr) & 0x00020000) == 0">
                <block>
                  Write32(DHCSR_Addr, 0xA05F0003);  // Force halt until finding a proper catch. Probably works better from flash.
                </block>
              </control>
            </sequence>

    We will contact NXP and share our proposed solution so they can review and integrate it in future DFP updates.

Children
No data