This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Dual Bank Bootloader Over ESB

I have two nrf52832 boards, both being developed with SDK v11 and the s132 soft device. 

Board one is given commands over UART to communicate over ESB with board two. Board two also has serial communication with an FPGA that can be reprogrammed sucsessfully over ESB. 

The goal is to be able to update the firmware on board two over ESB. Doing this will also reprogram the FPGA that currently boots from a file flashed along with the board two app via the "incbin" library.

Issues I'm having:

1. When trying to read and write to flash I discovered that DFU_BANK_1_REGION_START is in fact 0x918CB001. From my understanding this is the memory location of external RAM which is not attached and am not intending to attach. Also this not a multiple of four and is therefore not a valid boot address? The way the space for banks 0 and 1 are worked out seems to just be (BOOTLOADER_REGION_START - CODE_REGION_1_START)/2, leaves the available space around 1.75GB per bank for me, which is certainly not correct. I know i need to redefine these, but what is the best way to set the start and end position of both banks?  

2. Getting the bootloader to validate the new image and swap it into bank 0 over ESB? I currently can't try this due to not being able to write into the right places in memory but any advice other than swapping over to BLE comms for bootloading or trying to change code for BLE comms with ESB protocols throughout the DFU example would be appreciated.

Thanks in advance 

Jack

Parents
  • Hi Jack, 

     

    Leave the FPGA aside, I assume that you just need to flash a particular binary image to board #2 and the FPGA board will automatically be reprogrammed with the new image located on board #2 ? 

    Could you check and find why DFU_BANK_1_REGION_START = 0x918CB001 in your case ? It doesnt seem correct. Could you trace back and find what cause it to be >2GB ? 

    DFU_BANK_1_REGION_START by default equals (DFU_BANK_0_REGION_START + DFU_IMAGE_MAX_SIZE_BANKED)  

     

    How did you modify the bootloader to receive the image via ESB ? If you can manage to add a new dfu transport layer using ESB, then the bootloader should do its job to validate new image and swap the new image. 

  • Hi Hung, 

    Correct, the FPGA image is sorted out within the app on board #2. The plan is to use existing code for sending new FPGA images to board #2 from board #1. It works over some ESB commands controlled using matlab with realterm as a serial communication to board #1.  I've included the library that is being used for writing to flash for that. Once i've got a valid bank 1 to write to i plan to just use the bootloader library to validate the image and boot. 

    These are the relevant defines from the dfu_types.h file in the bootloader_dfu library and the respective values i get returned for them.

    #define NRF_UICR_BOOT_START_ADDRESS         (NRF_UICR_BASE + 0x14)      
    
    #if defined(NRF52)
    #define NRF_UICR_MBR_PARAMS_PAGE_ADDRESS    (NRF_UICR_BASE + 0x18)      
    #endif
    
    #define CODE_REGION_1_START                 SD_SIZE_GET(MBR_SIZE)   //0x2311D001    
    #define SOFTDEVICE_REGION_START             MBR_SIZE                //0X00001000    
    
    //nrf51 definitions
    
    #elif NRF52
    
    #define BOOTLOADER_REGION_START             0x0007A000                 
    #define BOOTLOADER_SETTINGS_ADDRESS         0x0007F000                  
    #define BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS  0x0007E000                  
    
    #define CODE_PAGE_SIZE                      0x1000                      
    
    #else
    
    #error No target defined
    
    #endif
    
    #define DFU_REGION_TOTAL_SIZE           (BOOTLOADER_REGION_START - CODE_REGION_1_START)             //0XDCF5CFFF            
    
    #ifndef DFU_APP_DATA_RESERVED
    #define DFU_APP_DATA_RESERVED           CODE_PAGE_SIZE * 0                                          //0X00000000   
    #endif
    
    #define DFU_IMAGE_MAX_SIZE_FULL         (DFU_REGION_TOTAL_SIZE - DFU_APP_DATA_RESERVED)             //0XDCF5CFFF    
    
    #define DFU_IMAGE_MAX_SIZE_BANKED       (((DFU_IMAGE_MAX_SIZE_FULL) - \
                                            (DFU_IMAGE_MAX_SIZE_FULL % (2 * CODE_PAGE_SIZE)))/2)        //0X6E7AE000    
                                            
    #define DFU_BL_IMAGE_MAX_SIZE           (BOOTLOADER_SETTINGS_ADDRESS - BOOTLOADER_REGION_START)        
    
    #define DFU_BANK_0_REGION_START         CODE_REGION_1_START                                         //0x2311D001                    
    #define DFU_BANK_1_REGION_START         (DFU_BANK_0_REGION_START + DFU_IMAGE_MAX_SIZE_BANKED)       //0X918CB001

    The issue seems to be the BOOTLOADER_REGION_START value when calculating DFU_REGION_TOTAL_SIZE, as it is less than CODE_REGION_1_START. How do you suggest changing this?

    
    #include "bsp.h"
    
    /******************************************************
    * FUNCTION DECLARATIONS
    *******************************************************/
    uint32_t * start_addr;
    
    /**
     * Function for erasing a page in flash.
     * @param page_address Address of the first word in the page to be erased.
     */
    void flash_page_erase(uint32_t * page_address)
    {
        // Turn on flash erase enable and wait until the NVMC is ready:
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    
        // Erase page:
        NRF_NVMC->ERASEPAGE = (uint32_t)page_address;
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    
        // Turn off flash erase enable and wait until the NVMC is ready:
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    }
    
    
    /**
     * Function for filling a page in flash with a value.
     * @param[in] address Address of the first word in the page to be filled.
     * @param[in] value Value to be written to flash.
     * Note 32 bit words written! To write less than 32 bit words set the bits that should
     * remain unchanged in the word to '1'
     */
    void flash_word_write(uint32_t * address, uint32_t value)
    {
        // Turn on flash write enable and wait until the NVMC is ready:
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    
        *address = value;
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    
        // Turn off flash write enable and wait until the NVMC is ready:
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
    
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
        {
            // Do nothing.
        }
    }
    
    
    
    void init_flash(int erase)
    {
    	int j;
    	uint32_t * addr;
    	uint32_t  pg_size = NRF_FICR->CODEPAGESIZE;
    	uint32_t  start_pg_num = NRF_FICR->CODESIZE - (71339/pg_size + 1);  // Use last pages in flash
    	start_addr = (uint32_t *) (start_pg_num * pg_size);
    
    	//Erase the pages
    	if (erase == 1) {
    		for (j=0; j<(71339/pg_size + 1);j++)
    		{
    			// Set address:
    			addr = (uint32_t *)(start_addr + j*pg_size/4); //Divide by 4 because address is a count of 32 bit words and pg_size is a count of bytes
    			// Erase page:
    			flash_page_erase(addr);
    		}
    	}
    }
    
    
    
    
    
    
    /***********************************************
    * Function to write an array - slightly dodgy casting?
    ************************************************/
    bool flash_array_write(uint32_t * address, uint8_t dataIn[], uint32_t dataLength, uint32_t * checksum)
    {
    	uint32_t  * data;
    	int j;
    
    	if ((dataLength*4)%4 !=0) return false; //Had to make temporary change while I figure out how to pass actual number of bytes instead of number of ints
    	data = (uint32_t *) dataIn;  //Is this ok?
    
    	for (j=0;j<dataLength;j++)
    	{
    		flash_word_write(address+j, *(data+j)); //data is 4 bytes
    		*checksum += *(data+j);
    	}
    	return true;
    }
    
    
    uint32_t flash_word_read(uint32_t * address)
    {
    	//ensure read only is Enabled
    	NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
    
    	while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    	{
    			// Do nothing.
    	}
    
    	return *address;
    
    	while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    	{
    			// Do nothing.
    	}
    }
    

    Thanks again :) 

  • CODE_REGION_1_START doesn't seem to be correct. Usually it's just the size of the softdevice which is written inside the softdevice (SOFTDEVICE_INFO_STRUCT_ADDRESS) 

     

    You can find this address usually by reading the address 0x3000 after you flash the softdevice. 

Reply Children
Related