Hi again
I am still struggling with debugging my code in DDR3 memory using the Keil uLink2. I have created a .ini file for the uLink2 to execute which initializes the DDR3 for use, load my code to DDR3, and attempts to change the pc and sp to that memory. The last thing is not working. the code definitely is in the DDR3 memory OK. Below is the the script function.
The code was linked to 0xA0000000
This is a microsemi cortex m3 FPGA arm.
Can anyone see a reason why this would not work? or why the uLink2 jumps away to undefined memory space? I assume people have debugged out of external RAM before
Thanks :-)
FUNC void SetupPC_SP (void) { // Stack pointer and vector table offset // registers are set to 0x00000000 // Setup Stack Pointer SP = _RDWORD(0xA0000000); // Setup Stack Pointer // Program Counter is set to (0x00000004 -1) PC = _RDWORD(0xA0000004-1); // Setup Program Counter // change vector table address to 0 _WDWORD(0xE000ED08, 0x0); // 0xE000ED08 SCB->VTOR = readonly_region_base; }
Well the initial PC is definitely not at 0xA0000003, and you don't need to subtract or add one to the value stored there. It should be ODD because it points to 16-bit THUMB code.
You might also want the SP to point to the top of internal SRAM
I saw that in an example. I questioned that as well. I have tried it both ways and the PC is still not being set to the value I tell to to be.
I wanted the stack to be in the ddr memory because the ddr memory will be remapped to address 0 in the nondebug version. The plan is to have a bootloader copy the code from external flash to ddr memory. That code will be linked at address 0 because the bootloader as its last action will remap the ddr memory to address 0.
For debugging though I am not doing remapping and loading the code with the uLink2 and not a bootloader. So the code is linked at address 0xA00000000 (ddr). The heap and the stack will follow the code.
I problem I am having is why does the script (I posted) unable to modify the PC and SP registers?
Is the function being called? What you posted seems incomplete.
You'd really want the stack in the lowest latency memory available, this would be memory significantly more tightly coupled than the DDR
Another working M3 script (complete)
/******************************************************************************/ /* RAM.INI: RAM Initialization File */ /******************************************************************************/ /* This file is part of the uVision/ARM development tools. */ /* Copyright (c) 2005-2010 Keil Software. All rights reserved. */ /* This software may only be used under the terms of a valid, current, */ /* end user licence from KEIL for a compatible version of KEIL software */ /* development tools. Nothing else gives you the right to use this software. */ /******************************************************************************/ FUNC void Setup (void) { SP = _RDWORD(0x20000000); // Setup Stack Pointer PC = _RDWORD(0x20000004); // Setup Program Counter _WDWORD(0xE000ED08, 0x20000000); // Setup Vector Table Offset Register } LOAD %L INCREMENTAL // load the application Setup(); // Setup for Running g, main
Be sure to also uncheck "Load Application at Startup" and "Update Target before Debugging"
Make sure you don't have any code in SystemInit() that will trash the memory configuration you created in the .INI file.
I am sorry for getting back to your post so late. I had to support the hardware group in getting their board up and running.
I did implement your suggestion but it does not have any affect on the new Microsemi cortex M3 ARM. I just don't understand why not.
I have asked Microsemi to figure out why remapping the DDR to address 0 does not work. They are very slow to respond and most times do not give me answer to I need to proceed with plan B which is to get the Kiel uVision compiler to link my code at address 0xA0000000 and for the uLink emulator to load and execute the code in the DDR.
I can created an image that in entirely in DDR and it will load without error when I start the debugger. The MSP and SP registers are correct at 0x20003000 but the PC register is not set to the entry point in the code (0xA0000188) but to 0x0000076A in the nvm. When I force the PC register to the correct value, the disassembled code appears (main) and is corrected. If I do a disassembly step from there instead of going to instruction 0xA0000190 (scatterload) it jumps to nvm at address 0x0000006D0.
I don’t know if there is something other than the PC that needs to be set or not. Everything I have read says No. The PC, SP and vector table base are the only things that need to be changed as you noted in your reply.
What needs to be done to make the uLink2 emulator it work?
Steve
I cannot post the entire script because it is too long. The initialization of the DD From the startup.ini script (the DDR initialization seems to be working)
FUNC void RemapDDR (void) { //-------------------------------------------------------------------------- // Remap MDDR to address 0x00000000. // _SYSREG_BASE = 0x40038000; _WDWORD(0x40038000, 0x0); // SYSREG->ESRAM_CR = 0u; // 0x40038000u + 0 _WDWORD(0x40038010, 0x0); // SYSREG->ENVM_REMAP_BASE_CR = 0u; // 0x40038000u + 0x10 _WDWORD(0x40038008, 0x1); // SYSREG->DDR_CR = 1u; // 0x40038000u + 8 // DDR_CR register is set for the enabling the // DDR memory address remap to Cortex M3 bottom address space } FUNC void SetupPC_SP (void) { SP = _RDWORD(0x20003000); // Setup Stack Pointer PC = _RDWORD(0xA0000004); // Setup Program Counter (+4) _WDWORD(0xE000ED08, 0xA0000000); // 0xE000ED08 SCB->VTOR = readonly_region_base; } InitDDR(); // initialize DDR so it can be accessed //RemapDDR(); // not working LOAD %L INCREMENTAL // Download SetupPC_SP(); // set PC/SP/vector table base address //g, main /*------------------------------------------------------------------- ** Execute upon software RESET **-----------------------------------------------------------------*/ FUNC void OnResetExec(void) { InitDDR(); // RemapDDR(); SetupPC_SP(); }
You understand what _RDWORD() does, right?
SP = _RDWORD(0x20003000); // Setup Stack Pointer
If you want to set the SP to 0x20003000
SP = 0x20003000;
Setting the code to built at 0xA0000000 should be a matter of configuring the GUI or scatter file. You might want to cross check that with the .MAP file, and disassembling the generated image.
Is there some potential for the core to execute some other code? What's initially mapped at zero?
I am new to ARM but it seemed to me to be a read command and I thought this was incorrect as well BUT I have seen it in many examples so for whatever reason I believed it was correct to use. I have no idea why it was posted this way in 3 or 4 different websites.
What you wrote seems correct to me and I will try it this morning.
Ok, I have tried this several different ways in the script file and nothing is written to either the PC or SP and the vct does not look right either
Is there some potential for the core to execute some other code? What's initially mapped at zero? I have a bootloader that is in nvm that copies my main code from a external flash into DDR memory starting at 0xA0000000. The map shows that all of the code is there and if I load it with the uLink2 I can see it in the memory window and it looks correct. vector table followed by my main.
What I am trying to do now is to debug the code in DDR using the uLink2. Kiel support told me to create a startup.ini script that is run before the debugger does anything that will initialize the DDR so it can be access, and set the PC/SP/vector base address to the start of DDR (0xA000000).
The init of DDR is working but I cannot get any of the registers to change. Also if I force the PC and SP registers to what I want them to be, the disassembly window shows me main with the proper instructions. If I do one assembly step it jumps to some address in nvm instead of the next address.
I don't understand why the uLink2/ARM is doing this if the PC is set correctly.
I need to debug my code in DDR because it is too big to fit into nvm.
FUNC void SetupPC_SP (void) { // Stack pointer and vector table offset // registers are set to 0x00000000 // Setup Stack Pointer WDWORD (SP, 0x20003000); // Setup Stack Pointer // Program Counter is set WDWORD (PC, 0xA0000004); // Setup Program Counter // change vector table address _WDWORD(0xE000ED08, 0xA0000000); // 0xE000ED08 SCB->VTOR = readonly_region_base; } OR FUNC void SetupPC_SP (void) { // Stack pointer and vector table offset // registers are set to 0x00000000 // Setup Stack Pointer SP = 0x20003000; // Setup Stack Pointer // Program Counter is set PC = 0xA0000004; // Setup Program Counter // change vector table address to 0 _WDWORD(0xE000ED08, 0xA0000000); // 0xE000ED08 SCB->VTOR = readonly_region_base; }
I finally believe I got DDR initialization, DDR remapping and the PC/SP working. I had to remove the FUNC's because the calls to them were getting errors that they did not exist. So I just have the entire startup.ini script execute from top to bottom and it works.
My DDR now shows up at address 0 which is pretty cool and the PC is getting the value I want.
But I am not out of the woods on this yet.
The last thing the script does is a LOAD command. The debugger does spend quite some time loading something big (big blue bar at bottom) but ends with a memory mismatch and exits.
What I found out is that the mismatch was between the value being loaded and what was in the DDR before remapping. The memory windows shows the proper value at address 0 but the LOAD command somehow match against the value address 0xA0000000 instead. That value should have been overwritten because it was remapped to address 0.
Its like the uLink2 was confused by the remap and wrote the code somewhere else but not at address 0.
Any ideas as to what might be going on with the LOAD command?
Hi
I have finally gotten to the point in my bootloader where I have loaded my code into the DDR from external Flash and need to remap and jump to the start address. Pre the Microsemi cortex M3 ARM app notes this is the order that the registers are to be set BUT once the remapping happens the two instructions to load the SP and PC registers cannot be executed because the memory is no longer there to fetch them. Its DDR.
Has anyone does this successfully somehow?
__asm void BootJump(INT32U firmwareStartAddress) { MOVS R1, #0x0 STR R1, [R0,#0x0] ; SYSREG->ESRAM_CR = 0u STR R1, [R0,#0x10] ; SYSREG->ENVM_REMAP_BASE_CR = 0u MOVS R2, #0x01 ; SYSREG->DDR_CR = 1u STR R2, [R0,#0x08] ; Remap DDR to address 0 LDR SP, [R1] ;Load new stack pointer address LDR PC, [R1, #4] ;Load new program counter address } void Jump_to_executable(void) { SCB->VTOR = 0x00000000; BootJump((INT32U)0x40038000); }
So is the boot loader in SRAM? Is it accessible from a shadow/normal address (0x20000000 ?) and is that currently mapped at ZERO? If it's at zero then you'd probably want to transfer control to the higher address code before you remap the memory underneath yourself.
View all questions in Keil forum