Skip to content

Commit

Permalink
STM32 DFU: more improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelbl committed Dec 26, 2024
1 parent 7eda016 commit af728cf
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
44 changes: 27 additions & 17 deletions examples/stm_dfu/src/main/java/net/codecrete/usb/dfu/DFUDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,27 @@ public void close() {
usbDevice.close();
}

/**
* Waits until the device disconnects.
* <p>
* Disconnection is a side effect of leaving DFU mode.
* </p>
* <p>
* If the device does not disconnect after 5 seconds,
* an exception will be thrown.
* </p>
*/
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.
*/
Expand Down Expand Up @@ -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];
Expand All @@ -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;
}
Expand Down Expand Up @@ -247,7 +255,7 @@ public void download(byte[] firmware) {
transaction += 1;
}

exitDownloadMode();
exitMode();
}

/**
Expand Down Expand Up @@ -327,7 +335,7 @@ private Page findPage(int address) {
return Segment.findPage(segments, address);
}

private void exitDownloadMode() {
private void exitMode() {
abort();

var status = getStatus();
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,47 @@
/**
* DFU request.
* <p>
* See USB Device Class Specification for Device Firmware Upgrade, version 1.1.
* See ST Microelectronics, application note AN3156.
* </p>
*/
public enum DFURequest {
/**
* Requests the device to leave DFU mode and enter the application.
* <p>
* 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.
* </p>
*/
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
}

0 comments on commit af728cf

Please sign in to comment.