We have custom board running on iMX.RT1061X with Macronix Octal SPI DDR Flash memory and we developed custom FlashLoader for it. FlashLoader is using the LCXFlashDriverLib and we compile the .cfx loader. We also created custom board definition JSON for it.
We use latest LinkServer v25.6.131 and MCU-Link debugger FW version 3.160.
Everything works nicely with LinkFlash.exe that comes with LinkServer, but when we launch the GDB debug session (LinkServer as GDB server), then there are problems writing the Flash. Log beginning and end:
C:\NXP\LinkServer_25.6.131\LinkServer.exe gdbserver MIMXRT1061XVN5B:XXX
INFO: Exact match for MIMXRT1061XVN5B:XXX found
INFO: Selected device MIMXRT1061XVN5B:XXX
INFO: Getting available probes
INFO: Selected probe #1 RBQDXOXGJT0PU (MCU-LINK (r0FB) CMSIS-DAP V3.160)
INFO: MCU-Link firmware update `check`: Probe ([RBQDXOXGJT0PU] [MCU-LINK (r0FB)
CMSIS-DAP V3.160]) is already running the same firmware version as the included firmware version [3.160]
Firmware update `check`: not required - forced update can be performed using: `LinkServer probe #1 update forced`
INFO: [stub (3333)] Ns: LinkServer RedlinkMulti Driver v25.6 (Jun 26 2025 19:34:05 - crt_emu_cm_redlink.exe build 1017)
GDB server listening on port 3333 in debug mode (core cm7)
Semihosting server listening on port 4444 (core cm7)
INFO: Connected to core cm7
INFO: [stub (3333)] Pc: ( 0) Reading remote configuration
INFO: [stub (3333)] Wc(03). No cache support.
INFO: [stub (3333)] Nc: Found generic directory XML file in C:\Users\XXX\AppData\Local\Temp\tmpd134cnsw\crt_directory.xml
INFO: [stub (3333)] Pc: ( 5) Remote configuration complete
INFO: [stub (3333)] Nc: Reconnected to existing LinkServer process.
INFO: [stub (3333)] Wc: ============= SCRIPT: RT1060_connect.scp =============
Wc: RT1060 Connect Script
Wc: DpID = 0BD11477
Wc: APID = 0x04770041
Wc: Disabling MPU
Wc: Configure FlexRAM for 768KB OC RAM, 128KB I-TCM, 128KB D-TCM
INFO: [stub (3333)] Wc: Finished
Wc: ============= END SCRIPT =============================
INFO: [stub (3333)] Nc: Probe Firmware: MCU-LINK (r0FB) CMSIS-DAP V3.160 (NXP Semiconductors)
Nc: Serial Number: RBQDXOXGJT0PU
Nc: VID:PID: 1FC9:0143
Nc: USB Path: 0002:0012:00
INFO: [stub (3333)] Nc: Using memory from core 0 after searching for a good core
INFO: [stub (3333)] Pc: ( 30) Emulator Connected
INFO: [stub (3333)] Pc: ( 40) Debug Halt
INFO: [stub (3333)] Pc: ( 50) CPU ID
INFO: [stub (3333)] Nc: debug interface type = CoreSight DP (DAP DP ID 0BD11477) over SWD TAP 0
Nc: processor type = Cortex-M7 (CPU ID 00000C27) on DAP AP 0
INFO: [stub (3333)] Nc: number of h/w breakpoints = 8
Nc: number of flash patches = 0
INFO: [stub (3333)] Nc: number of h/w watchpoints = 4
Nc: Probe(0): Connected&Reset. DpID: 0BD11477. CpuID: 00000C27. Info: <None>
INFO: [stub (3333)] Nc: Debug protocol: SWD. RTCK: Disabled. Vector catch: Disabled.
Ns: Content of CoreSight Debug ROM(s):
INFO: [stub (3333)] Nc: RBASE E00FD000: CID B105100D PID 000008E88C ROM (type 0x1)
INFO: [stub (3333)] Nc: ROM 1 E00FE000: CID B105100D PID 04000BB4C8 ROM (type 0x1)
INFO: [stub (3333)] Nc: ROM 2 E00FF000: CID B105100D PID 04000BB4C7 ROM (type 0x1)
INFO: [stub (3333)] Nc: ROM 3 E000E000: CID B105E00D PID 04000BB00C Gen SCS (type 0x0)
INFO: [stub (3333)] Nc: ROM 3 E0001000: CID B105E00D PID 04000BB002 Gen DWT (type 0x0)
INFO: [stub (3333)] Nc: ROM 3 E0002000: CID B105E00D PID 04000BB00E Gen (type 0x0)
INFO: [stub (3333)] Nc: ROM 3 E0000000: CID B105E00D PID 04000BB001 Gen ITM (type 0x0)
INFO: [stub (3333)] Nc: ROM 2 E0041000: CID B105900D PID 04001BB975 CSt ARM ETMv4.0 type 0x13 Trace Source - Core
INFO: [stub (3333)] Nc: ROM 2 E0042000: CID B105900D PID 04004BB906 CSt type 0x14 Debug Control - Trigger, e.g. ECT
INFO: [stub (3333)] Nc: ROM 1 E0040000: CID B105900D PID 04000BB9A9 CSt type 0x11 Trace Sink - TPIU
INFO: [stub (3333)] Nc: ROM 1 E0043000: CID B105F00D PID 04001BB101 Sys (type 0x0)
INFO: [stub (3333)] Nc: NXP: MIMXRT1061XVN5B
INFO: [stub (3333)] Nc: DAP stride is 1024 bytes (256 words)
INFO: [stub (3333)] Nc: Inspected v.2 External Flash Device on SPI MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
Nc: Image 'XXX Nov 3 2025 17:21:03'
INFO: [stub (3333)] Pc: ( 65) Chip Setup Complete
Pc: ( 70) License Check Complete
Ns: Awaiting telnet connection to port 14444 ...
INFO: [stub (3333)] Pc: ( 85) Registered Semihost Handler
Pc: (100) Target Ready
INFO: [stub (3333)] Na: GDB nonstop mode disabled (using allstop mode)
INFO: [stub (3333)] Wc: Zephyr stack backtrace is disabled
INFO: [stub (3333)] Nc: Opening flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
INFO: [stub (3333)] Nc: Sending VECTRESET to run flash driver
INFO: [stub (3333)] Nc: Flash device supported (8MB = 2048*4K at 0x60000000)
Pb: 1 of 1 ( 0) Writing sectors 0-198 at 0x60000000 with 814992 bytes
Ps: ( 0) at 60000000: 0 bytes - 0/814992
INFO: [stub (3333)] Ps: ( 0) at 60000000: 4096 bytes - 4096/814992
INFO: [stub (3333)] Ps: ( 1) at 60001000: 4096 bytes - 8192/814992
INFO: [stub (3333)] Ps: ( 1) at 60002000: 4096 bytes - 12288/814992
INFO: [stub (3333)] Ps: ( 2) at 60003000: 4096 bytes - 16384/814992
Nc: 60004000 done 2% (16384 out of 814992)
...
Nc: 600C4000 done 98% (802816 out of 814992)
INFO: [stub (3333)] Ps: ( 99) at 600C4000: 4096 bytes - 806912/814992
INFO: [stub (3333)] Ps: ( 99) at 600C5000: 4096 bytes - 811008/814992
INFO: [stub (3333)] Ps: (100) at 600C6000: 4096 bytes - 815104/814992
Nc: Sectors written: 199, unchanged: 0, total: 199
Nc: Closing flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
INFO: [stub (3333)] Pb: (100) Finished writing Flash successfully.
INFO: [stub (3333)] Nc: Opening flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx (already resident)
INFO: [stub (3333)] Nc: Sending VECTRESET to run flash driver
Error finishing flash operation
INFO: [stub (3333)] Nc: Flash device supported (8MB = 2048*4K at 0x60000000)
Pb: 1 of 1 ( 0) Writing sectors 198-198 at 0x600C6F92 with 44 bytes
Nc: Closing flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
INFO: [stub (3333)] Pb: (100) Writing Flash ended with an error.
Debugger disconnected
Process finished with exit code 0
INFO: Disconnected from core cm7
GDB Server stopped, exit code 1
It appears like it failed to write 44 bytes to unaligned address.
However, writing the same ELF file with LinkFlash succeeds:
Nc: 600C4000 done 98% (802816 out of 815032)
Ps: ( 99) at 600C4000: 4096 bytes - 806912/815032
Ps: ( 99) at 600C5000: 4096 bytes - 811008/815032
Ps: (100) at 600C6000: 4096 bytes - 815104/815032
Nc: Sectors written: 199, unchanged: 0, total: 199
Nc: Closing flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
Pb: (100) Finished writing Flash successfully.
Nt: Loaded 0xC6FB6 bytes in 6939ms (about 117kB/s)
Nt: Loading 'zephyr.elf' ELF 0x600C6FB8 len 0x4
Nc: Opening flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx (already resident)
Nc: Sending VECTRESET to run flash driver
Nc: Flash device supported (8MB = 2048*4K at 0x60000000)
Pb: 1 of 1 ( 0) Writing sectors 198-198 at 0x600C6FB8 with 4 bytes
Ps: ( 0) at 600C6000: 0 bytes - 0/4028
Ps: (100) at 600C6000: 4096 bytes - 4096/4028
Nc: 600C7000 done 100% (4096 out of 4028)
Nc: Sectors written: 1, unchanged: 0, total: 1
Nc: Closing flash driver MIMXRT1061X_SFDP_FlexSPI1_MXIC_OPI.cfx
Pb: (100) Finished writing Flash successfully.
Nt: Loaded 0x4 bytes in 129ms (about 0kB/s)
Nt: Reset target (system)
Nc: Starting execution using system reset
But there's a difference in the last section address and size.
If it matters, the IDE is IntelliJ CLion and firmware is a Zephyr RTOS application. This issue does not always occur, it seems like it depends on the firmware itself - like how large it is.
My first though was that it fails because in the custom Flashloader we have asserts on the address and size alignments. The "pseudo" page size is 4KB and true page size is 256B and trying to writing anything unaligned will obviously return error code kStatus_InvalidArgument. But as you can see in the log, no error codes are returned from Flashloader (or at least not printed into console).
But LinkFlash manages to write unaligned data by writing 0xFF's into unused bytes. And we have it working with GDB when binary has different size.
I suspected maybe the sector hashing causes trouble and built a Flashloader without it, but that didn't help. I also tried older LinkServer, same issue.
Right now it appears that LinkServer has some internal problem. If nothing else, it lacks the proper explanation to the failure.
Relevant parts of Flashloader source code:
FlashDev.c
FLASHDEV_SECTION
FlashDeviceV_t FlashDevice =
{
FLASH_DRV_VERS, // Driver Version, do not modify!
"XXX "__DATE__" "__TIME__,
EXTSPI, // Device Type
FLEXSPI_BASE_ADDRESS, // Device Start Address
FLASH_SIZE, // Device Size
FLASH_PSEUDO_PAGE_SIZE, // Programming Page Size
0, // Reserved, must be 0
0xFF, // Initial Content of Erased Memory
100, // Program Page Timeout (guessing it is in milliseconds)
1000, // Erase Sector Timeout (guessing it is in milliseconds)
// Specify Size and Address of Sectors
{
{FLASH_SECTOR_SIZE, 0},
{SECTOR_END}
}
};
driver header:
#define FLEXSPI_INST FLEXSPI
#define FLEXSPI_PORT kFLEXSPI_PortA1
#define FLEXSPI_CLOCK kCLOCK_FlexSpi
#define FLEXSPI_BASE_ADDRESS FlexSPI_AMBA_BASE
#define FLASH_SIZE 0x800000 /* 8 MB */
#define FLASH_PAGE_SIZE 256
#define FLASH_SECTOR_SIZE 4096
#define FLASH_SECTOR_COUNT (FLASH_SIZE / FLASH_SECTOR_SIZE)
#define FLASH_PSEUDO_PAGE_SIZE 4096 /* Allow debugger to transmit programmable data in larger chunks */
FlashPrg.c programming function:
uint32_t ProgramPage(uint32_t adr, uint32_t sz, uint8_t *buf)
{
status_t status = 0;
uint32_t *ptr = 0;
if (adr < FLEXSPI_BASE_ADDRESS) {
return kStatus_InvalidArgument;
}
if ((adr % FLASH_PAGE_SIZE) != 0) {
return kStatus_InvalidArgument;
}
if (sz == 0) {
return kStatus_InvalidArgument;
}
if ((sz % FLASH_PAGE_SIZE) != 0) {
return kStatus_InvalidArgument;
}
if ((((uint32_t)buf) % sizeof(uint32_t)) != 0) {
return kStatus_InvalidArgument;
}
if ((adr + sz) > (FLEXSPI_BASE_ADDRESS + FLASH_SIZE)) {
return kStatus_InvalidArgument;
}
/* Get offset to base of Flash */
adr -= FLEXSPI_BASE_ADDRESS;
ptr = (void *)buf;
while (sz > 0) {
status = flexspi_mxic_nor_page_program(adr, ptr);
if (status != kStatus_Success) {
return status;
}
sz -= FLASH_PAGE_SIZE;
adr += FLASH_PAGE_SIZE;
ptr += FLASH_PAGE_SIZE / sizeof(uint32_t);
}
return kStatus_Success;
}