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.