nrf_dfu_flash_store change to QSPI function -> callback issue in nrfx_qspi_write

Hi

I'm chnaging the Secure Bootloader to an external falsh for bank1, connected with QSPI.

In the function on_data_obj_write_request is the call for nrf_dfu_flash_store (file nrf_dfu_req_handler.c

static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
    NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");

    if (!nrf_dfu_validation_init_cmd_present())
    {
        /* Can't accept data because DFU isn't initialized by init command. */
        p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
        return;
    }

    uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
                                        s_dfu_settings.progress.firmware_image_offset_last;

    if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
    {
        /* Can't accept data because too much data has been received. */
        NRF_LOG_ERROR("Write request too long");
        p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
        return;
    }

    uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
    /* CRC must be calculated before handing off the data to fstorage because the data is
     * freed on write completion.
     */
    uint32_t const next_crc =
        crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);

    ASSERT(p_req->callback.write);

    ret_code_t ret =
        nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);

    if (ret != NRF_SUCCESS)
    {
        /* When nrf_dfu_flash_store() fails because there is no space in the queue,
         * stop processing the request so that the peer can detect a CRC error
         * and retransmit this object. Remember to manually free the buffer !
         */
        p_req->callback.write((void*)p_req->write.p_data);
        return;
    }

    /* Update the CRC of the firmware image. */
    s_dfu_settings.write_offset                   += p_req->write.len;
    s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
    s_dfu_settings.progress.firmware_image_crc     = next_crc;

    /* This is only used when the PRN is triggered and the 'write' message
     * is answered with a CRC message and these field are copied into the response.
     */
    p_res->write.crc    = s_dfu_settings.progress.firmware_image_crc;
    p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
}

There is a callback which is needed:

ret_code_t ret =
        nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);

inside this function I use the QSPI function:

hal_qspi_write(&p_src, len, (dest & EXTERNAL_FLASH_ADDRESS_LOWER_BYTES), (void*)callback))

which at the end is calling the nrfx function nrfx_qspi_write. 

Here I should have a callback, but I don't know what I should implement.

The original callback in the nrf_fstorage_write is implemented like this:
return (p_fs->p_api)->write(p_fs, dest, p_src, len, p_context);

ret_code_t nrf_fstorage_write(nrf_fstorage_t const * p_fs,
                              uint32_t               dest,
                              void           const * p_src,
                              uint32_t               len,
                              void                 * p_context)
{
    NRF_FSTORAGE_PARAM_CHECK(p_fs,        NRF_ERROR_NULL);
    NRF_FSTORAGE_PARAM_CHECK(p_src,       NRF_ERROR_NULL);
    NRF_FSTORAGE_PARAM_CHECK(p_fs->p_api, NRF_ERROR_INVALID_STATE);
    NRF_FSTORAGE_PARAM_CHECK(len,         NRF_ERROR_INVALID_LENGTH);

    /* Length must be a multiple of the program unit. */
    NRF_FSTORAGE_PARAM_CHECK(!(len % p_fs->p_flash_info->program_unit), NRF_ERROR_INVALID_LENGTH);

    /* Source and destination addresses must be word-aligned. */
    NRF_FSTORAGE_PARAM_CHECK(addr_is_aligned32(dest),                NRF_ERROR_INVALID_ADDR);
    NRF_FSTORAGE_PARAM_CHECK(addr_is_aligned32((uint32_t)p_src),     NRF_ERROR_INVALID_ADDR);
    NRF_FSTORAGE_PARAM_CHECK(addr_is_within_bounds(p_fs, dest, len), NRF_ERROR_INVALID_ADDR);

    return (p_fs->p_api)->write(p_fs, dest, p_src, len, p_context);
}

Now the DFU is strating on bank1 but the App is generating an error because data is missing because of this callack I guess?

I was following this topic:

https://devzone.nordicsemi.com/f/nordic-q-a/48961/dfu-with-external-qspi-memory

Parents
  • I add the 2 files, bank 0 was DFU process with call to internal flash, this one was running ok like expected. (stopped the transfer in debugging mode after some packets)

    The other log of bank1 with call to external QSPI falsh has failed.

    nRF Connect, 2024-06-21
    No name (F9:3E:58:83:16:DF)
    V	13:15:26.644	Connecting to F9:3E:58:83:16:DF...
    D	13:15:26.644	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
    D	13:15:26.973	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
    I	13:15:26.973	Connected to F9:3E:58:83:16:DF
    V	13:15:26.977	Discovering services...
    D	13:15:26.977	gatt.discoverServices()
    D	13:15:26.990	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
    I	13:15:27.319	Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
    D	13:15:27.632	[Callback] Services discovered with status: 0
    I	13:15:27.632	Services discovered
    V	13:15:27.648	Generic Access (0x1800)
    - Device Name [R W] (0x2A00)
    - Appearance [R] (0x2A01)
    - Peripheral Preferred Connection Parameters [R] (0x2A04)
    - Central Address Resolution [R] (0x2AA6)
    Generic Attribute (0x1801)
    - Service Changed [I] (0x2A05)
       Client Characteristic Configuration (0x2902)
    Device Information (0x180A)
    - Manufacturer Name String [R] (0x2A29)
    - Model Number String [R] (0x2A24)
    - Serial Number String [R] (0x2A25)
    - Hardware Revision String [R] (0x2A27)
    - Software Revision String [R] (0x2A28)
    Unknown Service (7189498b-a0b1-4e80-8f20-18fd31da8b3a)
    - Unknown Characteristic [I N R W] (71891401-a0b1-4e80-8f20-18fd31da8b3a)
       Client Characteristic Configuration (0x2902)
    - Unknown Characteristic [R W] (71891402-a0b1-4e80-8f20-18fd31da8b3a)
    Secure DFU Service (0xFE59)
    - Buttonless DFU [I W] (8ec90003-f315-4f60-9fb8-838830daea50)
       Client Characteristic Configuration (0x2902)
    D	13:15:27.648	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
    D	13:15:27.654	gatt.setCharacteristicNotification(71891401-a0b1-4e80-8f20-18fd31da8b3a, true)
    I	13:15:27.707	Connection parameters updated (interval: 30.0ms, latency: 0, timeout: 5000ms)
    I	13:15:28.282	PHY updated (TX: LE 2M, RX: LE 2M)
    V	13:15:31.008	[DFU] DFU service started
    V	13:15:31.008	[DFU] Opening file...
    I	13:15:31.025	[DFU] Firmware file opened successfully
    V	13:15:31.025	[DFU] Connecting to DFU target...
    D	13:15:31.025	[DFU] gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferredPhy = LE_1M | LE_2M)
    I	13:15:31.041	[DFU] Connected to F9:3E:58:83:16:DF
    V	13:15:31.041	[DFU] Discovering services...
    D	13:15:31.041	[DFU] gatt.discoverServices()
    I	13:15:31.041	[DFU] Services discovered
    W	13:15:31.042	[DFU] Application with buttonless update found
    V	13:15:31.042	[DFU] Jumping to the DFU Bootloader...
    V	13:15:31.042	[DFU] Enabling indications for 8ec90003-f315-4f60-9fb8-838830daea50
    D	13:15:31.042	[DFU] gatt.setCharacteristicNotification(8ec90003-f315-4f60-9fb8-838830daea50, true)
    D	13:15:31.042	[DFU] gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x02-00)
    I	13:15:31.094	[DFU] Data written to descr.8ec90003-f315-4f60-9fb8-838830daea50
    V	13:15:31.094	[DFU] Notifications enabled for 8ec90003-f315-4f60-9fb8-838830daea50
    A	13:15:31.094	[DFU] Indications enabled
    V	13:15:31.095	[DFU] Writing to characteristic 8ec90003-f315-4f60-9fb8-838830daea50, value (0x): 01
    D	13:15:31.095	[DFU] gatt.writeCharacteristic(8ec90003-f315-4f60-9fb8-838830daea50, value=0x01, WRITE_TYPE_DEFAULT)
    A	13:15:31.155	[DFU] Enter bootloader sent (Op Code = 1)
    I	13:15:31.186	[DFU] Notification received from 8ec90003-f315-4f60-9fb8-838830daea50, value (0x): 20-01-01
    A	13:15:31.187	[DFU] Response received (Op Code = 1, Status = 1)
    V	13:15:31.187	[DFU] Disconnecting...
    D	13:15:31.188	[DFU] gatt.disconnect()
    I	13:15:31.197	[DFU] Disconnected
    D	13:15:31.198	[DFU] gatt.refresh() (hidden)
    D	13:15:31.198	[DFU] gatt.disconnect()
    D	13:15:31.198	[DFU] gatt.close()
    V	13:15:31.198	[DFU] Scanning for the DFU Bootloader... (timeout 5000 ms)
    I	13:15:31.726	Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
    I	13:15:32.057	Connection parameters updated (interval: 30.0ms, latency: 0, timeout: 5000ms)
    I	13:15:32.342	[DFU] DFU Bootloader found with address F9:3E:58:83:16:E0
    V	13:15:32.356	[DFU] DFU service started
    I	13:15:32.356	[DFU] Firmware file opened successfully
    V	13:15:32.356	[DFU] Connecting to DFU target...
    D	13:15:32.389	[DFU] gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferredPhy = LE_1M | LE_2M)
    I	13:15:32.483	[DFU] Connected to F9:3E:58:83:16:E0
    V	13:15:32.483	[DFU] Discovering services...
    D	13:15:32.483	[DFU] gatt.discoverServices()
    D	13:15:32.600	[DFU] [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
    I	13:15:33.214	[DFU] Services discovered
    V	13:15:33.268	[DFU] Requesting new MTU...
    D	13:15:33.268	[DFU] gatt.requestMtu(517)
    I	13:15:33.268	[DFU] MTU changed to: 247
    V	13:15:33.268	[DFU] Enabling notifications for 8ec90001-f315-4f60-9fb8-838830daea50
    D	13:15:33.268	[DFU] gatt.setCharacteristicNotification(8ec90001-f315-4f60-9fb8-838830daea50, true)
    D	13:15:33.268	[DFU] gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x01-00)
    I	13:15:33.268	[DFU] Data written to descr.8ec90001-f315-4f60-9fb8-838830daea50
    V	13:15:33.268	[DFU] Notifications enabled for 8ec90001-f315-4f60-9fb8-838830daea50
    A	13:15:33.268	[DFU] Notifications enabled
    V	13:15:33.268	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 06-01
    D	13:15:33.268	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x06-01, WRITE_TYPE_DEFAULT)
    I	13:15:33.311	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	13:15:33.311	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-06-01-00-02-00-00-D2-00-00-00-29-C8-73-B4
    A	13:15:33.311	[DFU] Command object info received (Max size = 512, Offset = 210, CRC = B473C829)
    A	13:15:33.311	[DFU] Received CRC match Init packet
    V	13:15:33.311	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	13:15:33.311	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	13:15:33.337	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	13:15:33.359	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    A	13:15:33.359	[DFU] Command object executed
    V	13:15:33.359	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 06-02
    D	13:15:33.359	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x06-02, WRITE_TYPE_DEFAULT)
    I	13:15:33.382	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	13:15:33.383	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-06-01-00-10-00-00-00-00-00-00-00-00-00-00
    A	13:15:33.383	[DFU] Data object info received (Max size = 4096, Offset = 0, CRC = 00000000)
    V	13:15:33.384	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	13:15:33.385	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	13:15:33.422	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	13:15:33.422	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    A	13:15:33.422	[DFU] Data object (1/117) created
    D	13:15:33.422	[DFU] wait(400)
    A	13:15:33.815	[DFU] Uploading firmware...
    V	13:15:33.815	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	13:15:33.881	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	13:15:33.881	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	13:15:34.097	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-00-10-00-00-7C-E3-92-0A
    I	13:15:34.097	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	13:15:34.100	[DFU] Checksum received (Offset = 4096, CRC = 0A92E37C)
    V	13:15:34.100	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	13:15:34.100	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	13:15:34.138	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    I	13:15:34.138	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	13:15:34.138	[DFU] Data object executed
    V	13:15:34.138	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	13:15:34.138	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	13:15:34.164	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	13:15:34.165	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    A	13:15:34.165	[DFU] Data object (2/117) created
    D	13:15:34.165	[DFU] wait(400)
    A	13:15:34.566	[DFU] Uploading firmware...
    V	13:15:34.566	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	13:15:34.621	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	13:15:34.621	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	13:15:34.642	[DFU] PHY updated (TX: LE 2M, RX: LE 2M)
    I	13:15:34.725	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-00-10-00-00-7C-E3-92-0A
    I	13:15:34.725	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	13:15:34.725	[DFU] Checksum received (Offset = 4096, CRC = 0A92E37C)
    W	13:15:34.725	[DFU] 4096 bytes were lost
    V	13:15:34.725	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 02-01-00
    D	13:15:34.725	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x02-01-00, WRITE_TYPE_DEFAULT)
    I	13:15:34.748	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-02-01
    I	13:15:34.748	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	13:15:34.748	[DFU] Packet Receipt Notif Req (Op Code = 2) sent (Value = 1)
    A	13:15:34.748	[DFU] Resuming uploading firmware...
    V	13:15:34.748	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    D	13:15:37.192	[Callback] Connection state changed with status: 8 and new state: DISCONNECTED (0)
    E	13:15:37.193	Error 8 (0x8): GATT CONN TIMEOUT
    I	13:15:37.193	Disconnected
    D	13:15:37.220	[Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
    E	13:16:10.129	[DFU] Device has disconnected
    D	13:16:10.129	[DFU] gatt.disconnect()
    D	13:16:10.218	[DFU] gatt.close()
    D	13:16:10.221	[DFU] [Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
    V	13:16:10.231	[DFU] DFU service started
    I	13:16:10.231	[DFU] Firmware file opened successfully
    V	13:16:10.231	[DFU] Connecting to DFU target...
    D	13:16:10.261	[DFU] gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferredPhy = LE_1M | LE_2M)
    

    nRF Connect, 2024-06-21
    DFU_09 16:DF (F9:3E:58:83:16:E0)
    V	12:59:17.720	Connecting to F9:3E:58:83:16:E0...
    D	12:59:17.720	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
    D	12:59:17.785	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
    I	12:59:17.785	Connected to F9:3E:58:83:16:E0
    V	12:59:17.798	Discovering services...
    D	12:59:17.798	gatt.discoverServices()
    D	12:59:17.813	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
    I	12:59:18.196	Connection parameters updated (interval: 15.0ms, latency: 0, timeout: 6000ms)
    I	12:59:18.400	Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
    D	12:59:18.499	[Callback] Services discovered with status: 0
    I	12:59:18.499	Services discovered
    V	12:59:18.503	Generic Access (0x1800)
    - Device Name [R W] (0x2A00)
    - Appearance [R] (0x2A01)
    - Peripheral Preferred Connection Parameters [R] (0x2A04)
    - Central Address Resolution [R] (0x2AA6)
    Generic Attribute (0x1801)
    Secure DFU Service (0xFE59)
    - DFU Packet [WNR] (8ec90002-f315-4f60-9fb8-838830daea50)
    - DFU Control Point [N W] (8ec90001-f315-4f60-9fb8-838830daea50)
       Client Characteristic Configuration (0x2902)
    I	12:59:18.580	Connection parameters updated (interval: 15.0ms, latency: 0, timeout: 6000ms)
    I	12:59:20.703	PHY updated (TX: LE 2M, RX: LE 2M)
    V	12:59:34.654	[DFU] DFU service started
    V	12:59:34.654	[DFU] Opening file...
    I	12:59:34.683	[DFU] Firmware file opened successfully
    V	12:59:34.683	[DFU] Connecting to DFU target...
    D	12:59:34.683	[DFU] gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferredPhy = LE_1M | LE_2M)
    I	12:59:34.688	[DFU] Connected to F9:3E:58:83:16:E0
    V	12:59:34.688	[DFU] Discovering services...
    D	12:59:34.688	[DFU] gatt.discoverServices()
    I	12:59:34.689	[DFU] Services discovered
    V	12:59:34.705	[DFU] Requesting new MTU...
    D	12:59:34.705	[DFU] gatt.requestMtu(517)
    I	12:59:34.719	[DFU] MTU changed to: 247
    V	12:59:34.719	[DFU] Enabling notifications for 8ec90001-f315-4f60-9fb8-838830daea50
    D	12:59:34.719	[DFU] gatt.setCharacteristicNotification(8ec90001-f315-4f60-9fb8-838830daea50, true)
    D	12:59:34.721	[DFU] gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x01-00)
    I	12:59:34.780	[DFU] Data written to descr.8ec90001-f315-4f60-9fb8-838830daea50
    V	12:59:34.780	[DFU] Notifications enabled for 8ec90001-f315-4f60-9fb8-838830daea50
    A	12:59:34.780	[DFU] Notifications enabled
    V	12:59:34.780	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 06-01
    D	12:59:34.780	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x06-01, WRITE_TYPE_DEFAULT)
    I	12:59:34.809	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:34.810	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-06-01-00-02-00-00-00-00-00-00-00-00-00-00
    A	12:59:34.810	[DFU] Command object info received (Max size = 512, Offset = 0, CRC = 00000000)
    V	12:59:34.810	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 02-00-00
    D	12:59:34.810	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x02-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:34.839	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:34.839	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-02-01
    A	12:59:34.839	[DFU] Packet Receipt Notif disabled (Op Code = 2, Value = 0)
    V	12:59:34.839	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-01-D2-00-00-00
    D	12:59:34.839	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-01-D2-00-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:34.869	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:34.869	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    A	12:59:34.870	[DFU] Command object created
    V	12:59:34.870	[DFU] Writing to characteristic 8ec90002-f315-4f60-9fb8-838830daea50 value (0x): 12-CF-01-0A-88-01-08-01-12-83-01-08-8A-44-10-34-1A-04-80-02-A3-02-20-00-28-00-30-00-38-F8-81-1D-42-24-08-03-12-20-08-73-6A-FB-5F-BF-64-22-A5-7A-B3-3F-E6-DC-3A-1F-12-8F-88-27-D4-67-AA-C4-77-BB-D4-E1-74-CF-A0-2D-48-00-52-44-08-03-12-40-7E-0E-2C-0D-F3-00-9B-CB-95-64-E8-66-2A-DA-6D-83-14-64-B8-81-BB-1C-91-E1-DA-2F-95-B3-55-33-85-00-63-1D-41-C0-7F-EB-54-8E-EC-33-AF-AF-6C-59-44-B5-DE-60-AA-68-14-31-02-85-E0-B7-0D-E4-11-9E-FA-FF-10-00-1A-40-E0-DA-01-4D-ED-0F-57-DA-44-26-CF-8C-66-F0-D2-CF-B4-39-E6-A3-6C-23-85-8F-4F-2E-60-EA-87-D1-16-75-FC-E2-19-FC-F3-0C-CB-76-95-F1-64-A4-75-5B-13-B7-64-94-9C-59-D1-3C-77-E8-F9-6B-CB-C7-65-3D-A1-EE
    D	12:59:34.870	[DFU] gatt.writeCharacteristic(8ec90002-f315-4f60-9fb8-838830daea50, value=0x12-CF-01-0A-88-01-08-01-12-83-01-08-8A-44-10-34-1A-04-80-02-A3-02-20-00-28-00-30-00-38-F8-81-1D-42-24-08-03-12-20-08-73-6A-FB-5F-BF-64-22-A5-7A-B3-3F-E6-DC-3A-1F-12-8F-88-27-D4-67-AA-C4-77-BB-D4-E1-74-CF-A0-2D-48-00-52-44-08-03-12-40-7E-0E-2C-0D-F3-00-9B-CB-95-64-E8-66-2A-DA-6D-83-14-64-B8-81-BB-1C-91-E1-DA-2F-95-B3-55-33-85-00-63-1D-41-C0-7F-EB-54-8E-EC-33-AF-AF-6C-59-44-B5-DE-60-AA-68-14-31-02-85-E0-B7-0D-E4-11-9E-FA-FF-10-00-1A-40-E0-DA-01-4D-ED-0F-57-DA-44-26-CF-8C-66-F0-D2-CF-B4-39-E6-A3-6C-23-85-8F-4F-2E-60-EA-87-D1-16-75-FC-E2-19-FC-F3-0C-CB-76-95-F1-64-A4-75-5B-13-B7-64-94-9C-59-D1-3C-77-E8-F9-6B-CB-C7-65-3D-A1-EE, WRITE_TYPE_NO_RESPONSE)
    I	12:59:34.873	[DFU] Data written to 8ec90002-f315-4f60-9fb8-838830daea50
    A	12:59:34.873	[DFU] Command object sent (CRC = B473C829)
    V	12:59:34.873	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	12:59:34.873	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	12:59:34.900	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-D2-00-00-00-29-C8-73-B4
    I	12:59:34.901	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	12:59:34.902	[DFU] Checksum received (Offset = 210, CRC = B473C829)
    V	12:59:34.902	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	12:59:34.902	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	12:59:34.929	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:34.944	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    A	12:59:34.944	[DFU] Command object executed
    V	12:59:34.944	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 06-02
    D	12:59:34.945	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x06-02, WRITE_TYPE_DEFAULT)
    I	12:59:34.974	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:34.974	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-06-01-00-10-00-00-00-00-00-00-00-00-00-00
    A	12:59:34.974	[DFU] Data object info received (Max size = 4096, Offset = 0, CRC = 00000000)
    V	12:59:34.999	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	12:59:34.999	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:35.112	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    I	12:59:35.112	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	12:59:35.112	[DFU] Data object (1/117) created
    D	12:59:35.112	[DFU] wait(400)
    A	12:59:35.513	[DFU] Uploading firmware...
    V	12:59:35.513	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	12:59:35.548	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	12:59:35.548	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	12:59:35.605	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:35.606	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-00-10-00-00-7C-E3-92-0A
    A	12:59:35.607	[DFU] Checksum received (Offset = 4096, CRC = 0A92E37C)
    V	12:59:35.608	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	12:59:35.608	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	12:59:35.634	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:35.816	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    A	12:59:35.816	[DFU] Data object executed
    V	12:59:35.816	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	12:59:35.816	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:35.844	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:35.844	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    A	12:59:35.844	[DFU] Data object (2/117) created
    D	12:59:35.844	[DFU] wait(400)
    A	12:59:36.245	[DFU] Uploading firmware...
    V	12:59:36.245	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	12:59:36.319	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	12:59:36.319	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	12:59:36.356	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:36.356	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-00-20-00-00-BA-00-F7-3B
    A	12:59:36.357	[DFU] Checksum received (Offset = 8192, CRC = 3BF700BA)
    V	12:59:36.357	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	12:59:36.357	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	12:59:36.385	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:36.552	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    A	12:59:36.552	[DFU] Data object executed
    V	12:59:36.552	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	12:59:36.552	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:36.579	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:36.579	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    A	12:59:36.579	[DFU] Data object (3/117) created
    D	12:59:36.579	[DFU] wait(400)
    A	12:59:36.981	[DFU] Uploading firmware...
    V	12:59:36.981	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	12:59:37.053	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	12:59:37.054	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    I	12:59:37.105	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:37.106	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-03-01-00-30-00-00-AC-76-E2-39
    A	12:59:37.106	[DFU] Checksum received (Offset = 12288, CRC = 39E276AC)
    V	12:59:37.107	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 04
    D	12:59:37.107	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x04, WRITE_TYPE_DEFAULT)
    I	12:59:37.135	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    I	12:59:37.290	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-04-01
    A	12:59:37.290	[DFU] Data object executed
    V	12:59:37.290	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 01-02-00-10-00-00
    D	12:59:37.290	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x01-02-00-10-00-00, WRITE_TYPE_DEFAULT)
    I	12:59:37.332	[DFU] Notification received from 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 60-01-01
    I	12:59:37.333	[DFU] Data written to 8ec90001-f315-4f60-9fb8-838830daea50
    A	12:59:37.333	[DFU] Data object (4/117) created
    D	12:59:37.333	[DFU] wait(400)
    A	12:59:37.734	[DFU] Uploading firmware...
    V	12:59:37.735	[DFU] Sending firmware to characteristic 8ec90002-f315-4f60-9fb8-838830daea50...
    V	12:59:37.814	[DFU] Writing to characteristic 8ec90001-f315-4f60-9fb8-838830daea50, value (0x): 03
    D	12:59:37.814	[DFU] gatt.writeCharacteristic(8ec90001-f315-4f60-9fb8-838830daea50, value=0x03, WRITE_TYPE_DEFAULT)
    D	12:59:43.546	[Callback] Connection state changed with status: 8 and new state: DISCONNECTED (0)
    E	12:59:43.547	Error 8 (0x8): GATT CONN TIMEOUT
    I	12:59:43.547	Disconnected
    E	12:59:43.557	[DFU] Error (0x85): GATT ERROR
    V	12:59:43.558	[DFU] Disconnecting...
    D	12:59:43.597	[DFU] gatt.disconnect()
    I	12:59:43.597	[DFU] Disconnected
    D	12:59:43.597	[DFU] gatt.refresh() (hidden)
    D	12:59:43.597	[DFU] gatt.disconnect()
    D	12:59:43.605	[DFU] gatt.close()
    D	12:59:43.605	[DFU] wait(600)
    D	12:59:43.605	[Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
    D	12:59:43.617	[DFU] [Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
    D	12:59:44.205	gatt.close()
    D	12:59:44.215	wait(200)
    V	12:59:44.418	Connecting to F9:3E:58:83:16:E0...
    D	12:59:44.418	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
    

  • I saw that the Offset of the packet 2 is still 4096 and therefore from packet 1, here is the error:

  • Hi Einar. The falsh store and read write from the external falsh has to be added in a lot of functiomns like hash and crc32 calc and image copy but at the end it's working now.

    I will add some features to trigger the FW update without downloading over the BLE DFU, becuase the goal was to reaceiv ethe APP over BLE Mesh (system bootloader) and use the same crypto features like the point to point DFU. But now it's working to flash the application from the external QSPI so the entry pont is where the image copy function is used.

  • Hi
    the complete handling with the QSPI functions between is working now.

    If I receive ethe data for the init package directly to the QSPI and not over the APP. I have to read this data for the size and information for the encryption. This information is stored in the dat file. the bin file contains the application, the dat file the information for this.

    Which function is used to read this dat file? Then I can read this from the external flash with the same function.

    Thank you

  • Hello,

    Einar is out of office for a few weeks.

    Perhaps I misunderstand, but there is no function reading the dat file directly, but since the dat file contains the information from the init packet, the init packet is validated in nrf_dfu_validation_prevalidate() I think. This is found in nrf_dfu_validation.c, and is typically triggered by nrf_dfu_validation_init_cmd_execute().

    Best regards,

    Edvin

  • Hi Edvin

    Yes I was digging and found this function aswell. What I don't understand is where the data in m_packet is written, beacuse in may case the dat file is stored in the external flash and I have to point on this region and read the dat file from the external falsh. The question is where is this happing in BLE standart DFU? Then I can interchange this function.

    There is if (m_packet.has_signed_command) which I have to set before, but I can't find this code where will be set on or off.

    nrf_dfu_result_t nrf_dfu_validation_prevalidate(void)
    {
        nrf_dfu_result_t                 ret_val        = NRF_DFU_RES_CODE_SUCCESS;
        dfu_command_t            const * p_command      = &m_packet.command;
        dfu_signature_type_t             signature_type = DFU_SIGNATURE_TYPE_MIN;
        uint8_t                  const * p_signature    = NULL;
        uint32_t                         signature_len  = 0;
    
        if (m_packet.has_signed_command)
        {
            p_command      = &m_packet.signed_command.command;
            signature_type =  m_packet.signed_command.signature_type;
            p_signature    =  m_packet.signed_command.signature.bytes;
            signature_len  =  m_packet.signed_command.signature.size;
        }
    
        // Validate signature.
        if (signature_required(p_command->init.type))
        {
            ret_val = nrf_dfu_validation_signature_check(signature_type,
                                                         p_signature,
                                                         signature_len,
                                                         m_init_packet_data_ptr,
                                                         m_init_packet_data_len);
        }

    Is this the function where I have to read from the external flash?

    pb_istream_from_buffer in the pb_decode.c

    /** @brief Function for decoding byte stream into variable.
     *
     *  @retval true   If the stored init command was successfully decoded.
     *  @retval false  If there was no stored init command, or the decoding failed.
     */
    static bool stored_init_cmd_decode(void)
    {
        m_pb_stream = pb_istream_from_buffer(s_dfu_settings.init_command,
                                             s_dfu_settings.progress.command_size);
    

    The data from the flash has to be stored here I guess, correct?

    m_pb_stream = pb_istream_from_buffer(s_dfu_settings.init_command, s_dfu_settings.progress.command_size);

    and then call the function nrf_dfu_validation_init with the call to stored_init_cmd_decode)

  • Hello,

    The original secure bootloader (both uart and BLE) is a passive bootloader. This means that this event is triggered by the "DFU master", which is typically a mobile phone (BLE) or another MCU on the board (uart). 

    The callstack to this is quite long, but I managed to trace it back to on_write() in nrf_dfu_ble.c.

    Something like:

    on_write()
    nrf_dfu_req_handler_on_req()
    nrf_dfu_req_handler_req()
    nrf_dfu_req_handler_req_process()
    nrf_dfu_obj_op()
    nrf_dfu_command_req()
    on_cmd_obj_execute_request()
    nrf_dfu_validation_init_cmd_execute()
    

    So this is triggered by the DFU master, where it sends the init packet, containing some metadata on the DFU image (size, CRC, and the signature). And then it sends the execute command for that init packet.

    However, if you already have this packet stored when you restart into DFU mode, you need to do some check to decide whether to check the stored data. If that check passes, it means that you can do this immediately after that. Normally we use the dfu_enter parameter in nrf_bootloader.c to decide whether to enter DFU mode or not. You can check some of the typical checks in dfu_enter_check(). The NRF_BL_DFU_ENTER_METHOD_GPREGRET method is great to use if you want to set it from the application. Then you write a value to the GPREGRET register before you reset the device using NVIC_SystemReset(). Then this register will be checked from the bootloader, and this will tell it to enter DFU mode, or in your case to check the init packet stored on the external flash chip.

    If you are in this state, and the init packet is checked and found valid, then you can proceed to what the nrf_dfu_validation_init_cmd_execute does with:

    nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
                                                         uint32_t * p_data_len)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
    
        if (s_dfu_settings.progress.command_offset != s_dfu_settings.progress.command_size)
        {
            // The object wasn't the right (requested) size.
            NRF_LOG_ERROR("Execute with faulty offset");
            ret_val = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
        }
        else if (m_valid_init_cmd_present)
        {
            *p_dst_data_addr = nrf_dfu_bank1_start_addr();
            ret_val          = update_data_size_get(mp_init, p_data_len);
        }
        else if (stored_init_cmd_decode())
        {
            // Will only get here if init command was received since last reset.
            // An init command should not be written to flash until after it's been checked here.
            ret_val = nrf_dfu_validation_prevalidate(); // ************* You jump in after this ************
    
            *p_dst_data_addr = 0;
            *p_data_len      = 0;
    
            // Get size of binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_size_get(mp_init, p_data_len);
            }
    
            // Get address where to flash the binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_addr_get(mp_init, *p_data_len, p_dst_data_addr);
            }
    
            // Set flag validating the init command.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                m_valid_init_cmd_present = true;
            }
            else
            {
                nrf_dfu_settings_progress_reset();
            }
        }
        else
        {
            NRF_LOG_ERROR("Failed to decode init packet");
            ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
        }
    
        return ret_val;
    }

    (you jump in after line 21, so probably duplicate this function).

    Make sure that the rest of the API in this function works with your QSPI implementation.

    Best regards,

    Edvin

Reply
  • Hello,

    The original secure bootloader (both uart and BLE) is a passive bootloader. This means that this event is triggered by the "DFU master", which is typically a mobile phone (BLE) or another MCU on the board (uart). 

    The callstack to this is quite long, but I managed to trace it back to on_write() in nrf_dfu_ble.c.

    Something like:

    on_write()
    nrf_dfu_req_handler_on_req()
    nrf_dfu_req_handler_req()
    nrf_dfu_req_handler_req_process()
    nrf_dfu_obj_op()
    nrf_dfu_command_req()
    on_cmd_obj_execute_request()
    nrf_dfu_validation_init_cmd_execute()
    

    So this is triggered by the DFU master, where it sends the init packet, containing some metadata on the DFU image (size, CRC, and the signature). And then it sends the execute command for that init packet.

    However, if you already have this packet stored when you restart into DFU mode, you need to do some check to decide whether to check the stored data. If that check passes, it means that you can do this immediately after that. Normally we use the dfu_enter parameter in nrf_bootloader.c to decide whether to enter DFU mode or not. You can check some of the typical checks in dfu_enter_check(). The NRF_BL_DFU_ENTER_METHOD_GPREGRET method is great to use if you want to set it from the application. Then you write a value to the GPREGRET register before you reset the device using NVIC_SystemReset(). Then this register will be checked from the bootloader, and this will tell it to enter DFU mode, or in your case to check the init packet stored on the external flash chip.

    If you are in this state, and the init packet is checked and found valid, then you can proceed to what the nrf_dfu_validation_init_cmd_execute does with:

    nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
                                                         uint32_t * p_data_len)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
    
        if (s_dfu_settings.progress.command_offset != s_dfu_settings.progress.command_size)
        {
            // The object wasn't the right (requested) size.
            NRF_LOG_ERROR("Execute with faulty offset");
            ret_val = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
        }
        else if (m_valid_init_cmd_present)
        {
            *p_dst_data_addr = nrf_dfu_bank1_start_addr();
            ret_val          = update_data_size_get(mp_init, p_data_len);
        }
        else if (stored_init_cmd_decode())
        {
            // Will only get here if init command was received since last reset.
            // An init command should not be written to flash until after it's been checked here.
            ret_val = nrf_dfu_validation_prevalidate(); // ************* You jump in after this ************
    
            *p_dst_data_addr = 0;
            *p_data_len      = 0;
    
            // Get size of binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_size_get(mp_init, p_data_len);
            }
    
            // Get address where to flash the binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_addr_get(mp_init, *p_data_len, p_dst_data_addr);
            }
    
            // Set flag validating the init command.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                m_valid_init_cmd_present = true;
            }
            else
            {
                nrf_dfu_settings_progress_reset();
            }
        }
        else
        {
            NRF_LOG_ERROR("Failed to decode init packet");
            ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
        }
    
        return ret_val;
    }

    (you jump in after line 21, so probably duplicate this function).

    Make sure that the rest of the API in this function works with your QSPI implementation.

    Best regards,

    Edvin

Children
  • Hi Edvin

    Thank you for the analysis.

    I will use Bit2 in GPREGRET to indicate that there is a firmware and init package in the external flash.

    in the functiuon nrf_bootloader_init with the function dfu_enter_check the return value will be true.

    In this case I will read the size and data from the external flash to s_dfu_settings.init_command and s_dfu_settings.progress.command_size and call the function stored_init_cmd_decode.

    Then the init package will be decoded and signed as valid.

    After I will call  nrf_dfu_validation_prevalidate.

    The function stored_init_cmd_decode I will call in the dfu_enter_check.

    Now:

    I will jump to nrf_dfu_validation_init_cmd_execute line 21.

    Like I understand call this in a seperate function? (without the if)

    else if (stored_init_cmd_decode())
        {
            // Will only get here if init command was received since last reset.
            // An init command should not be written to flash until after it's been checked here.
            ret_val = nrf_dfu_validation_prevalidate();
    
            *p_dst_data_addr = 0;
            *p_data_len      = 0;
    
            // Get size of binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_size_get(mp_init, p_data_len);
            }
    
            // Get address where to flash the binary.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                ret_val = update_data_addr_get(mp_init, *p_data_len, p_dst_data_addr);
            }
    
            // Set flag validating the init command.
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                m_valid_init_cmd_present = true;
            }
            else
            {
                nrf_dfu_settings_progress_reset();
            }
        }

    This I can implement in the dfu_enter_check aswell? Or where should the code follow later?

    ***************************************************

    dfu_enter will be true and nrf_dfu_req_handler_init will be called.

    Where is the call to update the image from bank1 (my external flash)? Should I call something additional or set some bank1 = valid or something?

    Make sure that the rest of the API in this function works with your QSPI implementation.

    This is working, QSPI flash (bank1) is working with bootloader or application sent with the BLE App from Nordic.

    Thank you so much

  • Dominik Eugster said:
    Like I understand call this in a seperate function? (without the if)

    That was my idea, at least. Because you don't have an external device telling you what to do, this would be the first step if the bootloader has decided to enter DFU mode. 

    After validating the init packet, the next step is to start swapping out the actual application with the new image. We now assume that the application is legit, so the bootloader should then delete the old application from flash, and start receiving the new application. Since you don't have anyone pushing the new application to the bootloader, you need to make the bootloader read it from the external flash, and place it in it's internal flash. After the entire new application is in flash, in bank 0, I believe you can just reset the device, and the bootloader will discover that there is a new application present, and it will validate this one. 

    So in all, the steps you are bypassing is the "wait and receive init packet" followed by "validate the init packet command", in addition to "wait and receive full application" and "application transfer complete -> reset" command. 

    The bootloader has the possibility to use dual bank. In which case, it can receive the new application before deleting the old one. However, if the new application is larger than half of the old application, it will delete the bank0, and store it directly there. However, when the bootloader uses BLE to receive the image, it doesn't risk bricking the device if the transfer fails, or if the image following the valid init packet is actually invalid. So it may be a good idea to try to validate the actual image while it is still stored in the external flash before erasing the old application (because I assume that it is the application that put it in the QSPI in the first place). 

    I am not 100% sure how this is done by default, but you can look for a place that validates the image in bank 1, and try to use this on the image in the QSPI flash.

    Best regards,

    Edvin

  • Hi Edvin

    Since the QSPI flash support is integrated in the original bootloader I use again the 2 image bootloader. I use bank1 for QSPI flash, bank0 is internal. I was debugging all and it is working like this (triggered by BLE over the Nordic App)

    1. Bootloader starts. BLE DFU with new App -> init packet and new App will be checked and placed in bank 0, application starts and is running.

    2. During running application do again BLE DFU. Booloader is starting, checking init package and Application, recognize that bank0 is used, download the new application over QSP tothe external flash, validate it and if all is valid copy the image from external flash to internal and start the application.

    Everything fine and running.

    Now: init package and application (dat and bin file) will be placed by custom made app in the external flash. The application will check own CRC, if all is valid, GPREGRET  will be triggered and chip restart will be done.

    Then bootloader check GPREGRET, now there is a new init package in the external flash, call nrf_dfu_validation_init_cmd_execute. I can use the original function because first if is true and m_valid_init_cmd_present will be false and so it will call the if with stored_init_cmd_decode

    nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
                                                         uint32_t * p_data_len)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
    
        if (s_dfu_settings.progress.command_offset != s_dfu_settings.progress.command_size)
        {
            // The object wasn't the right (requested) size.
            NRF_LOG_ERROR("Execute with faulty offset");
            ret_val = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
        }
        else if (m_valid_init_cmd_present)
        {
            *p_dst_data_addr = nrf_dfu_bank1_start_addr();
            ret_val          = update_data_size_get(mp_init, p_data_len);
        }
        else if (stored_init_cmd_decode())

    After this in the nrf_bootloader_init there is the call for nrf_bootloader_fw_activate which should do the rest. Or am I missing something?

    I will try tomorrow

  • That sounds about right to me. You may want to test this with the debug bootloader, so that you can check the logs from the bootloader. Or you can enable the logs in your bootloader, but that probably requires you to change the bootloader's start address as well.

    Best regards,

    Edvin

  • Hi Edvin

    I did the debugging, here the esults:

    in the dfu_enter_check I enter with an additional flag of QSPI data is ready, working.

    Then I call this function:

    if (ret_val == NRF_SUCCESS)
        {
            init_pkg_size = (uint32_t) (init_command_buffer[0] | (init_command_buffer[1] << 8) | 
                                        (init_command_buffer[2] << 16) | (init_command_buffer[3] << 24));
            ret_val = nrf_dfu_validation_init_cmd_create(init_pkg_size);
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                //copy the data in the init package target
                //cut the size (first 4 bytes)
                ret_val = nrf_dfu_validation_init_cmd_append(&init_command_buffer[FW_UPDATE_EXTERNAL_FLASH_INIT_PACKAGE_SIZE_VARIABLE], init_pkg_size);
                if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
                {
                    // Execute a previously received init packed. Subsequent executes will have no effect.
                    ret_val = nrf_dfu_validation_init_cmd_execute(&firmware_start_addr, &firmware_size);
    
                   // Execute a previously received init packed. Subsequent executes will have no effect.
            		if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            		{
                        if (nrf_dfu_validation_activation_prepare(firmware_start_addr, firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
                        {
                            NRF_LOG_INFO("Postvalidation successful.");
                        }
            		}
                }
            }
        }

    ret_val is success, looks good.

    Then should I reset the chip or what should I do? Reinit?

    Because nothing is happening, maybe a function is missing which normaly will be triggered over the BLE DFU which is now missing? Maybe app_activate is missing because call is before dfu_enter check?

    Thank you

Related