Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

DFU fail with SDK15 bootloader

Hi

We are using a slightly modified (but fully compatible signed bootloader) in out product. On the application side we have a C# implementation of the DFU protocol that may work under iOS/Android with Xamarin or on a desktop PC with a BLE Dongle. With the SDK14 bootloader this worked quite well.

Last week we integrated the SDK15 in the product to get support for faster update performance. The bootloader seems to work properly and with the nRF Connect the update works as expected. With our C# library we randomly experianced that the update process failed because the expected RPN packets from the bootloader are not received.

A investigation with the bootloader log RTT output showed the reason for the issue. In the log "cannot allocate memory buffer!" entries can be found shortly after the process fails. This means that the incoming write request could not be stored in the bootloader and is ignored. I'm not sure how we should handle this issue on the app side.

I guess the reason why this only happens with out DFU library is that we don't use the MTU extention by now. The incoming write packets have all a length of 20 bytes instead of 244 bytes with the nRF Connect. The buffer that is used (nrf_balloc) is set up for packets of 244 bytes. With any allocated 20 bytes block full 224 bytes are wasted. I know that I probably could increase the number of balloc blocks, but how many of these blocks are necessairy?

Is the bootloader of the SDK15 supposed to work with packet size of 20 bytes? Do we need to update our library to use larger packtes?
Regards Adrian
NOTE: Attached to the issue you may find a log file with the error at line 1977.
  • Good morning Adrian,

    The size and number of DFU buffers are determined by MAX_DFU_PKT_LEN and MAX_DFU_BUFFERS respectively (in nrf_dfu_ble.c).

    Taking a look at around line 73 you will see that MAX_DFU_PKT_LEN is set indirectly by specifying the ATT MTU value with NRF_SDH_BLE_GATT_MAX_MTU_SIZE in sdk_config.h.

    MAX_DFU_BUFFERS is adjusted automatically based on MAX_DFU_PKT_LEN (around line 87) in order to accommodate for an entire DFU object in RAM.

    By adjusting NRF_SDH_BLE_GATT_MAX_MTU_SIZE to 23 in the bootloader's sdk_config file the BLE transport will size its buffers to be able to receive one entire DFU (4K) object in RAM .

    I am confident that this will help you solve your issues. Let me know Slight smile

    emdi

  • Hi emdi


    I agree that changing the NRF_SDH_BLE_GATT_MAX_MTU_SIZE would fix the issue, but this would mean that we sacrifice the benefit of high MTU in the new bootloader. In the future we plan to add support in our library for higher MTU to reach the max DFU speed, but compatibility is also an important point. Best case would be to have support for the higher MTU but be compatible with DFU clients that don't set a higher ATT MTU.

    I tested with more buffers (50 buffers of 244 bytes) and the problems are gone and we still have support for higher MTU. But how many buffers would be enough? In theory we would need 205 buffers to be able to keep all packets for one 4k block, but that would cause a ram consumption of 50k only for the buffers.

    A better solution would be that the buffers used for storing the requests would have a dynamic length. Why did you use nrf_balloc and not a heap based solution with malloc and free? Would this cause a higher code size?

    Regards Adrian

  • I see. Well, dynamic memory allocation is somewhat ...risky in embedded systems and we avoid it entirely in nRF5 SDK. This is cleary a scenario where it would have come in handy :) However, I don't how it would impact the code size.

    It's hard to predict how many buffers are needed, there are many variables in the equation. My suggestion is to log the buffer usage and try to tweak (increase) the number of buffers empirically. You can override the automatic configuration of the number of buffers by defining NRF_DFU_BLE_BUFFERS_OVERRIDE and setting NRF_DFU_BLE_BUFFERS to the desired amount of buffers (in sdk_config.h).

    One thing that comes to mind is that, as I understand, you are using a homebrewn library to perform DFU. Said library could retry to transfer an object in case of failure, if it doesn't do that already. Although the bootloader guarantees that when starting to receive a new object all its buffers are available (they are flushed on "data execute" messages), the speed at which packets are received and written to flash is variable even though the connection settings are fixed (retransmissions, timings etc). It might so happen that with the same settings the transfer of an object goes through and another time it doesn't. Clearly this would only apply in case the RAM buffers don't actually accomodate for an entire object, otherwise the transfer will succeed regardless of the speed.

    I hope I was clear enough :)

    Regards,

    emdi

  • Thanks for the details and your thoughts concerning this issue. I think that I can decide what is the best configuration in our use case.

    I've checked the impact of using malloc/free instead of nrf_balloc and the code size is a few hundred bytes less than with nrf_balloc. The tests I've made were quite promising so far.

    I understand the mixed feelings when it comes to using heap in embedded projects. We also try to avoid the usage of heap as the case of fragmentation adds an unpredictable risk factor. In this case I think the risk is a bit smaller than in general. The allocated objects are freed completely after a block is executed. This should prevent the heap from get into fragmented state.

    Anyway I'm not sure which option I'll choose, but I guess both ways would be an acceptable choice.

Related