November 22, 2011 - 11:33pm
Guest |
I want to write procedure that upgrades code in internal flash (gcc Ride-7 enviroment). It will be full upgrade of flash with executing mass erase command, so I should copy upgrade procedure to ram, execute it from ram and upgrade program.
And I have questions:
1. when I copying function to RAM, i copying data from flash address to ram address, but how detect size of function (it will not be only one function but more functions, so I want collect them...)
2. how to execute program from RAm after copy ? simple jump ?
3. how tell the linker to locate pocedures in flash at specified address ? (I want them to be inside first page of flash)
4. how tell the linker to locate some constants at special flash address ? (for veryfing flash contents)
with best regards,
|
Hi,
1) You can use the map file to retrieve the functions sizes.
2) A simple jump will be fine. Ensure that your routine does not return (either a software reset or a while(1) will be ok)
3) You can locate functions at absolute addresses using a specific segment name. You can refer to this older thread for detail: http://forum.raisonance.com/viewtopic.php?id=3216
4) Same as 3)
Good Luck & Enjoy!
Hello once again
I tried to copy procedure from flash to ram by simply
memcpy(...)
but when I look at ram where procedure was coppied ,first byte of copied procedure has disapeared. Executing from this point of course doesnt work.
Why is it so ?
with best regards
Hi,
I have no idea, but I suspect that either your memcpy is not properly written (incorrect address) or that the first byte is overwritten by another variable.
Try to move your destination block 4 bytes higher in RAM, and check if the first byte is still corrupted. If it is, the memcpy is not correctly called. If the first byte is OK, then you have not properly read your map file.
BR
Hi,
This is probably a problem in your way of passing the parameters to memcpy:
Keep in mind that in Cortex, code is aligned on 0x02 boundaries. But when you jump to or call a function, the lowest bit is used to indicate that this is thumb code not ARM code. This is a remains from the ARM7/ARM9 architecture.
Therefore, if for example your function's code starts at address x24, then when you call it you will call address 0x25. But the byte at address x24 is part of the function and required for operating.
Now depending on the syntax you use to give the function's address to memcpy, you might end up copying from the second byte (x25) not the first. (x24) Therefore you miss one byte and all the rest is misaligned.
In your case, AND-ing the functions addresses with xFFFFFFFE might be a way of doing it. (round the size up too, and check that the last byte is also copied) Or maybe you just use a bad syntax for retreiving the function's address...?
Finally, you must also make sure that your function's code is either compiled as relocatable (which will make it bigger) or linked for executing at the specific RAM address at which you will copy it before executing it. (which will require some linker script and options manipulations, and force you to determine in advance (at or before link time) the address it will execute at) By default the generated code cannot be executed if it is not located at the place it was linked for.
Best Regards,
Vincent
Thats right. My code is:
//-------------------
unsigned char RamBuffer[1200]; // buffer in RAM and place for function from flash
//---------------------
void UPG_FunctionUpgrade(void) // function to be copied and executed from RAM
{
(...)
}
//--------------
void ExeFromRam(void) // copying and executing function from RAM
{
void (*inramfunction) (void); // pointer to function
memcpy(RamBuffer,UPG_FunctionUpgrade,1024); // copying code
inramfunction=RamBuffer;
inramfunction(); // executing code from ram
}
//---------------
and exactly after copy, code in ram is missalligned by one byte and first byte of function is missing.
Could you please give me some king of example how to change linker script to compile function to be execuded at specific ram or flash address ?
with best regards
See files main.c and ramfunc.c this example:
\examples\ARM\REva\REvaTest
You don't have to determine the address of the ram function explicitly. You can let the linker do it.
But it has to be determined at link time (at the latest) and you cannot for example put it in the stack or heap.
And you cannot execute it sometimes from flash and sometimes from RAM.
Great thanks! For the first step, compiling function to executed from RAM is super. Is it nessesary to set "Generate long calls" in GCC comliller options to YES globally (it increases size of program), or is it possible to do it only for this function ?
But one more question: how exactly tell the linker to locate some constants at special flash address ? (for veryfing flash contents)
for instance:
const char VersionInfo[4]="1.2"; // I want it this constant to be placed for instance at 0x08003450 memory address
Can it be done by linker script ? I have tried look into linker scripts but ... it is not clear for me how to do that. Someone could help me with this ?
with best regards
Hi,
I think the "generate long calls" options only must really be activated for the Flash functions that _call_ RAM functions and vice-versa. i.e. when you call from one region to another. (in fact, when the difference between the addresses of the calling and called functions is larger than a certain distance)
Placing data at absolute addresses can indeed be done by modifying the linker script, and in fact modifying the linker script is the only way tp do it. I suggest you look at the CircleOS (and its applications) source code for examples of how to do that. (declare memory regions, assign sections to these regions, etc.) There are also a number of posts on this forum discussing this. I suggest you search it.
I hope it helps.
Best Regards,
Vincent