10 years, 6 months ago.

IAP on MBED

I am trying to use IAP (in application programming) to copy the code of a function from one point in memory space to another (I know this doesn't have any use, but this is absolutely crucial for a project that I'm working on). The copying of the code seems to work with out a hitch, but when I call the copied function it always results in hardfaults. The function I'm copying doesn't have any references to other functions or data (It is a simple return function), so there is no problem of relative address errors. I've given my code below along with the output that I get.

include the mbed library with this snippet

#include "mbed.h"
#include "IAP.h"

#define TARGET_SECTOR       14


char code[1024];
IAP     iap;
char val = 0;


typedef int (*function) ();
function blinkfunction;

MPU_Type mpu;


extern "C"
void HardFault_Handler() {
    register unsigned int _msp __asm("msp");
    printf("Hard Fault! %x (%x)\r\n", SCB->HFSR, *((unsigned int *)(_msp + 24)));
    printf("HFSR: 0x%X\n\r", SCB->HFSR);
    printf("MMFAR: 0x%X\tMMFSR: 0x%X\n\r", SCB->MMFAR, SCB->CFSR);
    printf("BFAR: 0x%X\tBFSR: 0x%X\n\r", SCB->BFAR, SCB->CFSR);
    printf(" - %x\r\n", (*(volatile uint32_t*)0xe000ed24));
//    printf("Hard Fault! %x\r\n", SCB->HFSR);

		printf("*********** MPU Settings *************\n\r");
		printf("TYPE: 0x%X\n\r", mpu.TYPE);
		printf("CTRL: 0x%X\n\r", mpu.CTRL);
    exit(-1);
}




int blink() {
    int a = 1, b = 1;
	return a + b;
}



void copy_code_ram() {
    
    char *charptr;
    
    charptr = (char *)&blink;
    int i;
    for(i = 0; i <200 ; i++) {
        code[i] = *charptr;
        charptr++;
    }
}    



void print_function(char *ptr, int num) {
    for(; num > 0; num--) {
        printf("0x%X  ", *ptr);
        ptr++;
    }
}
        

int main() {
    int r;
    
    printf("blink code:\n");
    print_function((char *)&blink, 100);
    

    printf("\n\r");
    copy_code_ram();
		
	//Print sector 	
    print_function(sector_start_adress[TARGET_SECTOR], 100);
    printf("\n\r");
		
	iap.prepare( TARGET_SECTOR, TARGET_SECTOR);
	iap.erase (TARGET_SECTOR, TARGET_SECTOR);
    iap.prepare( TARGET_SECTOR, TARGET_SECTOR);
    r   = iap.write( code, sector_start_adress[TARGET_SECTOR], 256);
    
    printf("\n\r");
    printf( "copied: SRAM(0x%08X)->Flash(0x%08X) for %d bytes. (result=0x%08X)\r\n", code, sector_start_adress[ TARGET_SECTOR ], 1024, r );
    printf("\n\r");
    
    blinkfunction = (function) (sector_start_adress[TARGET_SECTOR]);

    printf("\n\r");
    		
	r = 0;
	r = blink();
	printf("The return value from blink is %d\n\r", r);
	
    r = blinkfunction();
	printf("The return value from blinkfunction is %d\n\r", r);
	
    while(1) {
       

    }
}

Here is the output that I get:

Hard Fault! 4000000 (e000) HFSR: 0x400000000 MMFAR: 0xE000ED34 MMFSR: 0x20000 BFAR: 0xE000ED38 BFSR: 0x20000

I think I'm doing something wrong in calling the function. Can someone please point out my mistake?

Thanks

1 Answer

10 years, 6 months ago.

You could try setting the least significant bit of the function pointer to 1, telling the CPU that the function being called is to be executed in Thumb mode and not ARM mode. Without this bit set, a Cortex-M processor would generate a Usage Fault such as the one that you appear to have received here when you try to call blinkfunction().

I think changing the line of code which sets the function pointer to the following might help:

    blinkfunction = (function) (sector_start_adress[TARGET_SECTOR] | 1);

Accepted Answer