From 49148e76706e5e24c2ba7f6ccc1d7ec4736ab2f3 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 3 Mar 2021 15:24:13 +0000 Subject: support cheap chinese blue pill boards, make usb dfu compatible with dfuse --- boot/Makefile | 16 ++ boot/gdb.script | 2 + boot/usbdfu.c | 448 +++++++++++++++++++++++++++++++------------------------- 3 files changed, 265 insertions(+), 201 deletions(-) create mode 100644 boot/gdb.script (limited to 'boot') diff --git a/boot/Makefile b/boot/Makefile index 86d4d2c..4891184 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -30,3 +30,19 @@ include ../Makefile.include CFLAGS += -I.. +ds: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + +debug: ${PROG}.elf + ${PREFIX}-gdb -x gdb.script ${PROG}.elf + +reset: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset run" \ + -c shutdown + +tidy: + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} || astyle -A3 -s2 -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} + diff --git a/boot/gdb.script b/boot/gdb.script new file mode 100644 index 0000000..7cf9d09 --- /dev/null +++ b/boot/gdb.script @@ -0,0 +1,2 @@ +target remote localhost:3333 +cont diff --git a/boot/usbdfu.c b/boot/usbdfu.c index d538234..9287f57 100644 --- a/boot/usbdfu.c +++ b/boot/usbdfu.c @@ -27,13 +27,13 @@ #include -#define APP_ADDRESS 0x08002000 +#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 -void usb_set_config (usbd_device * usbd_dev, uint16_t wValue); +void usb_set_config (usbd_device *usbd_dev, uint16_t wValue); /* We need a special large control buffer for this device: */ uint8_t usbd_control_buffer[1024]; @@ -43,248 +43,294 @@ static enum dfu_state usbdfu_state = STATE_DFU_IDLE; extern uint32_t dfu_flag; static struct { - uint8_t buf[sizeof(usbd_control_buffer)]; - uint16_t len; - uint32_t addr; - uint16_t blocknum; + uint8_t buf[sizeof (usbd_control_buffer)]; + uint16_t len; + uint32_t addr; + uint16_t blocknum; } 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 = ID_VENDOR, - .idProduct = ID_PRODUCT, - .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 = { - .bLength = sizeof(struct usb_dfu_descriptor), - .bDescriptorType = DFU_FUNCTIONAL, - .bmAttributes = USB_DFU_CAN_DOWNLOAD, - .wDetachTimeout = 255, - .wTransferSize = 1024, - .bcdDFUVersion = 0x011A, + .bLength = sizeof (struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x011A, }; const struct usb_interface_descriptor iface = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */ - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 2, - - /* The ST Microelectronics DfuSe application needs this string. - * The format isn't documented... */ - .iInterface = 4, - - .extra = &dfu_function, - .extralen = sizeof(dfu_function), + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */ + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 2, + + /* The ST Microelectronics DfuSe application needs this string. + * The format isn't documented... */ + .iInterface = 4, + + .extra = &dfu_function, + .extralen = sizeof (dfu_function), }; const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = &iface, -}}; + .num_altsetting = 1, + .altsetting = &iface, + } +}; const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0xC0, - .bMaxPower = 0x32, - - .interface = ifaces, + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0xC0, + .bMaxPower = 0x32, + + .interface = ifaces, }; static const char *usb_strings[] = { - "Cabbages are good for you", - "fish", - "soup", - /* This string is used by ST Microelectronics' DfuSe utility. */ - "@Internal Flash /0x08000000/8*001Ka,56*001Kg", + VENDOR_NAME, + PRODUCT_NAME " (dfu mode)", + SERIAL_NUMBER, + /* This string is used by ST Microelectronics' DfuSe utility. */ + "@Internal Flash /0x08000000/8*001Ka,56*001Kg", }; +#define N_USB_STRINGS (sizeof(usb_strings)/sizeof(usb_strings[0])) -static uint8_t usbdfu_getstatus(usbd_device *usbd_dev, uint32_t *bwPollTimeout) +static void +delay_us (uint32_t d) { - (void)usbd_dev; - - switch (usbdfu_state) { - case STATE_DFU_DNLOAD_SYNC: - usbdfu_state = STATE_DFU_DNBUSY; - *bwPollTimeout = 100; - return DFU_STATUS_OK; - case STATE_DFU_MANIFEST_SYNC: - /* Device will reset when read is complete. */ - usbdfu_state = STATE_DFU_MANIFEST; - return DFU_STATUS_OK; - default: - return DFU_STATUS_OK; - } + d *= 7; + + while (d--) + __asm__ ("nop"); } -static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req) + +static uint8_t usbdfu_getstatus (usbd_device *usbd_dev, uint32_t *bwPollTimeout) { - int i; - (void)req; - (void)usbd_dev; - - switch (usbdfu_state) { - case STATE_DFU_DNBUSY: - flash_unlock(); - if (prog.blocknum == 0) { - switch (prog.buf[0]) { - case CMD_ERASE: - { - uint32_t *dat = (uint32_t *)(prog.buf + 1); - flash_erase_page(*dat); - } - case CMD_SETADDR: - { - uint32_t *dat = (uint32_t *)(prog.buf + 1); - prog.addr = *dat; - } - } - } else { - uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) * - dfu_function.wTransferSize); - for (i = 0; i < prog.len; i += 2) { - uint16_t *dat = (uint16_t *)(prog.buf + i); - flash_program_half_word(baseaddr + i, - *dat); - } - } - flash_lock(); - - /* 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. */ - default: - return; - } + (void)usbd_dev; + + switch (usbdfu_state) { + case STATE_DFU_DNLOAD_SYNC: + usbdfu_state = STATE_DFU_DNBUSY; + *bwPollTimeout = 100; + return DFU_STATUS_OK; + + case STATE_DFU_MANIFEST_SYNC: + /* Device will reset when read is complete. */ + usbdfu_state = STATE_DFU_MANIFEST; + return DFU_STATUS_OK; + + default: + return DFU_STATUS_OK; + } } -static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +static int usbdfu_getstatus_complete (usbd_device *usbd_dev, struct usb_setup_data *req) { + int i; + (void)req; + (void)usbd_dev; + + switch (usbdfu_state) { + case STATE_DFU_DNBUSY: + flash_unlock(); + + if (prog.blocknum == 0) { + switch (prog.buf[0]) { + case CMD_ERASE: { + uint32_t *dat = (uint32_t *) (prog.buf + 1); + flash_erase_page (*dat); + } + break; + + case CMD_SETADDR: { + uint32_t *dat = (uint32_t *) (prog.buf + 1); + prog.addr = *dat; + } + } + } else { + uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) * + dfu_function.wTransferSize); + + for (i = 0; i < prog.len; i += 2) { + uint16_t *dat = (uint16_t *) (prog.buf + i); + flash_program_half_word (baseaddr + i, + *dat); + } + } + + flash_lock(); + + /* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */ + usbdfu_state = STATE_DFU_DNLOAD_IDLE; + return 0; + + case STATE_DFU_MANIFEST: + /* USB device must detach, we just reset... */ + scb_reset_system(); + return 0; /* Will never return. */ + + default: + ; + } + + return 0; +} - if ((req->bmRequestType & 0x7F) != 0x21) - return 0; /* Only accept class request. */ - - switch (req->bRequest) { - case DFU_DNLOAD: - if ((len == NULL) || (*len == 0)) { - usbdfu_state = STATE_DFU_MANIFEST_SYNC; - return 1; - } else { - /* Copy download data for use on GET_STATUS. */ - prog.blocknum = req->wValue; - prog.len = *len; - memcpy(prog.buf, *buf, *len); - usbdfu_state = STATE_DFU_DNLOAD_SYNC; - return 1; - } - case DFU_CLRSTATUS: - /* 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. */ - usbdfu_state = STATE_DFU_IDLE; - return 1; - case DFU_UPLOAD: - /* Upload not supported for now. */ - return 0; - case DFU_GETSTATUS: { - uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */ - (*buf)[0] = usbdfu_getstatus(usbd_dev, &bwPollTimeout); - (*buf)[1] = bwPollTimeout & 0xFF; - (*buf)[2] = (bwPollTimeout >> 8) & 0xFF; - (*buf)[3] = (bwPollTimeout >> 16) & 0xFF; - (*buf)[4] = usbdfu_state; - (*buf)[5] = 0; /* iString not used here */ - *len = 6; - *complete = usbdfu_getstatus_complete; - return 1; - } - case DFU_GETSTATE: - /* Return state with no state transision. */ - *buf[0] = usbdfu_state; - *len = 1; - return 1; - } - - return 0; +static int usbdfu_control_request (usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete) +{ + + if ((req->bmRequestType & 0x7F) != 0x21) + return 0; /* Only accept class request. */ + + switch (req->bRequest) { + case DFU_DNLOAD: + if ((len == NULL) || (*len == 0)) { + usbdfu_state = STATE_DFU_MANIFEST_SYNC; + return 1; + } else { + /* Copy download data for use on GET_STATUS. */ + prog.blocknum = req->wValue; + prog.len = *len; + memcpy (prog.buf, *buf, *len); + usbdfu_state = STATE_DFU_DNLOAD_SYNC; + return 1; + } + + case DFU_CLRSTATUS: + + /* 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. */ + usbdfu_state = STATE_DFU_IDLE; + return 1; + + case DFU_UPLOAD: + /* Upload not supported for now. */ + return 0; + + case DFU_GETSTATUS: { + uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */ + (*buf)[0] = usbdfu_getstatus (usbd_dev, &bwPollTimeout); + (*buf)[1] = bwPollTimeout & 0xFF; + (*buf)[2] = (bwPollTimeout >> 8) & 0xFF; + (*buf)[3] = (bwPollTimeout >> 16) & 0xFF; + (*buf)[4] = usbdfu_state; + (*buf)[5] = 0; /* iString not used here */ + *len = 6; + *complete = usbdfu_getstatus_complete; + return 1; + } + + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = usbdfu_state; + *len = 1; + return 1; + } + + return 0; } +static void usb_reset (void) +{ + /*Force USB reset */ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13); + gpio_clear (GPIOA, GPIO12); + gpio_clear (GPIOA, GPIO13); + + delay_us (5000); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO12); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO13); +} + + void -usb_set_config (usbd_device * usbd_dev, uint16_t wValue) +usb_set_config (usbd_device *usbd_dev, uint16_t wValue) { (void) wValue; (void) usbd_dev; - - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - usbdfu_control_request); + + usbd_register_control_callback ( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + usbdfu_control_request); } -int main(void) +int main (void) { - usbd_device *usbd_dev; + usbd_device *usbd_dev; + + rcc_periph_clock_enable (RCC_GPIOA); + rcc_periph_reset_pulse (RST_USB); + + if (dfu_flag != 0xfee1dead) { + /* Boot the application if it's valid. */ + if ((* (volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { + /* Set vector table base address. */ + SCB_VTOR = APP_ADDRESS & 0xFFFF; + /* Initialise master stack pointer. */ + asm volatile ("msr msp, %0"::"g" + (* (volatile uint32_t *)APP_ADDRESS)); + /* Jump to application. */ + (* (void (* *)()) (APP_ADDRESS + 4))(); + } + } - rcc_periph_clock_enable(RCC_GPIOA); + usb_reset(); - if (dfu_flag!=0xfee1dead) { - /* Boot the application if it's valid. */ - if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { - /* Set vector table base address. */ - SCB_VTOR = APP_ADDRESS & 0xFFFF; - /* Initialise master stack pointer. */ - asm volatile("msr msp, %0"::"g" - (*(volatile uint32_t *)APP_ADDRESS)); - /* Jump to application. */ - (*(void (**)())(APP_ADDRESS + 4))(); - } - } + dfu_flag = 0; - dfu_flag=0; + rcc_clock_setup_in_hsi_out_48mhz(); - rcc_clock_setup_in_hsi_out_48mhz(); + rcc_periph_clock_enable (RCC_GPIOC); - rcc_periph_clock_enable(RCC_GPIOC); + gpio_set_mode (GPIOC, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); + gpio_set (GPIOC, GPIO11); - gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); - gpio_set(GPIOC, GPIO11); - usbd_dev = usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_dev = usbd_init (&stm32f103_usb_driver, &dev, &config, usb_strings, N_USB_STRINGS, usbd_control_buffer, sizeof (usbd_control_buffer)); - usbd_register_set_config_callback (usbd_dev, usb_set_config); + usbd_register_set_config_callback (usbd_dev, usb_set_config); - gpio_clear(GPIOC, GPIO11); + gpio_clear (GPIOC, GPIO11); - while (1) - usbd_poll(usbd_dev); + while (1) + usbd_poll (usbd_dev); } -- cgit v1.2.3