From af728cfa16cfb8bc656f56f5db5fa7dec052fa18 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Thu, 26 Dec 2024 13:09:08 +0100 Subject: [PATCH] STM32 DFU: more improvements --- .../main/java/net/codecrete/usb/dfu/DFU.java | 1 + .../java/net/codecrete/usb/dfu/DFUDevice.java | 44 ++++++++++++------- .../net/codecrete/usb/dfu/DFURequest.java | 34 +++++++++++++- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java index b3d9d9a..4ca4d2a 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFU.java @@ -64,6 +64,7 @@ public static void main(String[] args) { System.out.println("Firmware successfully downloaded and verified"); device.startApplication(); + device.waitForDisconnect(); System.out.println("DFU mode ended and firmware started"); device.close(); diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java index edaa785..4678e06 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java @@ -133,6 +133,27 @@ public void close() { usbDevice.close(); } + /** + * Waits until the device disconnects. + *

+ * Disconnection is a side effect of leaving DFU mode. + *

+ *

+ * If the device does not disconnect after 5 seconds, + * an exception will be thrown. + *

+ */ + public void waitForDisconnect() { + var waitingTime = 5000; + while (waitingTime > 0 && usbDevice.isConnected()) { + sleep(100); + waitingTime -= 100; + } + + if (usbDevice.isConnected()) + throw new DFUException("Device did not restart (try disconnecting and reconnecting it)"); + } + /** * Clears an error status. */ @@ -170,7 +191,7 @@ public DFUStatus getStatus() { public byte[] read(int address, int length) { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); setAddress(address); - exitDownloadMode(); + exitMode(); expectState(DeviceState.DFU_IDLE, DeviceState.DFU_UPLOAD_IDLE); var result = new byte[length]; @@ -187,20 +208,7 @@ public byte[] read(int address, int length) { blockNum += 1; } - // request zero length chunk to exit out of upload mode - var transfer = createDfuControlTransfer(DFURequest.UPLOAD, blockNum); - usbDevice.controlTransferIn(transfer, 0); - - DFUStatus status; - try { - status = getStatus(); - } catch (DFUException e) { - // Device might respond with an empty response; try again - status = getStatus(); - } - - if (status.state() != DeviceState.DFU_IDLE) - throw new DFUException("Unexpected state after exiting from upload mode"); + exitMode(); return result; } @@ -247,7 +255,7 @@ public void download(byte[] firmware) { transaction += 1; } - exitDownloadMode(); + exitMode(); } /** @@ -327,7 +335,7 @@ private Page findPage(int address) { return Segment.findPage(segments, address); } - private void exitDownloadMode() { + private void exitMode() { abort(); var status = getStatus(); @@ -340,6 +348,8 @@ private void exitDownloadMode() { public void startApplication() { expectState(DeviceState.DFU_IDLE, DeviceState.DFU_DNLOAD_IDLE); + // By sending a zero-length download packet and querying the status, + // the device will leave DFU mode and restart. var transfer = createDfuControlTransfer(DFURequest.DOWNLOAD, 0); usbDevice.controlTransferOut(transfer, null); diff --git a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java index 6c01b98..c927e10 100644 --- a/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java +++ b/examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFURequest.java @@ -10,15 +10,47 @@ /** * DFU request. *

- * See USB Device Class Specification for Device Firmware Upgrade, version 1.1. + * See ST Microelectronics, application note AN3156. *

*/ public enum DFURequest { + /** + * Requests the device to leave DFU mode and enter the application. + *

+ * The Detach request is not meaningful in the case of the bootloader. The bootloader starts + * with a system reset depending on the boot mode configuration settings, which means that + * no other application is running at that time. + *

+ */ DETACH, + /** + * Requests data transfer from Host to the device in order to load them + * into device internal flash memory. Includes also erase commands. + */ DOWNLOAD, + /** + * Requests data transfer from device to Host in order to load content + * of device internal flash memory into a Host file. + */ UPLOAD, + /** + * Requests device to send status report to the Host (including status + * resulting from the last request execution and the state the device + * enters immediately after this request). + */ GET_STATUS, + /** + * Requests device to clear error status and move to next step. + */ CLEAR_STATUS, + /** + * Requests the device to send only the state it enters immediately + * after this request. + */ GET_STATE, + /** + * Requests device to exit the current state/operation and enter idle + * state immediately + */ ABORT }