I struggle to understand the way function pointers work in the code I'm working with.
The code describes the IAP (in-application programming) of Flash memory on the LPC1768 Microcontroller from NXP.
unsigned int flashParamTab[5];
unsigned int flashResultTab[5];
// IAP entry function
#define IAP_LOCATION 0x1FFF1FF1
// In Application Programming function entry
typedef void (*IAP)(unsigned int[], unsigned int[]);
IAP flashIapEntry = (IAP)IAP_LOCATION;
This code is than being used with in various functions, like these two:
// Prepare a sector for write operation.
void flashPrepareSectors(unsigned int startSec, unsigned int endSec){
flashParamTab[0] = IAP_PREPARE_WRITE;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
// Erase a sector.
void flashEraseSectors(unsigned int startSec, unsigned int endSec) {
flashParamTab[0] = IAP_ERASE_SECTORS;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
As far as I understand:
typedef void (*IAP)(unsigned int[], unsigned int[]);
defines an IAP datatype where IAP is a pointer to a function that takes two arrays of integers as arguments, and doesn't return anything.
In the next step the
IAP flashIapEntry = (IAP)IAP_LOCATION;
declares a variable flashIapEntry of type IAP, that is a pointer to a specific location in the memory, where code for a function that takes two arrays of integers is located.
I can't really figure out what happens when this function is called. In my opinion in both cases (when preparing and erasing a sector) the same function is called (the one located at 0x1fff1ff1), and the only difference is the first field of the array, the flashParamTab[0], that defines the behaviour of this function.
Am I correct with my understanding?
CodePudding user response:
Correct. As is also described in this NXP application note, in your example, flashIapEntry
becomes a pointer to a function that takes two integer arrays as parameters and returns void. This means you would call that function as you would any other function in C, like this:
flashIapEntry(flashParamTab, flashResultTab);
"I can't really figure out what happens when this function is called."
The parameters are pushed onto the stack, as is the current program execution location, and then the program execution pointer is set to 0x1FFF1FF1. The command to be executed by the IAP entry function (at 0x1FFF1FF1) is defined by the values you set in the flashParamTab
array, and whatever results this function produces are written to the flashResultTab
memory area. Finally the program execution location is set to the value saved on the stack and the stack pointer is reset, and program flow continues after the call to flashIapEntry()
allowing you to check the results in the flashResultTab
array.
CodePudding user response:
The IAP libraries on NXP controllers is hardcoded, ever-present source for a lib already inside the MCU upon delivery. This lib isn't linked so neither your compiler nor linker knows about it.
The IAP_LOCATION
memory address is the physical address where the function is located and NXP guarantees that it has a certain format and calling convention. In order to call that function, we need to use a function pointer since the actual function isn't available anywhere in our source.
You can do it a bit more readable like this (from an IAP driver I once wrote) :
typedef uint32_t iap_func_t (const uint32_t*, uint32_t*);
static iap_func_t* const iap_entry = (iap_func_t*) IAP_ADDRESS;
The const
keyword ensures that the function pointer gets stored in flash, so this is essentially just as if we had declared the function normally.
Then call the function with different parameters depending on what you want it to do.