How do I execute a function from RAM on a Cortex-M3 (STM32)?

浪尽此生 提交于 2019-11-30 13:53:20

The crash upon loop iteration is probably because the function is branching to an absolute address and is not relative to the new function location in RAM. Would accessing the original code location at that point cause a bus error because of the flash erase operation?

I believe you can mark a function to be compiled and copied to RAM correctly with CARM by appending the __ram directive to the function definition. For instruction on how to do the same with the RealView compiler see the EXECUTING FUNCTIONS IN RAM technical support article:

µVision allows you to locate modules to specific memory areas that are entered in the dialog Project - Options - Target. To do so, right click on a source file (or file group) and open the dialog Options - Properties. Then select the memory regions under Memory Assignment.

There is an example in the folder ARMExamplesRAM_Function.

That should generate startup code to take care of copying the function to RAM and linking calls to that location correctly. Otherwise, if you need to dynamically copy arbitrary functions to RAM, then look into compiling position independent code (PIC) with RealView.

Without knowing more about your situation I can only suggest a few general things... make sure you have a valid stack for that function (or avoid all stack operations in the function), that your interrupts are disabled, and that any vectors in the system vector table don't point to code that goes away when you erase flash. Lastly, make sure your function is linked to run at the address you put it... the code may not be relocatable and may jump to a spot in is old location.

Because the ARM has a limited ability to load immediate data, utilities which generate code for the ARM frequently juxtapose code and data. For example, a statement like

void myRoutine(void)
{
  myVar1=0x12345678;
  myVar2=0x87654321;
}

might end up as something like:

myRoutine:        
    ldr r0,=myVar1; Load the address of _myVar
    ldr r1,=0x12345678
    str r1,[r0]
    ldr r0,=myVar1; Load the address of _myVar
    ldr r1,=0x87654321
    str r1,[r0]
    bx  lr

which would get translated into:
    ldr r0,dat1
    ldr r1,dat2
    str r1,[r0]
    ldr r0,dat3
    ldr r1,dat4
    str r1,[r0]
    bx  lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678

or perhaps even something like:
    mar  r0,dat1
    ldrm r0,[r1,r2,r3,r4]
    str r2,[r1]
    str r4,[r3]
    bx  lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678

Note that _myVar and 0x12345678 may be placed immediately following the code for the routine in which they appear; if you try to determine the length of the routine using a label which follows the last instruction, such length will fail to include the supplemental data.

An additional thing to note with the ARM is that for historical reasons, code addresses will often have their least significant bit set even though code actually starts on half-word boundaries. Thus, an instruction whose address is 0x12345679 will occupy either two or four bytes starting at 0x12345678. This can complicate address calculation for things like memcpy.

My recommendation would be to write a small routine in assembly language to do what you need. It's only a few instructions, you can know exactly what the code is doing and what address dependencies it might have, and you won't have to worry about future compiler versions changing your code in such a fashion as to break something [e.g. the third version of the above code would have no problem even if dat1 landed on an odd halfword boundary since the M3's LDR instruction can handle unaligned reads, but the fourth (slightly faster and more compact) version using LDRM would fail in such a case; even if today's version of a compiler uses four LDR instructions, a future version might use LDRM].

With the IAR compiler (I know your question is about Keil but I don't have it to play with) you can mark either the whole project or an individual file to be "position independent". From using this in the past with other processors it means you can move it "anywhere" and it will still work ok

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!