byte usbd_control_buffer[BLOCK_SIZE];
static enum dfu_state dfu_state = STATE_DFU_IDLE;
+static uint timeout;
+#define DEFAULT_TIMEOUT 5000 // ms
+#define DFU_TIMEOUT 2000
static struct {
byte buf[sizeof(usbd_control_buffer)];
.interface = ifaces,
};
+static inline u32 get_u32(u32 addr)
+{
+ return *(u32*)addr;
+}
+
+static inline u16 get_u16(u32 addr)
+{
+ return *(u16*)addr;
+}
+
+static bool verify_firmware(void)
+{
+ u32 len = get_u32(BOOTLOADER_APP_START + HDR_LENGTH);
+ u16 flash_in_progress = get_u16(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS);
+
+ // FIXME: Should check if len is reasonable
+
+ crc_reset();
+ u32 crc = crc_calculate_block((u32 *)BOOTLOADER_APP_START, len/4);
+ u32 want_crc = get_u32(BOOTLOADER_APP_START + len);
+ DEBUG("DFU: fip=%04x crc=%08x/%08x len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len);
+ if (flash_in_progress || crc != want_crc) {
+ DEBUG("DFU: Bad firmware\n");
+ return 0;
+ }
+
+ return 1;
+}
+
static byte dfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout)
{
switch (dfu_state) {
DEBUG("DFU: Block %u -> %08x + %u\n", prog.blocknum, (uint) baseaddr, prog.len);
flash_unlock();
flash_erase_page(baseaddr);
- for (uint i = 0; i < prog.len; i += 2) {
- u16 data = *(u16 *)(prog.buf + i);
- flash_program_half_word(baseaddr + i, data);
- }
+ for (uint i = 0; i < prog.len; i += 2)
+ flash_program_half_word(baseaddr + i, *(u16*)(prog.buf + i));
flash_lock();
for (uint i = 0; i < prog.len; i++) {
if (*(byte *)(baseaddr + i) != prog.buf[i]) {
flash_unlock();
flash_program_half_word(BOOTLOADER_APP_START + 0x20, 0);
flash_lock();
- dfu_state = STATE_DFU_MANIFEST_WAIT_RESET;
+ if (verify_firmware())
+ dfu_state = STATE_DFU_MANIFEST_WAIT_RESET;
+ else
+ dfu_state = STATE_DFU_ERROR;
return;
default:
return;
return USBD_REQ_NOTSUPP; /* Only accept class request. */
DEBUG("DFU: Request %02x in state %d\n", req->bRequest, dfu_state);
+ timeout = DFU_TIMEOUT;
switch (req->bRequest) {
case DFU_DNLOAD:
static void dfu_set_config(usbd_device *usbd_dev, u16 wValue UNUSED)
{
usbd_register_control_callback(
- usbd_dev,
- USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- dfu_control_request);
+ usbd_dev,
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ dfu_control_request);
}
static void dfu_reset(void)
RCC_APB2RSTR = 0;
}
-int main(void)
+static void configure_hardware(void)
{
- usbd_device *usbd_dev;
-
- reset_peripherals();
-
- // Flash programming requires running on the internal oscillator
- my_rcc_clock_setup_in_hsi_out_48mhz();
-
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_USB);
systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
systick_clear();
systick_counter_enable();
+}
- desig_get_unique_id_as_dfu(usb_serial_number);
-
- DEBUG("DFU: Entered boot-loader (SN %s)\n", usb_serial_number);
-
- // Simulate USB disconnect
+static void usb_disconnect(void)
+{
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
gpio_clear(GPIOA, GPIO11 | GPIO12);
for (uint i=0; i<100; i++) {
while (!systick_get_countflag())
;
}
+}
+
+int main(void)
+{
+ usbd_device *usbd_dev;
+
+ reset_peripherals();
+
+ // Flash programming requires running on the internal oscillator
+ my_rcc_clock_setup_in_hsi_out_48mhz();
+
+ configure_hardware();
+ desig_get_unique_id_as_dfu(usb_serial_number);
+
+ DEBUG("DFU: Started (SN %s)\n", usb_serial_number);
+
+ usb_disconnect();
DEBUG("DFU: Ready\n");
debug_led(0);
restart: ;
- uint timeout = 5000;
+ timeout = DEFAULT_TIMEOUT;
while (timeout || (dfu_state != STATE_DFU_IDLE && dfu_state != STATE_DFU_MANIFEST_WAIT_RESET)) {
usbd_poll(usbd_dev);
if (timeout && systick_get_countflag()) {
timeout--;
+ // FIXME: Blink LED even after timeout
if (!(timeout & 0x3f))
debug_led_toggle();
}
}
- u32 *app = (u32 *) BOOTLOADER_APP_START;
- u32 sp = app[0];
- u32 pc = app[1];
- u32 len = app[HDR_LENGTH/4];
- u16 flash_in_progress = *(u16 *)(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS);
-
- crc_reset();
- u32 crc = crc_calculate_block(app, len/4);
- u32 want_crc = *(u32 *)(BOOTLOADER_APP_START + len);
- DEBUG("DFU: fip=%04x, crc=%08x, want=%08x, len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len);
- if (flash_in_progress || crc != want_crc) {
- DEBUG("DFU: Bad firmware\n");
+ if (!verify_firmware())
goto restart;
- }
- DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc);
+ u32 sp = get_u32(BOOTLOADER_APP_START);
+ u32 pc = get_u32(BOOTLOADER_APP_START + 4);
+ DEBUG("DFU: Boot (sp=%08x pc=%08x)\n", (uint) sp, (uint) pc);
#ifdef DEBUG_USART
while (!usart_get_flag(DEBUG_USART, USART_FLAG_TC))