Firmware update¶
Replace the BNO08x's SH-2 firmware in the field through its bootloader, with an image you supply.
Use an image from CEVA for your exact part
A wrong or interrupted image leaves the hub in the bootloader. Keep BOOTN on a GPIO so you can always re-enter it, keep the supply stable during the transfer, and check that the image's part number matches your part.
What the bootloader needs¶
- BOOTN low at reset. The bootloader samples BOOTN with PS0 and PS1 when NRST rises. Wire BOOTN to a GPIO (with its 10 kΩ pull-up) and NRST to another.
- I2C, SPI or UART. The bootloader uses the interface the PS pins select; UART-RVC has no bootloader mode, so
the DFU calls fail with
SH2_ERR_BAD_PARAMon aUARTRVCport. - A different I2C address. Over I2C the bootloader answers at
0x28(SA0 low) or0x29(SA0 high), not0x4A/0x4B(datasheet section 1.4). Give your I2C port the optionalGetI2cAddress()andSetI2cAddress()hooks (Porting): the DFU calls then switch it toBootloaderI2cAddress()of its address (same SA0 bit) for the transfer and restore the address afterwards, also when the transfer fails. A port without the hooks must talk to the bootloader address itself. - A vendor image. CEVA supplies BNO08x firmware as an HcBin image with metadata (
FW-Format,SW-Part-Number). The image compiled in fromsrc/dfu/firmware-bno.cis a 64-byte stub that the driver refuses.
Update from memory¶
int update_firmware(MyI2c& bus, const uint8_t* image, uint32_t size) {
BNO085<MyI2c> imu(bus);
DfuMemoryImage fw{};
fw.data = image;
fw.length = size;
fw.format = "BNO_V1"; // FW-Format of the vendor image
fw.partNumber = "1000-3608"; // SW-Part-Number of the vendor image
DfuOptions options{};
options.progress = [](const DfuProgress& p) {
std::printf("%u / %u bytes\n", static_cast<unsigned>(p.bytesSent),
static_cast<unsigned>(p.totalBytes));
};
// BOOTN low across a reset, transfer, then BOOTN high and reset into the application.
const int status = imu.RunDfuFromMemory(fw, options);
if (status != SH2_OK) {
return status;
}
return imu.Begin() ? SH2_OK : imu.GetLastError();
}
RunDfuFromMemory() does the whole sequence and returns SH2_OK (0) or a negative SH-2 code:
- Enter the bootloader.
EnterBootloader(10, 50): close any open session, open the port, assert BOOTN, hold NRST low 10 ms, wait 94 ms (RESET_STARTUP_MS), release BOOTN, wait 50 ms. - Check the image.
FW-Formatmust beBNO_V1andSW-Part-Numbera known part (or the one you require), and the image at least 1024 bytes; otherwiseSH2_ERR_BAD_PARAMbefore anything is sent. - Send the size. The application length as 4 bytes big-endian plus CRC-16, then the packet length (1 to 64
bytes) plus CRC-16. The bootloader acknowledges each with
s. - Send the image. Packets of up to 64 bytes, each with a CRC-16 (CCITT, polynomial 0x1021, initial value
0xFFFF), each acknowledged; up to 5 attempts and 100 ms per packet.
options.progressruns after each one. - Reboot.
ExitBootloaderAndReboot(2, 100): BOOTN high, NRST low 2 ms, wait 94 ms plus 100 ms. Then callBegin()as usual.
Options¶
DfuOptions field |
Default | Effect |
|---|---|---|
requireFormatMatch |
true |
Check the image's FW-Format against requiredFormat |
requiredFormat |
"BNO_V1" |
Expected format |
requirePartNumber |
true |
Check SW-Part-Number against requiredPartNumber, or, when that is null, against the known part numbers 1000-3608, 1000-3676, 1000-4148, 1000-4563 |
requiredPartNumber |
nullptr |
Exact part number to require |
packetLenOverride |
0 | Packet length 1 to 64; 0 uses the image's preference, capped at 64 |
progress |
empty | Called with 0 bytes before the first packet, then after each packet |
DfuMemoryImage describes a raw image in memory: data, length, format, partNumber and an optional
preferredPacketLen. For an image you stream from storage, implement the HcBin_t function table
(src/dfu/HcBin.h) and call DfuWithOptions(image, options) between the bootloader calls.
Step by step¶
Call the pieces yourself when you need to do something between them:
| Call | Does |
|---|---|
EnterBootloader(resetLowMs = 10, settleMs = 50) |
BOOTN + reset sequence above; false on a UARTRVC port or during a transfer |
DfuFromMemory(image, options) |
Steps 2 to 4 from a DfuMemoryImage, at the bootloader I2C address |
DfuWithOptions(hcbin, options) / Dfu(hcbin) |
Steps 2 to 4 from any HcBin_t; Dfu() uses the default options |
ExitBootloaderAndReboot(resetLowMs = 2, settleMs = 100) |
BOOTN released, reset, wait |
During the transfer GetState() is DfuInProgress and Close() is refused. A transfer that starts while an SH-2
session is open closes the session first.
Next¶
The dfu_update and dfu_workflow_test ESP32 apps run this on hardware;
Hardware has the BOOTN and NRST wiring.