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

DFU - problem with moving data from external to internal flash

Hi,

I'm working on modification of DFU Bootloader to use external flash instead of standard Dual-bank or Single-bank version. Now it works quite well, but I have problems with moving data received over BT and stored in external memory to Bank 0 (in MCU flash).

I have edited function nrf_dfu_app_continue() to my needs. But there was a problem.

I tested it with blinky example hex as an update package. When I loaded 4096 bytes from external memory and wanted to store them in internal memory (using function nrf_dfu_flash_store) it looks that store function called in first iteration of the loop is performed only when second iteration is already running – therefore it uses wrong data (stored yet in page_buff array), but it is written into first page of internal memory. In that case I have data from second page of external memory both in first and second page of internal memory - and it's wrong. I expect, that I have to wait until store operation is completely finished and then start second iteration - but how to do it? Temporarily I solved it using two buffers which are switched each iteration of the loop, but I don't think it's correct solution.

And second question: I have to use wait_for_queue() function before each operation with internal flash - otherwise I'm getting errors that it cannot erase data on specified address etc. In original function these function calls are not necessary, but for me it's only option - why?

Thank you in advance for your help!

There is my code of modified function:

    uint32_t image_size = image_info[0];
    uint32_t const split_size  = CODE_PAGE_SIZE;

    uint32_t ret_val            = NRF_SUCCESS;
    uint32_t target_addr        = MAIN_APPLICATION_START_ADDR;
    uint32_t length_left        = image_size;
    uint32_t cur_len;
    uint32_t crc;
	uint32_t external_memory_address = 0;
	uint16_t external_memory_offset;
	uint16_t i;
	uint8_t	rx_buff[256];
	bool use_buff_2 = false;

    NRF_LOG_DEBUG("Enter nrf_dfu_app_continue\r\n");
    do
    {

        cur_len = (length_left > split_size) ? split_size : length_left;
		
		// Change used buffer
		if(!use_buff_2)
		{
			memset(page_buff, 0, 4096);
		}
		
		else 
		{
			memset(page_buff2, 0, 4096);
		}

		// Get 4096 bytes from external memory		
		external_memory_offset = 0;
		while(external_memory_offset < 4096)
		{
			memset(rx_buff,0,256);
			
			// My function to read data from external memory over SPI
			ReadPage(rx_buff, external_memory_address+external_memory_offset, 256);

			for(i=0;i<256;i++)
			{
				if(use_buff_2)
				{
					page_buff2[i+external_memory_offset] = rx_buff[i]; 
				}
				else 
				{
					page_buff[i+external_memory_offset] = rx_buff[i]; 
				}
			}
			external_memory_offset += 256;
		}
		 	
        // Erase the target page
		wait_for_queue();		
        ret_val = nrf_dfu_flash_erase((uint32_t*) target_addr, split_size / CODE_PAGE_SIZE, NULL);
        if (ret_val != NRF_SUCCESS)
        {
            return ret_val;
        }
		
        // Flash one page
		wait_for_queue();		
		ret_val = nrf_dfu_flash_store((uint32_t*)target_addr, (!use_buff_2) ? (uint32_t*)page_buff : (uint32_t*)page_buff2, cur_len, NULL);
        if (ret_val != NRF_SUCCESS)
        {
            return ret_val;
        }

		// TODO: compare copied data with original in external memory
		
        s_dfu_settings.write_offset += cur_len;
        ret_val = nrf_dfu_settings_write(NULL);

        target_addr += cur_len;
		external_memory_address += cur_len;
        length_left -= cur_len;
		use_buff_2 = !use_buff_2;
    }
    while(length_left > 0);

	wait_for_queue();		
	crc = crc32_compute((uint8_t*)MAIN_APPLICATION_START_ADDR, image_size, NULL);
	s_dfu_settings.bank_0.image_crc = crc;
	s_dfu_settings.bank_0.image_size = image_size;

    ret_val = nrf_dfu_settings_write(NULL); 
    return ret_val;
  • Hi,

    Could you let me know which SDK you are using ?

    When do you call nrf_dfu_app_continue() ?

    Do you have the softdevice running when you call that function ? If the softdevice is running, the access to NVMC peripheral is blocked and you shouldn't use the function. We call nrf_dfu_app_continue() after we reset and have the softdevice not running.

    What do you have inside wait_for_queue() ?

    What if you try to write only 1 page ? So only the first nrf_dfu_flash_store() is called ?

  • I'm using SDK 13.0.0, bootloader is based on example bootloader_secure_ble. My modified function nrf_dfu_app_continue() is called in nrf_dfu_data_req(), right before nrf_dfu_postvalidate() call.

    I'm not sure if softdevice is running during the call, but I think so, because BT communication is still working.

    wait_for_queue() is function from nrf_dfu_settings.c, which I only made extern to use in other functions. Its code:

    while (fs_queue_is_full())
    {
            delay_operation();
    }
    

    When I write only one page, it is OK - one page is correctly written.

    In SDK documentation there is comment to nrf_dfu_flash_store(): With SoftDevice, the operation is complete when the fstorage event is received. But I don't now how to work with that, I tried to use shared bool variable, which was set true when event occured, but it didn't work.

  • Not sure why you want to call nrf_dfu_app_continue() inside nrf_dfu_data_req(), why not let it run after the new image has been validated ? We do nrf_dfu_app_continue() after a reset and before the softdevice start to let the swapping image can run faster (because we can access flash directly, not requires softdevice)

    If you do flash activity when the softdevice is active, make sure you use nrf_fstorage_sd.c not the _nvmc.c one.

    When the softdevice is running, the operation is not blocking and you only register the command to the softdevice, so you need to check the call back to dequeue the number of queued activity.

    You can follow what we do when we call nrf_dfu_flash_store() in dfu_req_handling.c , we use dfu_data_write_handler() as the callback handler.

    Im not 100% sure why you have the issue you described, but what you can do is to make sure the last operation is finished m_flash_operations_pending=0 before you do next operation.

  • I was not sure, if I can call postvalidate function when there isn't image in flash yet. So I decided to copy data from external to internal flash before.

    But..

    I probably found solution for my problem. It's simmilar to your suggested idea - I just call wait_for_pending() at the end of each iteration. In that case it waits to finish store/erase operations and then start next iteration - this was exactly what I needed. :)

    Now I have to figure out, how to compare data in flash with data in page_buffer (in RAM), because nrf_dfu_mbr_compare() function probably doesn't work in that case. But it's another story... :)

    Thank you for your help

Related