This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC1768 copy function code for flash to RAM

I use the LPC1768 board and I want to copy a function from flash to RAM in runtime. I use the following code

void f()
{ int x=0; printf("%d\n",x);
} void g()
{ int x=5; printf("Hello: g"); printf("%d\n",x);
} int main(void)
{ char c; static void (*fnRAM_code)(void) = &f; int offset= (int)((long)g-(long)f); int i=0; int z=0; int *x; extern void uart0_init(void); unsigned char *pCodeStart = (unsigned char *)f;

uart0_init();

//(*fnRAM_code)();

//thump2 addresss /* Thumb 2 address */ pCodeStart = (unsigned char *)(((unsigned int)pCodeStart) & ~0x1); while (i < PROG_SIZE) { ProgRamSpace[i] = pCodeStart[i]; i++;

} (*fnRAM_code)(); fnRAM_code = (void(*)(void))(ProgRamSpace); (*fnRAM_code)();
}


But when I access the new address of the function I get the following error access violation at 0x100000018: no execute /read permision. Can anyone provide a solution for this issue

Best regards,
George

The scatter file is the following
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x00000000 0x00080000 { ; load region size_region ER_IROM1 0x00000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x10000000 0x00008000 { ; RW data .ANY (+RW +ZI) } }

  • It's real hard to determine the size of a compiled function and it's literal pool, or the relative position to branch to external subroutines, etc.

    Thumb code needs to be copied to 16-bit half-word address, but execution will be at an ODD address, nominally the base address you copied to plus one.

    The RAM may, or may not, permit execution, don't know about NXP/LPC, but others fault at 0x10000000, but work at 0x20000000

    Try a little assembler code fragment that sets R0 with a value and returns, and print the result from that.

  • Thank you for the prompt reply,
    Yes I know that is very hard and maybe does not work in this way. For this reason I have an really small f function.
    Then, I have already checked the instructions that are saved in the ProgRamSpace and seems to be correct. The problem as I explain above is that the function can not execute in this memory space Your point is to allocate the ProgRamSpace in the address 0x20000000, is this?
    Thank you
    George

  • I have already check this in address 0x20000000 and does not works. When access the function pointer that indicates to the buffer, that are saved the instructions a HardFault exception is triggered
    The scatter file
    LR_IROM1 0x00000000 0x00080000 { ; load region size_region ER_IROM1 0x00000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00008000 { ; RW data .ANY (+RW +ZI) }
    } George

  • As I said, I know very little about the NXP/LPC part, would have to research addresses and if core design permits execution from RAM, or requires remapping, so more generically

    #include <stdio.h>
    #include <string.h>
    
    typedef int (*pFunction)(void);
    
    void ExecuteFromRAM(void)
    {
        static const uint16_t CodeStart[] = { 0xF04F, 0x007B, 0x4770 }; // function, in ROM
        uint8_t ProgRamSpace[16]; // as big as required, here on stack
        pFunction fnRAM_code;
    
        memcpy(ProgRamSpace, CodeStart, sizeof(CodeStart)); // Copy code
    
        fnRAM_code = (pFunction)&ProgRamSpace[1]; // +1 for Thumb code
    
        printf("%d\n",fnRAM_code());
    }
    

  • Why not let the linker place the function in RAM? Then the startup code will perform the copy of the code from flash into RAM and all references to that function will make use of the RAM address.

    The datasheet for the processor contains information which memory regions that supports code execution, DMA transfers etc.

  • Clearly there are many solutions to the problem, but the problem is multifaceted and one really has to understand the requirements and ramification very precisely.

    If you start calling functions, or libraries from RAM based code you need to make sure everything in the call tree is brought there too, if the goal is to modify or erase flash, or other things that would preclude running from flash, or would cause significant stalling of execution.

    IAR has a directive like 'ramfunc' in Keil I think you need to use attributes, sections and scatter files, I've made that work in the past too, but don't have my example to hand.

  • If reprogramming a flash, then it's often best to create a self-contained piece of assembler code to run in RAM to make really sure there aren't any hidden helper functions that gets referenced from flash.

    But if the goal is to use RAM for additional speed, like critical ISR or evaluation code, then it works well to just make use of the scatter file.

  • Here I put a whole object file in RAM, but you can do so on a section or function basis also.
    http://www.keil.com/forum/24821/

  • Hello,
    Thanks for the sample.
    It is very useful
    George

  • Hello,

    Regarding to the above problem (LPC1768 copy function code for flash to RAM). The Hard fault exception takes place because of the INVPC bit in usageFault Register is 1. I can not understand why this happens. The first instruction in the f function that is allocated in the flash is the same with the instruction that is allocated in RAM after copy.
    Could you please provide a solution
    Best regards
    George

  • But what instructions have you copied?

    Does the function use absolute or relative addresses when accessing other functions or data? It isn't so trivial to just move a function to a different address - which is the reason why it's nice to have the linker link the function for use in RAM but with an initial copy stored in flash. Then you know that the RAM function makes correct accesses to all other symbols it needs access to.

  • Hello,
    The function use use absolute addresses, I think. The only that do is a simple add.

    Have look below :
    I have this simple function that I copy
    void f()
    { int x=5; int y=5; int a=x+5;
    } I use this code to copy
    void copyToRam()
    {

    static void (*fnRAM_code)(void) = f;

    unsigned char *pCodeStart = (unsigned char *)f;
    f(); // f is allocated in flash

    //thump2 addresss
    pCodeStart = (unsigned char *)(((unsigned int)pCodeStart) & ~0x1);

    //copy all the instructions of the f function in buffer that is allocated in RAM
    memcpy((char*)ProgRamSpace,pCodeStart,sizeof(ProgRamSpace));

    //create a thumb-2 call
    fnRAM_code = (void(*)(void))(&ProgRamSpace[1]);//The last significant of PC should be 1

    /create a call
    (*fnRAM_code)();

    }

    The first issue when I executed the code is that there are not read/execute rights in the region that the ProgRamSpace is allocated. But in memory map seems that this region has execute rights.

    The other is issue is that INVPC has value 1.

    But the instructions in the RAM and ROM are the same.

    - which is the reason why it's nice to have the linker link the function for use in RAM but with an initial copy stored in flash

    I can not understand what you mean. If I copy the function, the if I load the instruction should execute, should it?

    Best regards
    George

  • When placing functions in RAM using the scatter file, you can get the linker to store the function code in the flash similar to initial data values. But the linker links the function will all references as if the code is in RAM. So any part of the program that wants to call the function will make jumps into RAM. And the startup code can keep track of how large the function is and perform the copy from flash to RAM.

    Have you verified the individual assembler instructions to make sure that your memcpy() really will place a complete and correct function into RAM? The error indicates that you either land at the wrong address, or that there isn't correct code in the RAM. Or that you are copying to a RAM region that doesn't support program execution.

  • Hello,
    I understood your point. I was not right before. The INVSTATE bit is 1 not INVPC.
    Thank you
    George

  • Hello,
    Regarding the Hard Fault exception. This took place because of the LSP of PC was 0. I fixed this . And now the only issue that I have is with the permision writes.
    I went throught the datasheet of LPC1768 and I noticed that the region 0x10004000 has exec rights.
    The program counter has LSB 1.
    I attached the scatter file again
    LR_IROM1 0x00000000 0x00080000 { ; load region size_region ER_IROM1 0x00000000 0x00080000 { ; load address = execution address *.o(RESET, +First) *(InRoot$$Sections) *.o(+RO) } RW_IRAM1 0x10000000 0x00004000 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x10004000 0x00002000 { ; RW data *(section)

    }

    Regarding the scatter file the following memory mapping is generated for the variable ProgramRamToSpace

    Execution Region RW_IRAM2 (Base: 0x10004000, Size: 0x00000040, Max: 0x00002000, ABSOLUTE)

    Base Addr Size Type Attr Idx E Section Name Object

    0x10004000 0x00000040 Data RW 137 section copytoram.o.

    This variable includes function instructions. But its type is Data. Can i mark in someway this variable as thumb code type as the functions that are allocated in ROM. I read carefully your previous post and I think that the corrects instructions are saved in the buffer and the initial address of the function in the RAM is correct.

    Thank you for your time

    Best regards
    George