microcontrollers required that the internal flash memory should not be accessed while Erasing/Writing to the flash memory pages.
If the flash memory is accessed during the erase or write operations then the operation fails due to violation or access error. So Once you execute a flash erase or write command you need to wait for the operation to complete by checking a flag which indicates the status or command execution. This flag checking code needs to be placed in RAM and run from there without accessing the flash memory. To do this we will declare a buffer of 100 bytes on Stack and copy the flag checking code to that buffer and run the code from there.
// This type is used to declare variables of size of flash location.
// This is the size of one memory location of flash, its a 8 bit flash so using unsigned char
typedef unsigned char FlashDataType;
// This type is used to declare variables of size of flash address, Memory address is 16 bits so using unsigned short
typedef unsigned short FlashAddressType;
// Declare a function pointer which takes no arguments and returns a unsigned char value
typedef unsigned char (*pFuncType)(void);
// This function RamCode is the one which is to be copied to the stack and run. Its better to write the RAM code in assembly to avoid jump instructions that use absolute addressing. If you use C code then we dont know whether the compiler has used absolute addressing or relative addressing for loops or branching statements. However in new generation compilers options exist to enforce relative addressing for loops and branching insructions.
// Code that runs on the Stack.
unsigned char RamCode(void)
{
asm
{
//your assembly code here
}// asm end
return 1; // Return a value
}
// Dummy function to determine the function end. While copying the code we need to know from where to where we are copying the code, So this RamCodeEnd() is used to determine the end of RamCode.
void RamCodeEnd()
{
unsigned char i=0; i++;
}
// Buffer of 100 bytes in which the code is copied and run. This buffer can be allocated on the stack or heap, here its assumed to be allocated on stack
FlashDataType Buffer[RAM_CODE_SIZE];
// A function pointer that points to code that runs on Stack.
pFuncType pFunc;
// The below statements determine the size of the function in bytes by assuming that the RamCodeEnd function is allocated right after the RamCode. As an alternative we can use FunctionSize=sizeof(RamCode);
FunctionSize=( ((FlashAddressType) RamCodeEnd) – ( (FlashAddressType) RamCode) );
// Loop until the end of the function code.
for(Index=0;Index<=FunctionSize;Index++)
{
// Copy code to Buffer which is allocated on Stack /RAM
Buffer[Index] = *(( (FlashDataType*) ( ((FlashAddressType)RamCode )+Index)) );
}
// Set function pointer to point to the buffer which holds the code to be run on Stack.
pFunc=(pFuncType)(void*)&Buffer[0];
// Calling the RAM code
if((*pFunc)() == FAILURE)
{
// Handle return values here
}
This example is for microcontrollers which use Von-Neumann architecture where in the same address space is divided between Data memory and Code memory or RAM and Flash