STM32 DFU protocol DFU_UPLOAD problem
Hello,
I am trying to implement the DFU protocol in an Android app. I am following AN3156.
I am using UsbDeviceConnection class for the control transfer in android.
I am able to write to the memory to any address using the routines described in AN3156 (using command DFU_DNLOAD).
I am NOT able to read from memory from a specific address using command DFU_UPLOAD. I am only able to read from the very first address of flash memory, whose pointer is by default set to it (0x08000000). For some reason, when running the setAddressPointer routine, the controlTransfer method then returns -1 (USB communication fails). This routine uses command DFU_DNLOAD to set the address pointer.
My code is rather hard to follow since it uses multiple functions but I will post it anyway. I can provide any clarification of it of course. But it essencially just follows the procedures in AN3156, regarding the IDLE state, and DFU_GETSTATUS command. And since those routines are common, I created functions.
So, the problem is in function readBlock(). if I comment out the setAddressPointer, it reads successfully from the default address 0x08000000 as I said earlier. But when invoke this routine to set the address (which, as I said earlier, works fine for writting blocks to a specific address (DFU_DNLOAD command)), it messes up the USB communication itself. The controlTransfer does returns an error when DFU_UPLOAD command is sent.
Any help would be appreciated.
private final static int USB_DIR_IN = 0x80;
private final static int DFU_RequestType = 0x21; // '2' => Class request ; '1' => to interface
private final static int STATE_IDLE = 0x00;
private final static int STATE_DFU_IDLE = 0x02;
private final static int STATE_DFU_UPLOAD_IDLE = 0x09;
private final static int STATE_DFU_ERROR = 0x0A;
private final static int STATE_DFU_UPLOAD_BUSY = 0x92;
private final static int DFU_DNLOAD = 0x01;
private final static int DFU_UPLOAD = 0x02;
private final static int DFU_GETSTATUS = 0x03;
private final static int DFU_CLRSTATUS = 0x04;
private final static int DFU_GETSTATE = 0x05;
public void readBlock(int address, byte[] block, int blockNumber) throws Exception {
DfuStatus dfuStatus = new DfuStatus();
clearWaitIDLE(dfuStatus);
//set address for the first block written
if (0 == blockNumber) {
Log.i(TAG, "reading address: 0x" + Integer.toHexString(address));
setAddressPointer(address);
}
clearWaitIDLE(dfuStatus);
upload(block, block.length, (blockNumber + 2));
//executeVerifyStatus(dfuStatus, "block read");
clearWaitIDLE(dfuStatus);
}
//execute and verify action using getStatus(). arguments: where the error occurs (for what operation)
private void executeVerifyStatus(DfuStatus dfuStatus, String operation) throws Exception {
getStatus(dfuStatus); // to execute
if (dfuStatus.bState != STATE_DFU_DOWNLOAD_BUSY) {
throw new Exception("error on " + operation + " , execution failed (dfuBUSY not returned)");
}
getStatus(dfuStatus); // to verify action
if (dfuStatus.bState == STATE_DFU_ERROR) {
throw new Exception("error on " + operation + " , verification failed (dfuERROR)");
}
}
// Clears status and waits for DFU_IDLE status. useful to crear DFU_ERROR status.
private void clearWaitIDLE(DfuStatus dfuStatus) throws Exception {
while (dfuStatus.bState != STATE_DFU_IDLE) {
clearStatus();
getStatus(dfuStatus);
}
}
private void getStatus(DfuStatus status) throws Exception {
byte[] buffer = new byte[6];
int length = usb.controlTransfer(DFU_RequestType | USB_DIR_IN, DFU_GETSTATUS, 0, 0, buffer, 6, 500);
if (length < 0) {
throw new Exception("USB Failed during getStatus");
}
status.bStatus = buffer[0]; // state during request
status.bState = buffer[4]; // state after request
status.bwPollTimeout = (buffer[3] & 0xFF) << 16;
status.bwPollTimeout |= (buffer[2] & 0xFF) << 8;
status.bwPollTimeout |= (buffer[1] & 0xFF);
}
private void clearStatus() throws Exception {
int length = usb.controlTransfer(DFU_RequestType, DFU_CLRSTATUS, 0, 0, null, 0, 0);
if (length < 0) {
throw new Exception("USB Failed during clearStatus");
}
}
private void upload(byte[] data, int length, int blockNum) throws Exception {
int len = usb.controlTransfer(DFU_RequestType | USB_DIR_IN, DFU_UPLOAD, blockNum, 0, data, length, 100);
if (len < 0) {
throw new Exception("USB comm failed during upload");
}
}
