From f09381e0c38742f3e01d88ef153d4a268fca4fcc Mon Sep 17 00:00:00 2001 From: Michal Podhradsky Date: Tue, 4 Aug 2015 16:04:44 -0700 Subject: [PATCH] Initial commit for Bootloader for Lisa MX - compiles and flashes, then allows program to be uploaded, however after uploading the program never starts --- src/Makefile | 12 +- src/luftboot.c | 835 +++++++++++++++++++++++------------------------- src/luftboot.ld | 9 +- 3 files changed, 402 insertions(+), 454 deletions(-) diff --git a/src/Makefile b/src/Makefile index 08537b3..fcdc9dd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,15 +29,14 @@ $(info Not using gcc-arm-embedded, nano specs disabled!!!) endif endif -CFLAGS += -Os -g3 -Istm32/include -mcpu=cortex-m3 -mthumb -msoft-float -DSTM32F1 \ +CFLAGS += -Os -g3 -Istm32/include -mcpu=cortex-m4 -mthumb -msoft-float -DSTM32F4 \ -I$(LIBOPENCM3)/include --function-sections --data-sections \ -DVERSION="\"$(VERSION)\"" -DDEV_SERIAL="\"$(DEV_SERIAL)\"" -LDFLAGS_BOOT = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20005000 \ - -Wl,-T,luftboot.ld $(SPECS) -nostartfiles -lc -lnosys -Wl,-Map=mapfile \ - -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd -msoft-float -L$(LIBOPENCM3)/lib \ +LDFLAGS_BOOT = -lopencm3_stm32f4 \ + -Wl,-T,luftboot.ld $(SPECS) -nostartfiles -lc -lnosys \ + -mthumb -mcpu=cortex-m4 -msoft-float -L$(LIBOPENCM3)/lib \ -Wl,--gc-sections -LDFLAGS_BOOT += -Wl,--section-start=.devserial=0x8001FF0 -LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000 +LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000 ifneq ($(V),1) Q := @ @@ -92,3 +91,4 @@ flash: luftboot.elf -x ../scripts/black_magic_probe_flash.scr \ $< endif + diff --git a/src/luftboot.c b/src/luftboot.c index ffee0b5..7aef558 100644 --- a/src/luftboot.c +++ b/src/luftboot.c @@ -1,527 +1,474 @@ /* - * This file is part of the Paparazzi UAV project. + * This file is part of the libopencm3 project. * * Copyright (C) 2010 Gareth McMullin - * Copyright (C) 2011-2012 Piotr Esden-Tempski + * Copyright (C) 2012 Sergey Krukowski + * Copyright (C) 2014 Michal Podhradsky * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/** + * @file luftboot.c + * Bootloader for Lisa/Lia MX boards with STM32F4 chip. + * Based on KroozSD bootloader + * see https://github.com/softsr/libopencm3/tree/master/examples/stm32/f4/krooz/usb_dfu + * for original file */ #include #include -#include #include #include #include #include #include #include -#include -#ifndef VERSION -#define VERSION "" -#endif +#include -#ifndef DEV_SERIAL -#define DEV_SERIAL "NSERIAL" -#endif -#define APP_ADDRESS 0x08002000 -#define SECTOR_SIZE 2048 +#define APP_ADDRESS 0x08004000 +#define SECTOR_SIZE 2048 /* 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 -#define FLASH_OBP_RDP 0x1FFFF800 -#define FLASH_OBP_WRP10 0x1FFFF808 -/* Defines user option register as per Table 5 on Page 55 of RM0008 (STM32 - * Reference Manual) - */ -#define FLASH_OBP_DATA0 0x1FFFF804 - -#define FLASH_OBP_RDP_KEY 0x5aa5 - -static const char -dev_serial[] __attribute__((section (".devserial"))) = DEV_SERIAL; +#define USER_AP_WP 0x20000 /* We need a special large control buffer for this device: */ uint8_t usbd_control_buffer[SECTOR_SIZE]; +uint32_t sector_addr[12] = {0x08000000, 0x08004000, 0x08008000, 0x0800C000, + 0x08010000, 0x08020000, 0x08040000, + 0x08060000, 0x08080000, 0x080A0000, + 0x080C0000, 0x080E0000}; +uint16_t sector_erase_time[12]= {500, 1000, 500, 500, + 1000, 1500, 1500, + 1500, 1500, 1500, + 1500, 1500}; +uint8_t sector_num = 1; + static enum dfu_state usbdfu_state = STATE_DFU_IDLE; +inline char *get_dev_unique_id(char *serial_no); +void led_set(int id, int on); +static inline void led_advance(void); + 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 = 0x1D50, - .idProduct = 0x600F, - .bcdDevice = 0x0100, - .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 | USB_DFU_WILL_DETACH, - .wDetachTimeout = 255, - .wTransferSize = SECTOR_SIZE, - .bcdDFUVersion = 0x011A, + .bLength = sizeof(struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .wDetachTimeout = 255, + .wTransferSize = SECTOR_SIZE, + .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, }; -/** contains DEV_SERIAL and unique chip ID. - * chars: 7 (serial) + 1 (space) + 24 (id) + '\0' - */ -static char serial_no[7+1+24+1]; - -static inline char *get_serial_string(char *s); +static char serial_no[25]; static const char *usb_strings[] = { - "Transition Robotics Inc.", - "Lisa/M (Upgrade) " VERSION, - serial_no, - /* This string is used by ST Microelectronics' DfuSe utility */ - "@Internal Flash /0x08000000/4*002Ka,124*002Kg" + "Paparazzi UAV", + "Lisa/Lia MX (Upgrade) ", + serial_no, + /* This string is used by ST Microelectronics' DfuSe utility. */ + "@Internal Flash /0x08000000/8*001Ka,56*001Kg", }; -static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout) +/** + * Serial is 96bit so 12bytes so 12 hexa numbers, or 24 decimal + termination character + */ +inline char *get_dev_unique_id(char *s) { - 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; - } + volatile uint8_t *unique_id = (volatile uint8_t *)0x1FFF7A10; + + int i; + + // Fetch serial number from chip's unique ID + for(i = 0; i < 24; i+=2) { + s[i] = ((*unique_id >> 4) & 0xF) + '0'; + s[i+1] = (*unique_id++ & 0xF) + '0'; + } + for(i = 0; i < 24; i++) + if(s[i] > '9') { + s[i] += 'A' - '9' - 1; + } + // add termination character + s[24] = '\0'; + + return s; } -static void usbdfu_getstatus_complete(usbd_device *device, - struct usb_setup_data *req) +static uint8_t usbdfu_getstatus(usbd_device *usbd_dev, uint32_t *bwPollTimeout) { - int i; - (void)req; - - switch(usbdfu_state) { - case STATE_DFU_DNBUSY: - - flash_unlock(); - if(prog.blocknum == 0) { - if ((*(uint32_t*)(prog.buf+1) < 0x8002000) || - (*(uint32_t*)(prog.buf+1) >= 0x8040000)) { - usbd_ep_stall_set(device, 0, 1); - return; - } - switch(prog.buf[0]) { - case CMD_ERASE: - flash_erase_page(*(uint32_t*)(prog.buf+1)); - case CMD_SETADDR: - prog.addr = *(uint32_t*)(prog.buf+1); - } - } else { - uint32_t baseaddr = prog.addr + - ((prog.blocknum - 2) * - dfu_function.wTransferSize); - for(i = 0; i < prog.len; i += 2) - flash_program_half_word(baseaddr + i, - *(uint16_t*)(prog.buf+i)); - } - flash_lock(); - - /* We jump straight to dfuDNLOAD-IDLE, - * skipping dfuDNLOAD-SYNC - */ - usbdfu_state = STATE_DFU_DNLOAD_IDLE; - return; - - case STATE_DFU_MANIFEST: - /* Mark DATA0 register that we have just downloaded the code */ - if((FLASH_OBR & 0x3FC00) != 0x00) { - flash_unlock(); - FLASH_CR = 0; - flash_erase_option_bytes(); - flash_program_option_bytes(FLASH_OBP_RDP, 0x5AA5); - flash_program_option_bytes(FLASH_OBP_WRP10, 0x03FC); - flash_program_option_bytes(FLASH_OBP_DATA0, 0xFF00); - flash_lock(); - } - /* 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 = 70; + + if (prog.blocknum == 0 && prog.buf[0] == CMD_ERASE) + if(*(uint32_t *)(prog.buf + 1) == sector_addr[sector_num]) + *bwPollTimeout = sector_erase_time[sector_num]; + + 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 *device, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, - void (**complete)(usbd_device *device, - struct usb_setup_data *req)) +static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req) { + int i; + uint32_t addr; + (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: + addr = *(uint32_t *)(prog.buf + 1); + /* Unprotect user application area */ + if(addr == APP_ADDRESS) { + flash_program_option_bytes(FLASH_OPTCR | USER_AP_WP); + } + if(addr == sector_addr[sector_num] && (addr >= APP_ADDRESS)) { + flash_erase_sector((sector_num&0x0F) << 3, 2<<8); + sector_num++; + } + case CMD_SETADDR: + prog.addr = *(uint32_t *)(prog.buf + 1); + } + } else { + + uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) * + dfu_function.wTransferSize); + if(baseaddr >= APP_ADDRESS) { + + for (i = 0; i < prog.len; i += 4) + flash_program_word(baseaddr + i, + *(uint32_t *)(prog.buf + i)); + } + } + 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... */ + // add flash read protect + // add flash write protect + // save data to BACKUP regisyter + scb_reset_system(); + return; /* Will never return. */ + default: + return; + } +} - 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(&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, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + 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 inline void gpio_init(void) +bool gpio_force_bootloader() { - /* Enable GPIOA, GPIOB, GPIOC, and AFIO clocks. */ - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_GPIOB); - rcc_periph_clock_enable(RCC_GPIOC); - rcc_periph_clock_enable(RCC_AFIO); - - /* LED1 */ - /* Set GPIO8 (in GPIO port A) to 'output push-pull'. */ - gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO8); - - /* JTAG_TRST */ - /* Set GPIO4 (in GPIO port B) to 'output push-pull'. */ - gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO4); - - AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST; - - /* LED2, ADC4, ADC6 */ - /* Set GPIO15, GPIO5, GPIO2 (in GPIO port C) to 'output push-pull'. */ - gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO15 | GPIO5 | GPIO2); - - /* Preconfigure the LEDs. */ - gpio_set(GPIOA, GPIO8); - gpio_set(GPIOB, GPIO4); - gpio_set(GPIOC, GPIO15 | GPIO5 | GPIO2); + /* Enable clock for the "force bootloader" pin bank and check for it */ + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO9); + gpio_clear(GPIOA, GPIO9); + + if(gpio_get(GPIOA, GPIO9)) { + rcc_peripheral_disable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + return true; + } + rcc_peripheral_disable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + return false; } void led_set(int id, int on) { - if (on) { - switch (id) { - case 0: - gpio_clear(GPIOA, GPIO8); /* LED1 On */ - break; - case 1: - gpio_clear(GPIOB, GPIO4); /* JTAG_TRST On */ - break; - case 2: - gpio_clear(GPIOC, GPIO2); /* ADC6 On */ - break; - case 3: - gpio_clear(GPIOC, GPIO5); /* ADC4 On */ - break; - case 4: - gpio_clear(GPIOC, GPIO15); /* LED2 On */ - break; - } - } else { - switch (id) { - case 0: - gpio_set(GPIOA, GPIO8); /* LED1 On */ - break; - case 1: - gpio_set(GPIOB, GPIO4); /* JTAG_TRST On */ - break; - case 2: - gpio_set(GPIOC, GPIO2); /* ADC6 On */ - break; - case 3: - gpio_set(GPIOC, GPIO5); /* ADC4 On */ - break; - case 4: - gpio_set(GPIOC, GPIO15); /* LED2 On */ - break; - } - } + if (on) { + switch (id) { + case 0: + gpio_clear(GPIOA, GPIO8); /* LED1 On */ + break; + case 1: + gpio_clear(GPIOB, GPIO4); /* JTAG_TRST On */ + break; + case 2: + gpio_clear(GPIOC, GPIO2); /* ADC6 On */ + break; + case 3: + gpio_clear(GPIOC, GPIO5); /* ADC4 On */ + break; + case 4: + gpio_clear(GPIOC, GPIO15); /* LED2 On */ + break; + } + } else { + switch (id) { + case 0: + gpio_set(GPIOA, GPIO8); /* LED1 On */ + break; + case 1: + gpio_set(GPIOB, GPIO4); /* JTAG_TRST On */ + break; + case 2: + gpio_set(GPIOC, GPIO2); /* ADC6 On */ + break; + case 3: + gpio_set(GPIOC, GPIO5); /* ADC4 On */ + break; + case 4: + gpio_set(GPIOC, GPIO15); /* LED2 On */ + break; + } + } } -static inline void led_advance(void) +void sys_tick_handler() { - static int state = 0; + led_advance(); +} - if (state < 5) { - led_set(state, 1); - } else if (state < 10) { - led_set(state - 5, 0); - } else if (state < 15) { - led_set(14 - state, 1); - } else if (state < 20) { - led_set(19 - state, 0); - } +static inline void led_advance(void) +{ + static int state = 0; - state++; - if(state == 20) state = 0; + if (state < 5) { + led_set(state, 1); + } else if (state < 10) { + led_set(state - 5, 0); + } else if (state < 15) { + led_set(14 - state, 1); + } else if (state < 20) { + led_set(19 - state, 0); + } -} + state++; + if(state == 20) state = 0; -bool gpio_force_bootloader() -{ - /* Force the bootloader if the GPIO state was changed to indicate this - in the application (state remains after a core-only reset) - Skip bootloader if the "skip bootloader" pin is grounded - Force bootloader if the USB vbus is powered - Skip bootloader otherwise */ - - /* Check if we are being forced by the payload. */ - if (((GPIO_CRL(GPIOC) & 0x3) == 0x0) && - ((GPIO_CRL(GPIOC) & 0xC) == 0x8) && - ((GPIO_IDR(GPIOC) & 0x1) == 0x0)){ - return true; - } else { - /* Enable clock for the "skip bootloader" pin bank and check - * for it - */ - rcc_periph_clock_enable(RCC_GPIOC); - gpio_set_mode(GPIOC, GPIO_MODE_INPUT, - GPIO_CNF_INPUT_PULL_UPDOWN, GPIO0); - gpio_set(GPIOC, GPIO0); - - if (!gpio_get(GPIOC, GPIO0)) { - /* If pin grounded, disable the pin bank and return */ - gpio_set_mode(GPIOC, GPIO_MODE_INPUT, - GPIO_CNF_INPUT_FLOAT, GPIO0); - rcc_periph_clock_disable(RCC_GPIOC); - return false; - } - /* Disable the pin bank */ - gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, - GPIO0); - rcc_periph_clock_disable(RCC_GPIOC); - - /* Enable clock for the "USB vbus" pin bank and check for it */ - rcc_periph_clock_enable(RCC_GPIOA); - gpio_set_mode(GPIOA, GPIO_MODE_INPUT, - GPIO_CNF_INPUT_PULL_UPDOWN, GPIO9); - gpio_clear(GPIOA, GPIO9); - - if (gpio_get(GPIOA, GPIO9)) { - /* If vbus pin high, disable the pin bank and return */ - gpio_set_mode(GPIOA, GPIO_MODE_INPUT, - GPIO_CNF_INPUT_FLOAT, GPIO9); - rcc_periph_clock_disable(RCC_GPIOA); - return true; - } - /* Disable the pin bank */ - gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, - GPIO9); - rcc_periph_clock_disable(RCC_GPIOA); - } - - return false; } int main(void) { - /* Check if the application is valid. */ - if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { - /* Check if we have just downloaded the new code by looking at - * the DATA0 option register or that we do NOT want to force - * the bootloader - */ - if (((FLASH_OBR & 0x3FC00) == 0x00) || - (!gpio_force_bootloader() && 1)) { - /* If we DID just download new code, reset that data - * register - */ - if((FLASH_OBR & 0x3FC00) == 0x00) { - flash_unlock(); - FLASH_CR = 0; - flash_erase_option_bytes(); - /* Flash read unprotect */ - flash_program_option_bytes(FLASH_OBP_RDP, 0x5AA5); - /* Write protect first 4 flash pages */ - flash_program_option_bytes(FLASH_OBP_WRP10, 0x03FC); - /* Write data register that we downloaded the code - * and want to jump the app - */ - flash_program_option_bytes(FLASH_OBP_DATA0, - 0x00FF); - flash_lock(); - } - /* 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))(); - } - } - - if ((FLASH_WRPR & 0x03) != 0x00) { - flash_unlock(); - FLASH_CR = 0; - flash_erase_option_bytes(); - flash_program_option_bytes(FLASH_OBP_RDP, FLASH_OBP_RDP_KEY); - flash_program_option_bytes(FLASH_OBP_WRP10, 0x03FC); - } - -#if LUFTBOOT_USE_48MHZ_INTERNAL_OSC -#pragma message "Luftboot using 8MHz internal RC oscillator to PLL it to 48MHz." - rcc_clock_setup_in_hsi_out_48mhz(); -#else -#pragma message "Luftboot using 12MHz external clock to PLL it to 72MHz." - rcc_clock_setup_in_hse_12mhz_out_72mhz(); -#endif - - rcc_periph_clock_enable(RCC_OTGFS); - - gpio_init(); - - systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); - systick_set_reload(900000); - systick_interrupt_enable(); - systick_counter_enable(); - - /* Get serial number */ - get_serial_string(serial_no); - - usbd_device *device = usbd_init(&stm32f107_usb_driver, &dev, &config, - usb_strings, 4, usbd_control_buffer, - sizeof(usbd_control_buffer)); - usbd_register_control_callback( device, - USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - usbdfu_control_request); - - while (1) - usbd_poll(device); + if (!(gpio_force_bootloader() && 1) + || (FLASH_OPTCR & USER_AP_WP) + ) + { + /* Boot the application if it's valid. */ + { + /* Write protect user application area */ + flash_program_option_bytes(FLASH_OPTCR & ~USER_AP_WP); + /* 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))(); + } + } + + usbd_device *usbd_dev; + + rcc_clock_setup_hse_3v3(&hse_12mhz_3v3[CLOCK_3V3_48MHZ]); + + //rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + + /* Enable GPIOA, GPIOB, GPIOC, and AFIO clocks. */ + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN | + RCC_AHB1ENR_IOPBEN | + RCC_AHB1ENR_IOPCEN); + + //gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO13 | GPIO14 | GPIO15); + //gpio_clear(GPIOA, GPIO13); + //gpio_set(GPIOA, GPIO14 | GPIO15); + + /* Write protect bootloader sector if not yet */ + if((FLASH_OPTCR & 0x10000)) { + flash_program_option_bytes(FLASH_OPTCR & ~0x10000); + } + + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); + + /* LED1 */ + /* Set GPIO8 (in GPIO port A) to 'output push-pull'. */ + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8); + gpio_set_output_options(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO8); + /* Preconfigure the LEDs. */ + gpio_clear(GPIOA, GPIO8); /* LED1 On */ + + /* LED 2*/ + gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + GPIO4); + gpio_set_output_options(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO4); + gpio_clear(GPIOB, GPIO4); /* JTAG_TRST On */ + + /* LED3-5 */ + gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + GPIO2 | GPIO5 | GPIO15); + gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO2 | GPIO5 | GPIO15); + gpio_clear(GPIOC, GPIO2); + gpio_clear(GPIOC, GPIO5); + gpio_clear(GPIOC, GPIO15); + + /* Sys tick*/ + rcc_periph_clock_enable(RCC_OTGFS); + + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + + systick_set_reload(700000); + systick_interrupt_enable(); + systick_counter_enable(); + + + /* USB */ + get_dev_unique_id(serial_no); + + usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, + sizeof(usbd_control_buffer)); + 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); + + while (1) + usbd_poll(usbd_dev); } -/** get serial number as combination of DEV_SERIAL and unique chip ID. - * first 7 chars are DEV_SERIAL, space, then 24 chars unique chip ID. - */ -static inline char *get_serial_string(char *s) -{ - int i; - for(i = 0; i < 7; i++) { - s[i] = dev_serial[i]; - } - s[i] = ' '; - desig_get_unique_id_as_string(&s[8], 25); - - return s; -} -void sys_tick_handler() -{ - led_advance(); -} diff --git a/src/luftboot.ld b/src/luftboot.ld index 016068c..d80ea4b 100644 --- a/src/luftboot.ld +++ b/src/luftboot.ld @@ -20,10 +20,11 @@ /* Define memory regions. */ MEMORY { - rom (rx) : ORIGIN = 0x08000000, LENGTH = 8K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } -/* Include the common ld script from libopenstm32. */ -INCLUDE libopencm3_stm32f1.ld +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f4.ld +