Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf52832 simple FW updater

Hi everyone.
I've implemented kind of simple FW updater.
The purpose is to copy FW from flash (0x0 address, no MBR or SoftDevice) to RAM buffer on node1.
than send this FW to node2 by a couple of packets via ESB.
After receive all FW data, execute FW updater (copy received FW from RAM to 0x0 same address FLASH via RAM function).

Flash copy procedure is ok and works on writing to some other address (0x5000 for example).
But when I execute it on 0x0 address my device becomes bricked...

Here is the source code:

#define FW_FLASH_START			0x0
#define RAM_START	            0x20009000

//FW copy function type
typedef void (*update_fw_proc)(uint32_t dest, uint8_t *src, uint32_t size);

//FW copy function
void fw_copy_flash(uint32_t dest, uint8_t *src, uint32_t size)
{
		int i;
		int pagesNum = FW_DATA_MAX_SIZE / NRF_FICR->CODEPAGESIZE;
	
		__disable_irq();
	
		//erase number of pages needed
		for (i = FW_START_PAGE; i < 80; i++) {
			// Enable erase.
			NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
			__ISB();
			__DSB();

			// Erase the page
			NRF_NVMC->ERASEPAGE = i * NRF_FICR->CODEPAGESIZE;	
	
			while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {;}
				
			NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
			__ISB();
			__DSB();
		}
		
        //write to flash
        for (i = 0; i < size; i++)
        {
			uint32_t byte_shift = (dest + i) & (uint32_t)0x03;
			uint32_t address32 = (dest + i) & ~byte_shift; // Address to the word this byte is in.
			uint32_t value32 = (*(uint32_t*)address32 & ~((uint32_t)0xFF << (byte_shift << (uint32_t)3)));
			value32 = value32 + ((uint32_t)src[i] << (byte_shift << 3));

			// Enable write.
			NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
			__ISB();
			__DSB();

			*(uint32_t*)address32 = value32;
			while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {;}

			NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
			__ISB();
			__DSB();
        }
		
        //reset board
	     __DSB();                                                          
        SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
                           (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                            SCB_AIRCR_SYSRESETREQ_Msk    );         
         __DSB();                                                          

        for(;;)                                                           
        {
            __NOP();
        }
}

//execute FW update (place FW copy function to RAM and execute it) 
void execute_fw_update(uint8_t* fwData, uint32_t fwSize) {			
		update_fw_proc updater = (update_fw_proc) (RAM_START + 1);
		uint32_t src = (uint32_t)fw_copy_flash;
		memcpy((void*)RAM_START, (void*)(src & ~1), FW_FLASH_FUNC_SIZE);
		__dsb(0xf);
		__isb(0xf);
		(updater)(FW_FLASH_START, fwData, fwSize);
}


What am I doing wrong?

Kind regards.
Ivan.

Related