Setting CPU registers from JLINK script (Cortex-M4) wih a value rm RAM

98 views Asked by At

The target and toolchain context :

So i use an exotic ARM Cortex M4 device (2 core M4 + 1 core NPU) which has an internal 8MB SDRAM and an external 16MB flash. This SoC also has a small internal SRAM and Flash but it is not used to flash the firmware and therefore a out of the context of this issue. The IDE is MDK (uvision 5), the debugger is Jlink OB (V7) with DLL 6.32, the debugger and version of Jlink cannot be changed due to compatibility reasons with other tools of the toolchain.

The problem :

During development and debug the firmware is flashed to the SDRAM, which avoids writing many cyles to the external FLASH and is faster. Due to MDK limitations after flashing the SDRAM it is not possible to run directly : in common cases (firmware to the flash) a reset would be performed, but we cannot do it here because the data is in SDRAM and after a reset the SDRAM is erased by BOOT0 / BOOT1 stages.

The only way to run after flashing is to start a debug session and then clic the "run at full speed" button. The debug session can then be closed and the SoC will continue to run.When we open the debug session, an .ini script is ran by MDK which will remap the SDRAM, dynamically set the SP (stack pointer) and PC (program counter) CPU registers, and set the CPU to run. Obviously opening a debug session everytime just to run the SoC after any modification of the firmware is problematic : it opens a bunch of files (startup.s init.c etc), it implies multiple actions, messes up with the IDE and wastes time.

The goal :

Automatically performing these actions (SDRAM remap, set SP and PC, run) after flashing, so that the debug sessions does not have to be started and the SoC can run directly.

What i tried :

So, i figured i could probably write a Jlink script

    halt
    WaitHalt 1000
    w4 0xE0042020, 0x00000003 //remap SDRAM
    wreg "R13 (SP)", 0xC0020048 //set SP
    wreg "R15 (PC)", 0x0001ABC1 //set PC
    go //run
    qc //close and quit

For reference, here is the .ini script of MDK, runs before each debug session.

FUNC void Setup (void) {  
    _WDWORD(0xE0042020, 0x00000003);  // Sdram mapping 0xC0000000 -> 0x00000000 
    SP = _RDWORD(0xC0010000);         // Setup Stack Pointer
    PC = _RDWORD(0xC0010004);         // Setup Program Counter 
}
LOAD %L INCREMENTAL    //load symbol file of *.axf (not relevant here)
Setup();

The catch :

Apparently with jlinkcommander script it is not possible to read a memory location and use the resulting datas to perform another action, in my case i would need to read the memory at 0xC0010000 and 0xC0010004 then write the resulting datas to SP and PC. https://wiki.segger.com/J-Link_Commander#Mem32 In my script i used hardcoded values, to confirm it works, but this is not an option because each time the firmware is modified SP and PC will also change. THere is another style of Jlink script, C like, where we can find a weakly declared callback HandleAfterFlashProg that we can implement . This style of script we can store datas in variables. https://wiki.segger.com/J-Link_script_files

https://github.com/search?q=HandleAfterFlashProg%28%29&type=code

Sadly with this script we cannot write CPU registers. At least according to a reply of Segger on their forum. So it looks like i am stuck, none of the two Jlink script style can perform the two operations together, one can write CPU regisrer but not use variables. The other can use variable but not write CPU registers, i dont quite understand why.

What seems weird to me is that the MDK .ini script, which in the end just controls the Jlink, does exactly that, it reads the memory at 0xC0010000 and 0xC0010004then set PC and SP with the resulting datas, all via the Jlink. So i must be missing something very fundamental.

Does anyone have an idea on how i could do this? My current script works fine but can only use hardcoded value for SP and PC, and therefore is not usable.

0

There are 0 answers