BLE DFU mode on RAK4630 - DFU never completes - stuck at 100%

I am attempting to enable DFU over BLE on RAK4630, allowing OTA firmware upgrades without the need to plug in USB cable. I also need BLE UART to communicate with the module remotely.

I have enabled both characteristics in the sketch:
At the beginning of the sketch, I declare the DFU and UART:

#include <arduino.h>
#include <bluefruit.h>
BLEUart bleuart;
BLEDfu bledfu;
// ... [other initialization stuff here ]

void setup()
{
// Configure Bluefruit per DFU and UART examples:
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
 Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16,16);
 Bluefruit.begin(1, 0);
 Bluefruit.setTxPower(4);
 Bluefruit.setName("RAKTEST1");
 Serial.println("Setting BLE pin to 123456");
 Bluefruit.Security.setPIN("123456");

 
 Bluefruit.Periph.setConnectCallback(connect_callback);
 Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
 
// Start up both DFU and UART:
 bledfu.begin();
 bleuart.begin();

// Advertise BLE:
 Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
 Bluefruit.Advertising.addTxPower();
 Bluefruit.Advertising.addName();
 Bluefruit.Advertising.restartOnDisconnect(true);
 Bluefruit.Advertising.setInterval(32,244);
 Bluefruit.Advertising.setFastTimeout(30);
 Bluefruit.Advertising.start(0);
//... more setup()...
}

After uploading the sketch via USB port, I remove and re-pair the device on Android smartphone. Then I use Nordic DFU app (latest version) to find the appropriate .ZIP file and begin update.
I get the following:
:white_check_mark: Bootloader Enabled
:white_check_mark: DFU initialized
:arrow_forward: Uploading… 100% (4.9 kB/s)
:arrow_forward: Completed

It gets stuck at 100% uploading, but never gets to the “Completed” line, and the RAK baseboard has the following lights:
GREEN: flashing fast (not throbbing)
BLUE: slow throbbing (fade in/out)

After removing power to the RAK4630 and re-connecting, it is in DFU mode (different device recognized by Windows, and opens File Explorer to browse immediately).

Update: I tested using the DFU example from Github but it does the same thing. It stops at 100% but never goes to “:white_check_mark: Firmware Upload”. If I try to reset the board (press button or pull USB cable) after progress reaches 100%, it boots in DFU mode (Green LED pulsing slow), requiring flash of firmware via USB again.

I have left it for at least 10 minutes after 100% is reached, with no success.

Any ideas on what I did wrong?
Thanks!

It would be very helpful if the unit could be placed in DFU mode from a command sent over the UART. In this way I could enact some measure of security to prevent end-user from entering DFU without permission. I.e. send a command like “DFU_MODE [password]”.

I tried to send a UART command to enable DFU, by executing bledfu.begin() when the command was received.
BLEdfu is instantiated at beginning of sketch, but I don’t call bledfu.begin() until the magic “Enter DFU” command is received via BLE UART.

However, this doesn’t work. The NRF DFU software gets stuck at “Initializing DFU…” and doesn’t progress further. Lights on RAK4630 baseboard are off (not flashing)
:white_check_mark: Bootloader enabled
:arrow_forward: Initializing DFU…
…

Would I instead need to set a flag, then reboot the RAK and only initialize DFU at reboot? If so, would the user need to un-pair and re-pair their phone to access the DFU mode?

Thank you!

	NRF_POWER->GPREGRET = 0xA8; // 0xA8 OTA, 0x4e Serial, 0x57 UF2
	NVIC_SystemReset();			// or sd_nvic_SystemReset();

0xA8 for OTA DFU
0x4e for bootloader mode
0x57 for UF2 bootloader mode

1 Like

Thanks @beegee , can you help me understand when to use these commands? Do I set these commands when receiving the BLE UART command to enter DFU mode? or something else? and also why the DFU example did not work when copied directly from github repo?
Thank you!

I am using this to set the device manually into the different modes.
Normally,
bootloader mode (0x4e) would be forced by the uploader from Arduino over USB
UF2 bootloader mode (0x57) would be forced by double push reset by the bootloader
OTA DFU mode (0xA8) is initiated by the Bluefruit library if you enable the OTA-DFU characteristic:

/** OTA DFU service */
BLEDfu ble_dfu;

	// Start the DFU service
	ble_dfu.begin();

You can have a look at my WisBlock-API-V2 BLE initialization where I enable OTA DFU, UART, Device Info and a custom BLE characteristic.

1 Like

Hi Bernd!

I am struggling with the same issue, but it get stuck even earlier. It is definitely different on Android and iOS. I tried it with the Nordic DFU Updater App and with the Connect App.
On Android (DFU App) it connects to the RAK4631, puts it into DFU Mode and starts to upload in the Initialize DFU section. When it tries to upload the FW it immediately gives an error. The green LED is then dimming fast, not flashing and the blue LED goes off. I then need to flash the FW via USB.
On iOS with the DFU App it even doesn’t come to the Initialize DFU section (part2 of the process).
When I try it with the Connect App it says Error 3 no write permit. Do we need to set open permission with the ble_dfu class?
I also tried variuos settings, but none of them worked. Would be good to suggest the recommended settings for nordic apps.

My second question would be, if it is possible to implement the secure dfu mode and if the bootloader supports that, as the BLEDfu class shows up as Legacy DFU Service. Some applications out there, which I want to use, are on SecDFU only.

Thanks for feedback
BR
Rainer

Can you check the bootloader on the RAK4631?

Double push reset
Open the new drive that pops up
Open the file INFO_UF2.TXT
Check the content. The latest bootloader version is

UF2 Bootloader 0.4.3
Model: WisBlock RAK4631 Board
Board-ID: WisBlock-RAK4631-Board
Date: May 20 2023
Ver: 0.4.3
SoftDevice: S140 6.1.1

If you don’t have this bootloader, update the bootloader and retry.

A failed OTA DFU leaves the device without firmware, so the dimming on/off green LED is normal, because the device is stuck in bootloader mode.

Hi Bernd !

Thanks for the fast Reply!! It works now. Sure I have the latest bootloader running.
The trick was to start ble_dfu first and then start ble_dis. I thought I had this tested already, but now it works on Android and iOS with the Connect App:

ble_dfu.begin();	
ble_dis.begin();