#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
+#include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/desig.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/usart.h>
+#include <libopencm3/usb/dfu.h>
#include <libopencm3/usb/usbd.h>
#include <string.h>
usart_enable(USART1);
}
-static const struct usb_device_descriptor dev = {
+static const struct usb_device_descriptor device = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.endpoint = endpoints,
};
+static const struct usb_dfu_descriptor dfu_function = {
+ .bLength = sizeof(struct usb_dfu_descriptor),
+ .bDescriptorType = DFU_FUNCTIONAL,
+ .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
+ .wDetachTimeout = 255,
+ .wTransferSize = 1024,
+ .bcdDFUVersion = 0x0100,
+};
+
+static const struct usb_interface_descriptor dfu_iface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = 0xFE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = 0,
+
+ .extra = &dfu_function,
+ .extralen = sizeof(dfu_function),
+};
+
static const struct usb_interface ifaces[] = {{
.num_altsetting = 1,
.altsetting = &iface,
+}, {
+ .num_altsetting = 1,
+ .altsetting = &dfu_iface,
}};
static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
- .bNumInterfaces = 1,
+ .bNumInterfaces = 2,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
return USBD_REQ_HANDLED;
}
+static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
+{
+ // Reset to bootloader, which implements the rest of DFU
+ scb_reset_core();
+}
+
+static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
+ struct usb_setup_data *req,
+ uint8_t **buf UNUSED,
+ uint16_t *len UNUSED,
+ void (**complete)(usbd_device *dev, struct usb_setup_data *req))
+{
+ if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
+ return USBD_REQ_NOTSUPP;
+
+ *complete = dfu_detach_complete;
+ return USBD_REQ_HANDLED;
+}
+
static void ep81_cb(usbd_device *usbd_dev, uint8_t ep UNUSED)
{
byte buf[4];
static void set_config_cb(usbd_device *usbd_dev, uint16_t wValue UNUSED)
{
usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, control_cb);
+ usbd_register_control_callback(usbd_dev,
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ dfu_control_cb);
usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb);
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
ep81_cb(usbd_dev, 0);
gpio_clear(GPIOA, GPIO11 | GPIO12);
delay_ms(1000);
- usbd_device *usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, ARRAY_SIZE(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
+ usbd_device *usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &device, &config, usb_strings, ARRAY_SIZE(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_reset_callback(usbd_dev, reset_cb);
usbd_register_set_config_callback(usbd_dev, set_config_cb);
u32 last_ds_step = 0;