Flashing firmware OTA for nRF Connect SDK nRF52840

Hi,

I am trying to reproduce DFU functionality from the nRF Connect for Android app.

I want to be able to flash my firmware OTA from my app.

The problem I am getting is that sometimes it sends the packages and sometimes it doesn't, but when it works after that I cannot see that few seconds of validation that happened in the nRF app.

It seems like all the packages are sent, but it doesn't switch the firmware.

Maybe someone did it before me, it seems like a prevalent thing.

I am using Xamarin Forms so it's all in C#. Here is my code for that.

private async Task<bool> FlashFirmware(IDevice device)
{
    // Get the firmware binary data
    var firmwareData = await PickFirmwareFileAsync();

    if (firmwareData == null || firmwareData.Length == 0)
    {
        SHFTLOG.Instance.Error("BLEM", "Invalid firmware data.");
        return false;
    }

    try
    {
        if (device == null)
        {
            SHFTLOG.Instance.Error("BLEM", "Invalid device.");
            return false;
        }

        SHFTLOG.Instance.Debug("BLEM", "Starting firmware flash process for device " + device.Id);

        // DFU service and characteristic UUIDs
        string dfuServiceUUID = "8d53dc1d-1db7-4cd3-868b-8a527460aa84";
        string dfuCharacteristicUUID = "da2e7828-fbce-4e01-ae9e-261174997c48";

        var service = await device.GetServiceAsync(Guid.Parse(dfuServiceUUID));
        if (service == null)
        {
            SHFTLOG.Instance.Error("BLEM", "DFU service not found on device.");
            return false;
        }

        var characteristic = await service.GetCharacteristicAsync(Guid.Parse(dfuCharacteristicUUID));
        if (characteristic == null)
        {
            SHFTLOG.Instance.Error("BLEM", "DFU characteristic not found on device.");
            return false;
        }

        // Initialize DFU process
        byte[] initPacket = new byte[] { 0x01, 0x04 }; // Example initialization packet
        await characteristic.WriteAsync(initPacket);
        SHFTLOG.Instance.Debug("BLEM", "Sent DFU initialization packet.");

        // Write firmware data in chunks
        int chunkSize = 20; // Max BLE payload size
        for (int i = 0; i < firmwareData.Length; i += chunkSize)
        {
            int bytesToSend = Math.Min(chunkSize, firmwareData.Length - i);
            byte[] chunk = new byte[bytesToSend];
            Array.Copy(firmwareData, i, chunk, 0, bytesToSend);

            await characteristic.WriteAsync(chunk);
            SHFTLOG.Instance.Debug("BLEM", $"Sent firmware chunk {i / chunkSize + 1}");
        }

        // Finalize DFU process
        byte[] finalizePacket = new byte[] { 0x01, 0x05 }; // Example finalize packet
        await characteristic.WriteAsync(finalizePacket);
        SHFTLOG.Instance.Debug("BLEM", "Sent DFU finalize packet.");

        byte[] validateDfuCommand = new byte[] { 0x03 };
        await characteristic.WriteAsync(validateDfuCommand);

        // Wait for confirmation
        var (responseData, resultCode) = await characteristic.ReadAsync();

        if (responseData[0] == 0x01 && resultCode == 0)  // Assuming 0 resultCode indicates success
        {
            Console.WriteLine("DFU completed successfully.");
        }
        else
        {
            Console.WriteLine("DFU failed. Result code: " + resultCode);
        }

        SHFTLOG.Instance.Debug("BLEM", "Firmware flash process completed successfully.");
        return true;
    }
    catch (Exception ex)
    {
        SHFTLOG.Instance.Error("BLEM", "Exception during firmware flash: " + ex.Message);
        return false;
    }
}

Parents
  • Hello,

    The problem I am getting is that sometimes it sends the packages and sometimes it doesn't

    We don't have any support for C#, or any tools or examples using it that shows how it should work, so unfortunately I don't know why it is not working. If you have questions on the protocol, I might be able to help, but if the issue is that the C# application is not working as intended, then I don't know what the issue might be.

    Perhaps these questions can help you along the way:

    Does your application find the DFU target device?

    Is it able to connect to it?

    When you say it is not sending packets, perhaps you are writing them too fast?

    Do you check the return values when trying to send a packet? Does it indicate that something is wrong when the packets are not sent?

    Best regards,

    Edvin

  • Hi Edvin,

    thank you for your answer.

    Could you maybe help me with understanding the protocol, especially validating. After sending the packets, I try to send a validation packet.

    I can see in the nRF Connect for Android app while uploading my firmware code is still working (blinking LED), but when it shows validating it is off (so I assume the program is stopped) and then the new program works.

    Meanwhile in my app after uploading it doesn't take to verify and sometimes it shows an error that this characteristic doesn't support read. (when I try to read validation).

Reply
  • Hi Edvin,

    thank you for your answer.

    Could you maybe help me with understanding the protocol, especially validating. After sending the packets, I try to send a validation packet.

    I can see in the nRF Connect for Android app while uploading my firmware code is still working (blinking LED), but when it shows validating it is off (so I assume the program is stopped) and then the new program works.

    Meanwhile in my app after uploading it doesn't take to verify and sometimes it shows an error that this characteristic doesn't support read. (when I try to read validation).

Children
  • What characteristic?

    You are talking about the LED behavior. I am not sure which one you refer to. When performing a DFU, the application will reset the device, and it will enter DFU mode in the bootloader. When this happens, there is a different LED pattern. After everything is complete (upload/download, validation and swapping) the new application is started. Which of these are we talking about?

    Best regards,

    Edvin

  • I will try to explain it step by step what problems I get Slight smile:)

    I have a custom board using nRF52840 and want to flash firmware to its board using Xamarin Forms.

    I have an LED mounted on this board that blinks with different patterns when connected to the BlueTooth device or sends data, advertising, low battery, etc.

    As I know we need to connect to the device first and then when we find the DFU characteristic we can send data to that one. I can also see in the example of nRF Connect for Android that after sending all the data, the code is verified and replaced with a new one.

    What I can also see, is when I upload the code using the nRF app when the packets are sent, my LED still blinks, indicating e.g. battery level, meaning the old code is still working and showing the status even though there packets are being uploaded to the board. However, when the validating is performed, it looks like the board goes off as my LED doesn't work. After that, I can see the new code working.

    So I can understand from that, that "validating" checks and replaces the code.

    However, in my case with C#, validating takes no time, and there is no time when I can see the LED not working, which would mean that the code is not replaced.

    I tried to replicate exactly the behavior from the nRF app, but apparently something is different. Also, I can see that the characteristic has no response, but we need to validate the flash so how do we do that?

    Here I put a screenshot from the nRF app to show you the service and characteristics I am working on, I hope you can help me with understanding that.

    Best Regards

    Mateusz

  • Try to enable logging in the bootloader, by following step 2 in this exercise:

    https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-8-bootloaders-and-dfu-fota/topic/exercise-1-dfu-over-uart/

    What does the log say when you try to execute the DFU from your C# application?

    BR,
    Edvin

Related