diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 6080f1eb6e4..d5aaf747aba 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -45,10 +45,11 @@ volatile uint32_t magic[2] __attribute__((section(".noinit"))); void platform_init(void) { - /* Enable GPIO peripherals */ + /* Enable peripherals */ rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_CRC); #ifndef BMP_BOOTLOADER /* Blackpill board has a floating button on PA0. Pull it up and use as active-low. */ @@ -73,26 +74,19 @@ void platform_init(void) #endif rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[PLATFORM_CLOCK_FREQ]); - /* Enable peripherals */ - rcc_periph_clock_enable(RCC_OTGFS); - rcc_periph_clock_enable(RCC_CRC); - /* Set up DM/DP pins. PA9/PA10 are not routed to USB-C. */ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); - GPIOA_OSPEEDR &= 0x3c00000cU; - GPIOA_OSPEEDR |= 0x28000008U; - /* Set up TDI, TDO, TCK and TMS pins */ gpio_mode_setup(TDI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TDI_PIN); gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TDO_PIN); gpio_mode_setup(TCK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TCK_PIN); gpio_mode_setup(TMS_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TMS_PIN); - gpio_set_output_options(TDI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, TDI_PIN); - gpio_set_output_options(TDO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, TDO_PIN); - gpio_set_output_options(TCK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, TCK_PIN); - gpio_set_output_options(TMS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, TMS_PIN); + gpio_set_output_options(TDI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, TDI_PIN); + gpio_set_output_options(TDO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, TDO_PIN); + gpio_set_output_options(TCK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, TCK_PIN); + gpio_set_output_options(TMS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, TMS_PIN); /* Set up LED pins */ gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER); @@ -114,6 +108,9 @@ void platform_init(void) /* https://github.com/libopencm3/libopencm3/pull/1256#issuecomment-779424001 */ OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN; OTG_FS_GCCFG &= ~(OTG_GCCFG_VBUSBSEN | OTG_GCCFG_VBUSASEN); + + /* By default, do not drive the SWD bus too fast. */ + platform_max_frequency_set(3000000); } void platform_nrst_set_val(bool assert) diff --git a/src/platforms/common/blackpill-f4/usbdfu.c b/src/platforms/common/blackpill-f4/usbdfu.c index b32afce068d..d5d205ea968 100644 --- a/src/platforms/common/blackpill-f4/usbdfu.c +++ b/src/platforms/common/blackpill-f4/usbdfu.c @@ -19,9 +19,10 @@ #include #include +#include +#include #include #include -#include #include #include "usbdfu.h" @@ -30,6 +31,9 @@ uintptr_t app_address = 0x08004000U; volatile uint32_t magic[2] __attribute__((section(".noinit"))); +static uint32_t dfu_activity_counter; + +static void sys_tick_init(void); void dfu_detach(void) { @@ -38,6 +42,7 @@ void dfu_detach(void) int main(void) { + /* Enable GPIO peripherals */ rcc_periph_clock_enable(RCC_GPIOA); /* Blackpill board has a floating button on PA0. Pull it up and use as active-low. */ @@ -53,11 +58,11 @@ int main(void) /* Assert blue LED as indicator we are in the bootloader */ rcc_periph_clock_enable(RCC_GPIOC); - gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_BOOTLOADER); - gpio_set(LED_PORT, LED_BOOTLOADER); + gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_BOOTLOADER | LED_IDLE_RUN); + gpio_clear(LED_PORT, LED_BOOTLOADER | LED_IDLE_RUN); - /* Enable peripherals */ - rcc_periph_clock_enable(RCC_OTGFS); + /* Run heartbeat on blue LED */ + sys_tick_init(); /* Set up USB Pins and alternate function*/ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); @@ -75,4 +80,46 @@ int main(void) void dfu_event(void) { + static bool idle_state = false; + /* Ask systick to pause blinking for 1 second */ + dfu_activity_counter = 10U; + /* Toggle-blink it ourself */ + SET_IDLE_STATE(idle_state); + idle_state = !idle_state; +} + +static void sys_tick_init(void) +{ + /* Use SysTick at 10Hz to toggle-blink the blue LED at 5 Hz */ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + systick_set_reload(rcc_ahb_frequency / 8U / 10U); + /* SYSTICK_IRQ with low priority */ + nvic_set_priority(NVIC_SYSTICK_IRQ, 14U << 4U); + systick_interrupt_enable(); + /* Start the heartbeat timer */ + systick_counter_enable(); +} + +void sys_tick_handler(void) +{ + static uint32_t count = 0U; + if (dfu_activity_counter > 0U) { + dfu_activity_counter--; + return; + } + switch (count) { + case 0U: + /* Reload downcounter and disable LED */ + count = 10U; + SET_IDLE_STATE(false); + break; + case 1U: + count--; + /* Enable LED for 1/10th of cycle */ + SET_IDLE_STATE(true); + break; + default: + count--; + break; + } } diff --git a/src/platforms/common/stm32/dfu_f4.c b/src/platforms/common/stm32/dfu_f4.c index 60f22886510..790246061ef 100644 --- a/src/platforms/common/stm32/dfu_f4.c +++ b/src/platforms/common/stm32/dfu_f4.c @@ -17,6 +17,32 @@ * along with this program. If not, see . */ +/* + * References, ST datasheets: + * + * DS8626 - STM32F405xx/407xx Rev 9 pg108, Table 40. Flash memory programming + * https://www.st.com/resource/en/datasheet/stm32f407vg.pdf + * (f4discovery:stm32f407vg, 128/1024 KiB; + * hydrabus:stm32f405rg, 128/1024 KiB) + * + * DS9716 - STM32F401xB/xC Rev 11 pg85, Table 45. Flash memory programming + * https://www.st.com/resource/en/datasheet/stm32f401cb.pdf + * (blackpill-f4:stm32f401cc, 64/256 KiB) + * + * DS10086 - STM32F401xD/xE Rev 3 pg86, Table 45. Flash memory programming + * https://www.st.com/resource/en/datasheet/stm32f401re.pdf + * (blackpill-f4:stm32f401ce, 96/512 KiB; + * 96b_carbon:stm32f401re, 96/512 KiB) + * + * DS10314 - STM32F411xC/xE Rev 7 pg92, Table 45. Flash memory programming + * https://www.st.com/resource/en/datasheet/stm32f411ce.pdf + * (blackpill-f4:stm32f411ce, 128/512 KiB) + * + * DS11853 - STM32F722xx/723xx Rev 9 pg138, Table 53. Flash memory programming + * https://www.st.com/resource/en/datasheet/stm32f723ie.pdf + * (stlinkv3:stm32f723ie, 256/512 KiB; and F7 has slightly smaller timings than F4 family) + */ + #include "general.h" #include "usbdfu.h" @@ -41,7 +67,29 @@ static uint32_t sector_addr[] = { 0, }; -static uint16_t sector_erase_time[] = {500, 500, 500, 500, 1100, 2600, 2600, 2600, 2600, 2600, 2600, 2600, 2600}; +/* Sector erase times in milliseconds, typ, for x32 parallelism at 2.7-3.6v */ +typedef enum erase_times_f4 { + ERASE_TIME_16KB = 250, /* 500 * 0.5 */ + ERASE_TIME_64KB = 550, /* 1100 * 0.5 */ + ERASE_TIME_128KB = 1000, /* 2000 * 0.5 */ +} erase_times_f4_e; + +static erase_times_f4_e sector_erase_time[] = { + ERASE_TIME_16KB, + ERASE_TIME_16KB, + ERASE_TIME_16KB, + ERASE_TIME_16KB, + ERASE_TIME_64KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, + ERASE_TIME_128KB, +}; + static uint8_t sector_num = 0xff; static_assert(ARRAY_LENGTH(sector_erase_time) == ARRAY_LENGTH(sector_addr) - 1U, @@ -75,20 +123,25 @@ void dfu_flash_program_buffer(const uint32_t baseaddr, const void *const buf, co const uint32_t *const buffer = (const uint32_t *)buf; for (size_t i = 0; i < len; i += 4U) flash_program_word(baseaddr + i, buffer[i >> 2U]); + + /* Call the platform specific dfu event callback. */ + dfu_event(); } uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum) { - /* Erase for big pages on STM2/4 needs "long" time - Try not to hit USB timeouts*/ + /* + * Sector erase for big pages of STM32 F2/F4/F7 needs "long" time, + * up to 1-2 seconds. Try not to hit USB timeouts. + */ if (blocknum == 0 && cmd == CMD_ERASE) { get_sector_num(addr); if (addr == sector_addr[sector_num]) return sector_erase_time[sector_num]; } - /* Programming 256 word with 100 us(max) per word*/ - return 26U; + /* Programming 256 words (32-bit) with 16 us(typ), 100 us(max) per word */ + return 16U * 1024U / 4U / 1000U; } void dfu_protect(bool enable)