Bootloader code copy causing hard fault

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to implement a bootloader in my SAME70 project.  It's rather simple in that the application code reads in serial port data and writes the .hex code to an unused part of flash.  Then it jumps to a function shown here which is located at a reserved location which is never erased to copy byte for byte the application from that part of flash to the application area.  Here is the address map:

0-application

0x20000 - this code to erase the application then copy the bytes.  This is not erased

0x40000 - area in flash where the code to be copied is located.

 

This code first erases the application code located between 0 and 0x20000, using this routine.  Note that all the code in this section is function call free and should never jump from the 0x20000 area of code.

__disable_irq(); //disable the global interrupts so we don't get called off to the code that is being erased, we MUST stay in this routine
uint32_t edestaddress=0x0000; //starting address of the app area of flash
uint32_t page_nums=16;
//turn off the interrupt and test that it's off
((Efc *)device->hw)->EEFC_FMR &= 0xfffffffe; //ken test disable the operation complete interrupt
test=((Efc *)device->hw)->EEFC_FMR; //and test if the flag really is reset
while((test & 0x00000001) == 1); //wait if the flag is still 1

for(x=0;x<16;x++) //erase up to location 20000 which is where this flashloop is located.  each erase is 16x512=8192 so loop 16 times

	{
	page     = (edestaddress / CONF_FLASH_PAGE_SIZE);
	// Erase by 16 pages
	while (! ((((Efc *)device->hw)->EEFC_FSR & EEFC_FSR_FRDY) > 0)   ) {}	// Wait for EFC ready to start a new command
	EFC_CRITICAL_SECTION_ENTER();
	((Efc *)device->hw)->EEFC_FCR = EEFC_FCR_FCMD_EPA | EEFC_FCR_FARG(page | 0x02) | EEFC_FCR_FKEY_PASSWD;
	EFC_CRITICAL_SECTION_LEAVE();
	while( (((Efc *)device->hw)->EEFC_FSR & 0x0000001) == 0); //wait until flag goes to 1
	edestaddress+=8192;  //next block to erase
	}

One thing to note is that if I set the start address for erase to 0x6000 (my code ends around 0x1b000) it works, but won't work if I start erase at 0x4000 or below

Next, I copy the app from location 0x40000 to 0x0000 a byte at a time.  I have verified that the flash at 0x0000 is getting erased and that the data at location 0x40000 is valid

 

The code is a bit cryptic, but what I did was do a copy and paste of the efc function calls (such as flash_read() and flash_write()) so all the code would be in the 0x40000 code space

For this test, the code in the buffer (0x40000) is identical to the code in the app area (0x0000) which is why I can do an erase from 0x6000 onward and when I do a reset it still works.  But if

I start my erase at 0x4000, then I go to a hard fault interrupt where we hang.

 

I'm guessing that the code is getting interrupted (although I turn off global interrupt) during a copy or erase causing it to go to bad flash, or doing some other kind of reference in the erased area, but if I do a single step it seems to stay above 0x20000 where this bootloader is.

 

One other thing is that it gets farther in the code if I single step it (although the loops are too big to single step forever) but if I just run it, it goes to the hard fault interrupt.

 

Thanks

for(x=0;x<256;x++) //copy 256 blocks of 512 bytes
	{	

	// Check if the address is valid 

	if ((srcaddress > PAGE_SIZE * TOTAL_PAGES) || (srcaddress + PAGE_SIZE > PAGE_SIZE * TOTAL_PAGES)) {
		while(1); //error if here
		}

   char *csrc = (char *)(srcaddress + IFLASH_ADDR);
   // Copy a page of image to buffer
   for (int i=0; i<PAGE_SIZE; i++)
       databuffer[i] = csrc[i];

	/* Check if the address is valid */
	if ((destaddress > PAGE_SIZE * TOTAL_PAGES) || (destaddress + PAGE_SIZE > PAGE_SIZE * TOTAL_PAGES)) {
		while(1); //bad address
		}
	uint32_t addr;
	for (addr = destaddress; addr < destaddress + PAGE_SIZE; addr += IFLASH_PAGE_SIZE) {
		uint32_t i;
		page=_efc_page(addr);
		while (! ((((Efc *)device->hw)->EEFC_FSR & EEFC_FSR_FRDY) > 0))
			{
			/* Wait for EFC ready to start a new command */
			}

		for (i = 0; i < IFLASH_PAGE_SIZE; i += 4) {
			*((uint32_t *)(IFLASH_ADDR + (page * EFC_PAGE_SIZE) + i)) = *((uint32_t *)(databuffer + i));
			}

		__DSB();
		__DMB();

		/* Erase and write page */
		EFC_CRITICAL_SECTION_ENTER();
		((Efc *)device->hw)->EEFC_FCR = ((false) ? EEFC_FCR_FCMD_EWP : EEFC_FCR_FCMD_WP) | EEFC_FCR_FARG(page) | EEFC_FCR_FKEY_PASSWD;
		EFC_CRITICAL_SECTION_LEAVE();

		}	

	srcaddress+=PAGE_SIZE; //increment the source and dest addressses by the page size and continue
	destaddress+=PAGE_SIZE;
	}

NVIC_SystemReset(); //this should now take us to a normal operation
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

NOW WORKING.  I don't know exactly what I changed, but the code is the same as above and everything now works.  It seems to be reliable and never fails to transfer the data from the buffer to the app area.  So I'm happy.