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

Start Bootloader From App

I'm trying to create a method so a users can initiate an OTA update from a paired device. To that end I've written something which is supposed to invalidate the data at the BOOTLOADER_SETTINGS_ADDRESS to invalidate the current app and then call a system reset to run through the bootloader. Once working I will call this routine (start_bootloader()) on a given event from the paired device.

My problem is I can't understand pstorage and how to use it to invalidate the data at the BOOTLOADER_SETTINGS_ADDRESS. In looking through some examples (in the bootloader code for example, which most of the following is from) I can't see how the code actually specifies the BOOTLOADER_SETTINGS_ADDRESS as where to write the data. I see how it gets the data from that address.

The code below does not throw any errors it just does nothing. When I break at the sd_nvic_SystemReset(); call no memory locations have been affected and the app just restarts.

Note that I do NOT have a bootloader installed. I have set up to flash a device with softdevice, application and bootloader, setting the BOOTLOADER_SETTINGS_ADDRESS correctly and the BOOT_ADDR correctly so that everything works (i.e. it starts up in the application). If a corrupt the data used to flash the BOOTLOADER_SETTINGS_ADDRESS it goes to the bootloader and I can OTA the applications.

So what I'm asking is what am I doing wrong with pstorage below so that it is NOT changing the BOOTLOADER_SETTINGS_ADDRESS.

   typedef enum
{
    BOOTLOADER_UPDATING,
    BOOTLOADER_SETTINGS_SAVING,
    BOOTLOADER_COMPLETE,
    BOOTLOADER_TIMEOUT,
    BOOTLOADER_RESET,
} bootloader_status_t;


static pstorage_handle_t        m_bootsettings_handle;  /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */
static bootloader_status_t      m_update_status;        /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */

static void pstorage_callback_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len)
{
    // Do Nothing For Now
    APP_ERROR_CHECK(result);
}



/*@brief Function for access to bootloader setting */

void bootloader_util_settings_get(const bootloader_settings_t** pp_bootloader_settings)
{
    // Read only pointer to bootloader settings in flash.
    *pp_bootloader_settings = (bootloader_settings_t*)BOOTLOADER_SETTINGS_ADDRESS;
}


void bootloader_settings_save(bootloader_settings_t * p_settings)
{
    uint32_t err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t));
    APP_ERROR_CHECK(err_code);
    
    err_code = pstorage_store(&m_bootsettings_handle,
                              (uint8_t *)p_settings,
                              sizeof(bootloader_settings_t),
                              0);
    APP_ERROR_CHECK(err_code);
}

void start_bootloader()
{
    uint32_t                err_code = NRF_SUCCESS;
    pstorage_module_param_t storage_params;
    
    //    sd_softdevice_disable();
    
    storage_params.cb          = pstorage_callback_handler;
    storage_params.block_size  = sizeof(bootloader_settings_t);
    storage_params.block_count = 1;
    
    err_code = pstorage_init();
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    
    err_code = pstorage_register(&storage_params, &m_bootsettings_handle);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    //    m_bootsettings_handle.block_id = BOOTLOADER_SETTINGS_ADDRESS;
    static bootloader_settings_t settings;
    const bootloader_settings_t * p_bootloader_settings;
    
    bootloader_util_settings_get(&p_bootloader_settings);
    settings.bank_0_crc  = p_bootloader_settings->bank_0_crc;
    settings.bank_0_size = p_bootloader_settings->bank_0_size;
    settings.bank_0      = BANK_VALID_APP;
    settings.bank_1      = p_bootloader_settings->bank_1;
    
    bootloader_settings_save(&settings);
    
    sd_nvic_SystemReset();
    
}
Parents
  • I'll say up front that I am not a pstorage expert. That said, I believe that the bootloader application will allocate a pstorage area at the very top of memory. The bootloader is allocated the space right below its pstorage area. Then your application will create its own pstorage area beneath the bootloader. So it may be difficult for you to corrupt the bootloaders pstorage from the application FW.

    I have a bit simpler mechanism for entering the bootloader in my application. When I receive the go into bootloader command from my host application, I set a value in the general purpose RAM retention register (GPREGRET) and reset. The bootloader init code looks at the GPREGRET and if my enter bootloader value is present, the bootloader is invoked. I'll put a code snippet from my applicaton below. Note, the reset is not performed in the command handler the command handler sets a flag that is checked elsewhere.

    	if (p_received_command->parameters[0] == ENTER_RADIO_BOOTLOADER)
    	{
    		calc_response_length(O_CMD_SUCCESS);
    		p_onset->cmd_resp_ready = true;
    		
    		set_enter_bootloader(true);
    		
    		err_code = sd_power_gpregret_clr(0xFF);
    		if (err_code != NRF_SUCCESS)
    		{
    			ASSERT(false);
    		}
    		
    		err_code = sd_power_gpregret_set(ENTER_BOOTLOADER_VALUE);
    		if (err_code != NRF_SUCCESS)
    		{
    			ASSERT(false);
    		}
    		
    		return;
    	}
    
  • That control snippet is part of my on_write event handler for my proprietary service and characteristic. The p_received_command points to the data portion of the event which contains my proprietary commands including a enter bootloader command. It is declared like this:

    	ble_gatts_evt_write_t	* p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    onset_recv_command_t	* p_received_command = (onset_recv_command_t *)&p_evt_write->data[0];
    
Reply
  • That control snippet is part of my on_write event handler for my proprietary service and characteristic. The p_received_command points to the data portion of the event which contains my proprietary commands including a enter bootloader command. It is declared like this:

    	ble_gatts_evt_write_t	* p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    onset_recv_command_t	* p_received_command = (onset_recv_command_t *)&p_evt_write->data[0];
    
Children
No Data
Related