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. 

  • I re-flashed the soft device and read this

    CODE_REGION_1_START = 0x32FFF04F

    0x3000 = 0x2311D001

    any ideas?

    Sorry for the delayed response. 

  • Hi Jack, 

    Could you let which S132 version you used ? 

    It looks pretty strange. The structure of the softdevice information is defined in Chapter 13 in S132 SDS v6.0

    The size of the softdevice is located at word 2nd meaning address 0x3008 (SOFTDEVICE_INFO_STRUCT_ADDRESS + 8)

    This is what I see when I flash the board with S132 v6.0 and use nrfjprog to read: 

    0x26000 matched with the size of the softdevice (+MBR) of 152kB. 

  •  This is what I get, soft device is s132 v2.0.0

    2nd image is what i get after re-flashing the soft device, seems to be correct now. Whenever I flash my code however it seems to mess with the soft device. Is there maybe an issue with my linker file or makefile? 

Reply Children
  • Okey, so maybe your code overwritten the softdevice. 

    Where is there start address  of your application (and your bootloader if you have one ?) and where is your bin file located in the flash ?  

  • The start address of the my app will be CODE_REGION_1_START right? I've not flashed the bootloader yet as I was trying to resolve this issue first. 

    I'm not really sure how to locate where my app ends in flash but I know that my hex file is around 240KB. 

    I'm using the .ld file form the blinky example which may be the issue, this is what it looks like currently. 

    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000
      UICR (rx) : ORIGIN = 0x10001000, LENGTH = 0x0FFFF000
      RAM (rwx) :  ORIGIN = 0x20000000, LENGTH = 0x10000
    }
    
    SECTIONS
    {
      .uicr 0x1000120C :
      {
    	KEEP(*(.uicr))
      } > UICR
      .fs_data :
      {
        PROVIDE(__start_fs_data = .);
        KEEP(*(.fs_data))
        PROVIDE(__stop_fs_data = .);
      } > RAM
    } INSERT AFTER .data;
    
    INCLUDE "nrf5x_common.ld"

    the origin of flash should maybe be moved to after the softdevice?  

  • Hi Jack, 

     

    No, not really CODE_REGION_1_START is used in the bootloader code to detect where it should swap the old image with the new image. 

    But do you need softdevice in your application ? As far as I can see you are using ESB no BLE ? 

    If you use softdevice, you application start address has to adjust to be located after the softdevice. Please have a look at any example inside ble_peripheral or in the blinky example adjusted for softdevice:  \examples\peripheral\blinky\pca10040\s132\armgcc 

     

    How do you plan to swap image on the board 2 ? You would need to use a bootloader to do the task. 

  • I see, in which case how do I check the start and end points of my application?

    If the soft device is only required for the BLE communication then you're right i wont be needing it, thanks.  I assumed that it would be required to work with the bootloader but I guess not. The plan is to write the new image to the address immediately after the current application and get the bootloader to validate it from there and swap them over. Writing the new image can be done the same way that I am currently receiving the FPGA image, just writing it to an address in flash rather than the FPGA. I'm just not sure which address to write it to. 

  • You can remove the softdevice if you don't plan to use BLE. But you still need the MBR to do the image replacing. What you are planing to do require good understanding on how the MBR works and assessment if a bootloader needed or not. I would suggest you to get familiar with how our bootloader work, how we replace application image and also replace the bootloader itself. How the bootloader is executed and the vector table is forwarded by the MBR. 

    The start point of your application is defined in the .ld file, as in the blinky example :  FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000 , start at address 0x00.

    The size of your application shows by the compiler after you build it. Or you can find the size using .map file, or convert to binary file. 

     

     

Related