DFU: multiple fix
* add spaces around operators * remove detach timeout since we reboot immediately after download * reduce polling timeout to increase flashing speed * use block number instead of counting to know which page to flash * remove detach case since this request is only for runtime mode * fix APP_IDLE to DFU_IDLE
This commit is contained in:
parent
3c6fde5822
commit
5e13d19bda
|
@ -42,7 +42,7 @@ static enum dfu_status usb_dfu_status = DFU_STATUS_OK; /**< current DFU status *
|
|||
|
||||
static uint8_t download_data[sizeof(usbd_control_buffer)] = {0}; /**< downloaded data to be programmed in flash */
|
||||
static uint16_t download_length = 0; /**< length of downloaded data */
|
||||
static uint32_t flash_pointer = 0; /**< where the downloaded data should be flashed */
|
||||
static uint32_t download_offset = 0; /**< destination offset of where the downloaded data should be flashed */
|
||||
|
||||
/** USB DFU device descriptor
|
||||
* @note as defined in USB Device Firmware Upgrade specification section 4.2.1
|
||||
|
@ -71,7 +71,7 @@ static const struct usb_dfu_descriptor usb_dfu_functional = {
|
|||
.bLength = sizeof(struct usb_dfu_descriptor), /**< provide own size */
|
||||
.bDescriptorType = DFU_FUNCTIONAL, /**< functional descriptor type */
|
||||
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, /**< this DFU can download and will detach after download (we don't support manifest for simplicity, technically we could) */
|
||||
.wDetachTimeout = 200, /**< maximum time in milliseconds to detach (and reboot) */
|
||||
.wDetachTimeout = 0, /**< maximum time in milliseconds to detach (and reboot) */
|
||||
.wTransferSize = sizeof(usbd_control_buffer), /**< set max transfer size */
|
||||
.bcdDFUVersion = 0x0110, /**< DFU specification version 1.1 used */
|
||||
};
|
||||
|
@ -157,8 +157,7 @@ static void usb_dfu_flash(usbd_device *usbd_dev, struct usb_setup_data *req)
|
|||
(void)usbd_dev; // variable not used
|
||||
(void)req; // variable not used
|
||||
led_off(); // indicate we are processing
|
||||
if (flash_internal_write(flash_pointer, download_data, download_length, true) >= download_length) { // write downloaded data
|
||||
flash_pointer += download_length; // go to next segment
|
||||
if (flash_internal_write((uint32_t)&__application_beginning + download_offset, download_data, download_length, true) >= download_length) { // write downloaded data
|
||||
usb_dfu_state = STATE_DFU_DNLOAD_IDLE; // go back to idle stat to wait for next segment
|
||||
} else { // warn about writing error
|
||||
usb_dfu_status = DFU_STATUS_ERR_WRITE;
|
||||
|
@ -196,47 +195,47 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
|
|||
(void)usbd_dev; // device is not used
|
||||
|
||||
// DFU only requires handling class requests
|
||||
if ((req->bmRequestType & USB_REQ_TYPE_TYPE)!=USB_REQ_TYPE_CLASS) {
|
||||
if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_CLASS) {
|
||||
return USBD_REQ_NOTSUPP;
|
||||
}
|
||||
|
||||
led_off(); // indicate we are processing request
|
||||
int to_return = USBD_REQ_HANDLED; // value to return
|
||||
switch (req->bRequest) {
|
||||
case DFU_DETACH: // USB detach requested
|
||||
*complete = usb_dfu_reset; // reset after reply
|
||||
break;
|
||||
case DFU_DNLOAD: // download firmware on flash
|
||||
if (STATE_DFU_IDLE!=usb_dfu_state && STATE_DFU_DNLOAD_IDLE!=usb_dfu_state) { // wrong start to request download
|
||||
if (STATE_DFU_IDLE != usb_dfu_state && STATE_DFU_DNLOAD_IDLE != usb_dfu_state) { // wrong start to request download
|
||||
// warn about programming error
|
||||
usb_dfu_status = DFU_STATUS_ERR_PROG;
|
||||
usb_dfu_state = STATE_DFU_ERROR;
|
||||
} else if (STATE_DFU_IDLE==usb_dfu_state && ((NULL==len) || (0 == *len))) { // download request should not start empty
|
||||
} else if (STATE_DFU_IDLE == usb_dfu_state && ((NULL == len) || (0 == *len))) { // download request should not start empty
|
||||
// warn about programming error
|
||||
usb_dfu_status = DFU_STATUS_ERR_PROG;
|
||||
usb_dfu_state = STATE_DFU_ERROR;
|
||||
} else if (STATE_DFU_DNLOAD_IDLE==usb_dfu_state && ((NULL==len) || (0 == *len))) { // download completed
|
||||
} else if (STATE_DFU_DNLOAD_IDLE == usb_dfu_state && ((NULL == len) || (0 == *len))) { // download completed
|
||||
// go to manifestation phase
|
||||
usb_dfu_state = STATE_DFU_MANIFEST_SYNC;
|
||||
} else { // there is data to be flashed
|
||||
if (*len%2) {
|
||||
// we can only write half words
|
||||
download_length = *len; // remember download length
|
||||
download_offset = req->wValue * sizeof(usbd_control_buffer); // remember offset
|
||||
if (*len > sizeof(usbd_control_buffer) || *len > sizeof(download_data)) { // got too much data
|
||||
usb_dfu_status = DFU_STATUS_ERR_PROG;
|
||||
usb_dfu_state = STATE_DFU_ERROR;
|
||||
} else if ((uint32_t)&__application_end>=FLASH_BASE && flash_pointer+*len>=(uint32_t)&__application_end) {
|
||||
} else if ((uint32_t)&__application_end >= FLASH_BASE && (uint32_t)&__application_beginning + download_offset + download_length >= (uint32_t)&__application_end) {
|
||||
// application data is exceeding enforced flash size for application
|
||||
usb_dfu_status = DFU_STATUS_ERR_ADDRESS;
|
||||
usb_dfu_state = STATE_DFU_ERROR;
|
||||
} else if ((uint32_t)&__application_end<FLASH_BASE && flash_pointer+*len>=(uint32_t)(FLASH_BASE+DESIG_FLASH_SIZE*1024)) {
|
||||
} else if ((uint32_t)&__application_end < FLASH_BASE || (uint32_t)&__application_beginning + download_offset + download_length >= (uint32_t)(FLASH_BASE + DESIG_FLASH_SIZE * 1024)) {
|
||||
// application data is exceeding advertised flash size
|
||||
usb_dfu_status = DFU_STATUS_ERR_ADDRESS;
|
||||
usb_dfu_state = STATE_DFU_ERROR;
|
||||
} else {
|
||||
// save downloaded data to be flashed
|
||||
for (uint16_t i=0; i<*len && i<sizeof(download_data); i++) {
|
||||
for (uint16_t i = 0 ; i < *len && i < sizeof(download_data); i++) {
|
||||
download_data[i] = (*buf)[i];
|
||||
}
|
||||
download_length = *len;
|
||||
if (*len % 2) { // we can only write half words
|
||||
download_data[*len++] = 0xff; // leave flash untouched
|
||||
}
|
||||
usb_dfu_state = STATE_DFU_DNLOAD_SYNC; // go to sync state
|
||||
*complete = usb_dfu_flash; // start flashing the downloaded data
|
||||
}
|
||||
|
@ -247,24 +246,24 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
|
|||
break;
|
||||
case DFU_GETSTATUS: // get status
|
||||
(*buf)[0] = usb_dfu_status; // set status
|
||||
(*buf)[1] = 100; // set poll timeout (24 bits, in milliseconds) to small value for periodical poll
|
||||
(*buf)[1] = 10; // set poll timeout (24 bits, in milliseconds) to small value for periodical poll
|
||||
(*buf)[2] = 0; // set poll timeout (24 bits, in milliseconds) to small value for periodical poll
|
||||
(*buf)[3] = 0; // set poll timeout (24 bits, in milliseconds) to small value for periodical poll
|
||||
(*buf)[4] = usb_dfu_state; // set state
|
||||
(*buf)[5] = 0; // string not used
|
||||
*len = 6; // set length of buffer to return
|
||||
if (STATE_DFU_DNLOAD_SYNC==usb_dfu_state) {
|
||||
if (STATE_DFU_DNLOAD_SYNC == usb_dfu_state) {
|
||||
usb_dfu_state = STATE_DFU_DNBUSY; // switch to busy state
|
||||
} else if (STATE_DFU_MANIFEST_SYNC==usb_dfu_state) {
|
||||
} else if (STATE_DFU_MANIFEST_SYNC == usb_dfu_state) {
|
||||
usb_dfu_state = STATE_DFU_MANIFEST; // go to manifest mode
|
||||
led_off(); // indicate the end
|
||||
*complete = usb_dfu_reset; // start reset without waiting for request since we advertised we would detach
|
||||
}
|
||||
break;
|
||||
case DFU_CLRSTATUS: // clear status
|
||||
if (STATE_DFU_ERROR==usb_dfu_state || DFU_STATUS_OK!=usb_dfu_status) { // only clear in case there is an error
|
||||
if (STATE_DFU_ERROR == usb_dfu_state || DFU_STATUS_OK != usb_dfu_status) { // only clear in case there is an error
|
||||
usb_dfu_status = DFU_STATUS_OK; // clear error status
|
||||
usb_dfu_state = STATE_APP_IDLE; // put back in idle state
|
||||
usb_dfu_state = STATE_DFU_IDLE; // put back in idle state
|
||||
}
|
||||
break;
|
||||
case DFU_GETSTATE: // get state
|
||||
|
@ -272,9 +271,9 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
|
|||
*len = 1; // only state needs to be provided
|
||||
break;
|
||||
case DFU_ABORT: // abort current operation
|
||||
usb_dfu_state = STATE_APP_IDLE; // put back in idle state (nothing else to do)
|
||||
flash_pointer = (uint32_t)&__application_beginning; // reset download location
|
||||
usb_dfu_state = STATE_DFU_IDLE; // put back in idle state (nothing else to do)
|
||||
break;
|
||||
case DFU_DETACH: // this request is only defined in runtime mode
|
||||
default:
|
||||
to_return = USBD_REQ_NOTSUPP;
|
||||
}
|
||||
|
@ -285,7 +284,6 @@ static enum usbd_request_return_codes usb_dfu_control_request(usbd_device *usbd_
|
|||
|
||||
void usb_dfu_setup(void)
|
||||
{
|
||||
flash_pointer = (uint32_t)&__application_beginning; // set download destination to beginning of application in flash
|
||||
rcc_periph_reset_pulse(RST_USB); // reset USB peripheral
|
||||
usb_disconnect(); // disconnect to force re-enumeration
|
||||
rcc_periph_clock_enable(RCC_GPIOA); // enable clock for GPIO used for USB
|
||||
|
|
Loading…
Reference in New Issue