Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Fancy DFU on blackpill-f4 #1717

Merged
21 changes: 9 additions & 12 deletions src/platforms/common/blackpill-f4/blackpill-f4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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);
dragonmux marked this conversation as resolved.
Show resolved Hide resolved
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);
Expand All @@ -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)
Expand Down
57 changes: 52 additions & 5 deletions src/platforms/common/blackpill-f4/usbdfu.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

#include <string.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/dwc/otg_fs.h>

#include "usbdfu.h"
Expand All @@ -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)
{
Expand All @@ -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. */
Expand All @@ -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);
Expand All @@ -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--;
dragonmux marked this conversation as resolved.
Show resolved Hide resolved
/* Enable LED for 1/10th of cycle */
SET_IDLE_STATE(true);
break;
default:
count--;
break;
}
}
63 changes: 58 additions & 5 deletions src/platforms/common/stm32/dfu_f4.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* 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"

Expand All @@ -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 */
dragonmux marked this conversation as resolved.
Show resolved Hide resolved
} 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,
Expand Down Expand Up @@ -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)
Expand Down