|
|
@ -28,8 +28,8 @@ |
|
|
|
#define APP_ADDRESS 0x08002000 |
|
|
|
|
|
|
|
/* Commands sent with wBlockNum == 0 as per ST implementation. */ |
|
|
|
#define CMD_SETADDR 0x21 |
|
|
|
#define CMD_ERASE 0x41 |
|
|
|
#define CMD_SETADDR 0x21 |
|
|
|
#define CMD_ERASE 0x41 |
|
|
|
|
|
|
|
/* We need a special large control buffer for this device: */ |
|
|
|
u8 usbd_control_buffer[1024]; |
|
|
@ -44,20 +44,20 @@ static struct { |
|
|
|
} prog; |
|
|
|
|
|
|
|
const struct usb_device_descriptor dev = { |
|
|
|
.bLength = USB_DT_DEVICE_SIZE, |
|
|
|
.bDescriptorType = USB_DT_DEVICE, |
|
|
|
.bcdUSB = 0x0200, |
|
|
|
.bDeviceClass = 0, |
|
|
|
.bDeviceSubClass = 0, |
|
|
|
.bDeviceProtocol = 0, |
|
|
|
.bMaxPacketSize0 = 64, |
|
|
|
.idVendor = 0x0483, |
|
|
|
.idProduct = 0xDF11, |
|
|
|
.bcdDevice = 0x0200, |
|
|
|
.iManufacturer = 1, |
|
|
|
.iProduct = 2, |
|
|
|
.iSerialNumber = 3, |
|
|
|
.bNumConfigurations = 1, |
|
|
|
.bLength = USB_DT_DEVICE_SIZE, |
|
|
|
.bDescriptorType = USB_DT_DEVICE, |
|
|
|
.bcdUSB = 0x0200, |
|
|
|
.bDeviceClass = 0, |
|
|
|
.bDeviceSubClass = 0, |
|
|
|
.bDeviceProtocol = 0, |
|
|
|
.bMaxPacketSize0 = 64, |
|
|
|
.idVendor = 0x0483, |
|
|
|
.idProduct = 0xDF11, |
|
|
|
.bcdDevice = 0x0200, |
|
|
|
.iManufacturer = 1, |
|
|
|
.iProduct = 2, |
|
|
|
.iSerialNumber = 3, |
|
|
|
.bNumConfigurations = 1, |
|
|
|
}; |
|
|
|
|
|
|
|
const struct usb_dfu_descriptor dfu_function = { |
|
|
@ -79,7 +79,7 @@ const struct usb_interface_descriptor iface = { |
|
|
|
.bInterfaceSubClass = 1, |
|
|
|
.bInterfaceProtocol = 2, |
|
|
|
|
|
|
|
/* The ST Microelectronics DfuSe application needs this string.
|
|
|
|
/* The ST Microelectronics DfuSe application needs this string.
|
|
|
|
* The format isn't documented... */ |
|
|
|
.iInterface = 4, |
|
|
|
|
|
|
@ -110,7 +110,7 @@ static const char *usb_strings[] = { |
|
|
|
"Black Sphere Technologies", |
|
|
|
"DFU Demo", |
|
|
|
"DEMO", |
|
|
|
/* This string is used by ST Microelectronics' DfuSe utility */ |
|
|
|
/* This string is used by ST Microelectronics' DfuSe utility. */ |
|
|
|
"@Internal Flash /0x08000000/8*001Ka,56*001Kg" |
|
|
|
}; |
|
|
|
|
|
|
@ -118,15 +118,13 @@ static u8 usbdfu_getstatus(u32 *bwPollTimeout) |
|
|
|
{ |
|
|
|
switch(usbdfu_state) { |
|
|
|
case STATE_DFU_DNLOAD_SYNC: |
|
|
|
usbdfu_state = STATE_DFU_DNBUSY; |
|
|
|
usbdfu_state = STATE_DFU_DNBUSY; |
|
|
|
*bwPollTimeout = 100; |
|
|
|
return DFU_STATUS_OK; |
|
|
|
|
|
|
|
case STATE_DFU_MANIFEST_SYNC: |
|
|
|
/* Device will reset when read is complete */ |
|
|
|
/* Device will reset when read is complete. */ |
|
|
|
usbdfu_state = STATE_DFU_MANIFEST; |
|
|
|
return DFU_STATUS_OK; |
|
|
|
|
|
|
|
default: |
|
|
|
return DFU_STATUS_OK; |
|
|
|
} |
|
|
@ -137,56 +135,50 @@ static void usbdfu_getstatus_complete(struct usb_setup_data *req) |
|
|
|
int i; |
|
|
|
(void)req; |
|
|
|
|
|
|
|
switch(usbdfu_state) { |
|
|
|
switch (usbdfu_state) { |
|
|
|
case STATE_DFU_DNBUSY: |
|
|
|
|
|
|
|
flash_unlock(); |
|
|
|
if(prog.blocknum == 0) { |
|
|
|
if (prog.blocknum == 0) { |
|
|
|
switch(prog.buf[0]) { |
|
|
|
case CMD_ERASE: |
|
|
|
flash_erase_page(*(u32*)(prog.buf+1)); |
|
|
|
flash_erase_page(*(u32 *)(prog.buf + 1)); |
|
|
|
case CMD_SETADDR: |
|
|
|
prog.addr = *(u32*)(prog.buf+1); |
|
|
|
prog.addr = *(u32 *)(prog.buf + 1); |
|
|
|
} |
|
|
|
} else { |
|
|
|
u32 baseaddr = prog.addr + |
|
|
|
((prog.blocknum - 2) * |
|
|
|
dfu_function.wTransferSize); |
|
|
|
for(i = 0; i < prog.len; i += 2) |
|
|
|
flash_program_half_word(baseaddr + i, |
|
|
|
*(u16*)(prog.buf+i)); |
|
|
|
u32 baseaddr = prog.addr + ((prog.blocknum - 2) * |
|
|
|
dfu_function.wTransferSize); |
|
|
|
for (i = 0; i < prog.len; i += 2) |
|
|
|
flash_program_half_word(baseaddr + i, |
|
|
|
*(u16 *)(prog.buf + i)); |
|
|
|
} |
|
|
|
flash_lock(); |
|
|
|
|
|
|
|
/* We jump straight to dfuDNLOAD-IDLE,
|
|
|
|
* skipping dfuDNLOAD-SYNC |
|
|
|
*/ |
|
|
|
/* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */ |
|
|
|
usbdfu_state = STATE_DFU_DNLOAD_IDLE; |
|
|
|
return; |
|
|
|
|
|
|
|
case STATE_DFU_MANIFEST: |
|
|
|
/* USB device must detach, we just reset... */ |
|
|
|
scb_reset_system(); |
|
|
|
return; /* Will never return */ |
|
|
|
return; /* Will never return. */ |
|
|
|
default: |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
u16 *len, void (**complete)(struct usb_setup_data *req)) |
|
|
|
{ |
|
|
|
|
|
|
|
if((req->bmRequestType & 0x7F) != 0x21) |
|
|
|
return 0; /* Only accept class request */ |
|
|
|
if ((req->bmRequestType & 0x7f) != 0x21) |
|
|
|
return 0; /* Only accept class request. */ |
|
|
|
|
|
|
|
switch(req->bRequest) { |
|
|
|
case DFU_DNLOAD: |
|
|
|
if((len == NULL) || (*len == 0)) { |
|
|
|
if ((len == NULL) || (*len == 0)) { |
|
|
|
usbdfu_state = STATE_DFU_MANIFEST_SYNC; |
|
|
|
return 1; |
|
|
|
} else { |
|
|
|
/* Copy download data for use on GET_STATUS */ |
|
|
|
/* Copy download data for use on GET_STATUS. */ |
|
|
|
prog.blocknum = req->wValue; |
|
|
|
prog.len = *len; |
|
|
|
memcpy(prog.buf, *buf, *len); |
|
|
@ -194,16 +186,16 @@ static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
return 1; |
|
|
|
} |
|
|
|
case DFU_CLRSTATUS: |
|
|
|
/* Clear error and return to dfuIDLE */ |
|
|
|
/* Clear error and return to dfuIDLE. */ |
|
|
|
if(usbdfu_state == STATE_DFU_ERROR) |
|
|
|
usbdfu_state = STATE_DFU_IDLE; |
|
|
|
return 1; |
|
|
|
case DFU_ABORT: |
|
|
|
/* Abort returns to dfuIDLE state */ |
|
|
|
/* Abort returns to dfuIDLE state. */ |
|
|
|
usbdfu_state = STATE_DFU_IDLE; |
|
|
|
return 1; |
|
|
|
case DFU_UPLOAD: |
|
|
|
/* Upload not supported for now */ |
|
|
|
/* Upload not supported for now. */ |
|
|
|
return 0; |
|
|
|
case DFU_GETSTATUS: { |
|
|
|
u32 bwPollTimeout = 0; /* 24-bit integer in DFU class spec */ |
|
|
@ -213,7 +205,7 @@ static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
(*buf)[2] = (bwPollTimeout >> 8) & 0xFF; |
|
|
|
(*buf)[3] = (bwPollTimeout >> 16) & 0xFF; |
|
|
|
(*buf)[4] = usbdfu_state; |
|
|
|
(*buf)[5] = 0; /* iString not used here */ |
|
|
|
(*buf)[5] = 0; /* iString not used here */ |
|
|
|
*len = 6; |
|
|
|
|
|
|
|
*complete = usbdfu_getstatus_complete; |
|
|
@ -221,7 +213,7 @@ static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
return 1; |
|
|
|
} |
|
|
|
case DFU_GETSTATE: |
|
|
|
/* Return state with no state transision */ |
|
|
|
/* Return state with no state transision. */ |
|
|
|
*buf[0] = usbdfu_state; |
|
|
|
*len = 1; |
|
|
|
return 1; |
|
|
@ -233,20 +225,21 @@ static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf, |
|
|
|
int main(void) |
|
|
|
{ |
|
|
|
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN); |
|
|
|
if(!gpio_get(GPIOA, GPIO10)) { |
|
|
|
/* Boot the application if it's valid */ |
|
|
|
if((*(volatile u32*)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { |
|
|
|
/* Set vector table base address */ |
|
|
|
|
|
|
|
if (!gpio_get(GPIOA, GPIO10)) { |
|
|
|
/* Boot the application if it's valid. */ |
|
|
|
if ((*(volatile u32*)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { |
|
|
|
/* Set vector table base address. */ |
|
|
|
SCB_VTOR = APP_ADDRESS & 0xFFFF; |
|
|
|
/* Initialise master stack pointer */ |
|
|
|
/* Initialise master stack pointer. */ |
|
|
|
asm volatile ("msr msp, %0"::"g" |
|
|
|
(*(volatile u32*)APP_ADDRESS)); |
|
|
|
/* Jump to application */ |
|
|
|
(*(volatile u32 *)APP_ADDRESS)); |
|
|
|
/* Jump to application. */ |
|
|
|
(*(void(**)())(APP_ADDRESS + 4))(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rcc_clock_setup_in_hsi_out_48mhz(); |
|
|
|
rcc_clock_setup_in_hsi_out_48mhz(); |
|
|
|
|
|
|
|
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN); |
|
|
|
|
|
|
@ -263,6 +256,6 @@ int main(void) |
|
|
|
|
|
|
|
gpio_clear(GPIOC, GPIO11); |
|
|
|
|
|
|
|
while (1) |
|
|
|
while (1) |
|
|
|
usbd_poll(); |
|
|
|
} |
|
|
|