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

copying code to ram and executing it

Hello,

I am using Keil uVision 5.15 compiler. copying a routine to ram(FLASH_eraseOneBlock) and try to runit,
the code crashes (hardware Fault). I have looked at Keil's ram function example and it does not
work either. my code is:

typedef void (*FunctionPointer_t)(uint32_t );
FunctionPointer_t ramFunc;
uint32_t executableRam[100];

void TxfrToRam(void)
{
    uint32_t source,source_end;
    uint32_t *dest,addr;

    source = (uint32_t)&FLASH_eraseOneBlock;
    source_end = (uint32_t)source + 80;
    dest = (uint32_t *)executableRam;
    ramFunc = (FunctionPointer_t)dest;
    while (source < source_end)
    {
        *dest++ = *(uint32_t *)source++;
    }
    for (addr = 0x2000; addr < 0x20000; addr += FLASH_PAGE_SIZE)
    {
        ramFunc(addr);
    }
}

Any help will be highly appreciated.

Thanks

Yash

  • Further update: I have verified that the code is copied correctly. It goes to the correct
    location. The disassembly shows it is correct code. The very first instruction in ram causes
    hard fault.
    When I copy the code The address in the variable is one more than the actual code, though
    I have corrected it. May be bit 0 of pc has a special meaning. Please help.
    Thanks
    Yash

  • community.nxp.com/.../113048

    It uses the address of the destination to determine what instruction mode it jumps into. An even instruction address changes the instruction mode to ARM 7. An odd instruction address keeps the processor in Thumb mode.

  • The least significant bit of target code addresses tells the processor if it is jumping to code using 32-bit ARM instructions or 16-bit thumb instructions. So if you get this bit wrong your code will fail badly.

  • Your post lacks specificity, but if this is a Cortex-Mx processor it isn't going to be able to run code at EVEN addresses, so the copy and jump will both be broken in your example.

    This method has been demonstrated on a Cortex-Mx system

    int TestFunc(void)
    {
      return(123);
    }
    
    #define FUNC_SIZE 64
    
    typedef int (*pFunction)(void);
    
    int RamFunc(void)
    {
      uint8_t Buffer[FUNC_SIZE];
      pFunction RunFunc;
    
      memcpy(Buffer, (void *)((uint32_t)&TestFunc & ~1), FUNC_SIZE); // Copy code
    
      RunFunc = (pFunction)&Buffer[1]; // +1 for Thumb code
    
      return(RunFunc()); // sourcer32@gmail.com
    }
    

    Calling external functions, even ones inserted by the compiler to do basic math, will cause headaches, and you need to catch all the function code and the literal pool it uses.

  • "copying a routine to ram(FLASH_eraseOneBlock) and try to runit"

    _You_ shouldn't copy the code into RAM. The linker script already supports producing a binary that will link the function for use in RAM and that will automatically copy the function into RAM on startup. This will make sure that any references to the function and any references from the function will be properly adjusted - that's not something you can manage yourself unless you have waaaaay too much spare time.

  • Thanks everybody. I had multiple problems. The thumb mode was one of them. I was not able to get the linker script to automatically copy the code to ram, but my simple copy worked fine. Also I had timer interrupt enabled (in FLASH) which was also causing crash. step by step debugging always worked. Any way now those problems are solved. Thanks
    Yash

  • Note that the scatter file specifies two addresses for al regions.

    One address range where to store the variables/code in flash.
    One address range where to run the variables/code.

    So the linker can link a function to store in flash, but with addresses adjusted for running in RAM. That's the officially sanctioned way of getting correct binary code for use in RAM.