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

前端 未结 4 1266
半阙折子戏
半阙折子戏 2021-01-02 17:32

I\'m trying to execute a function from RAM on a Cortex-M3 processor (STM32). The function erases the and rewrites the internal flash, so i definitely needs to be in RAM but

4条回答
  •  一向
    一向 (楼主)
    2021-01-02 17:41

    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].

提交回复
热议问题