stlink: Use common initialization and detect V2.1 boards.

Factor out hardware revision detection, USB detach and power settings, as
all three program (bootloader, bmp and dfu-upgrade) need it.
This commit is contained in:
Uwe Bonnes 2017-04-17 18:27:07 +02:00
parent 16f99238b1
commit 963df9febc
7 changed files with 189 additions and 214 deletions

View File

@ -0,0 +1,22 @@
Bootloader Upgrade on Stlink
============================
Beside accessing the SWD pins direct like explained on
https://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe
an updated bootloader can also be programmed via DFU. This requires three
steps:
1. Prepare bootloader update
Normal BMP has to be replaced by the upgrade programm:
dfu-util -s 0x08002000:leave -D dfu_upgrade.bin
Wait until Dual color led flashes red, indicating DFU is active for the
bootloader.
2. Flash new bootloader
dfu-util -s 0x08000000 -D blackmagic_dfu.bin
Wait until Dual color led flashes green, indicating bootloader is active.
If not, unplug USB, keep black reset button pressed, replug USB.
Wait until Dual color led flashes green.
3. Flash BMP
dfu-util -s 0x08002000:leave:force -D blackmagic.bin

View File

@ -20,14 +20,15 @@ SRC += cdcacm.c \
serialno.c \
timing.c \
timing_stm32.c \
stlink_common.c \
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex
blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o
blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o stlink_common.o
@echo " LD $@"
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o
dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o stlink_common.o
@echo " LD $@"
$(Q)$(CC) $^ -o $@ $(LDFLAGS)

View File

@ -24,84 +24,40 @@
#include <libopencm3/cm3/scb.h>
#include "usbdfu.h"
uint32_t app_address = 0x08000000;
#include "general.h"
#include "platform.h"
static uint8_t rev;
static uint16_t led_idle_run;
uint32_t app_address = 0x08000000;
static uint16_t led_upgrade;
static uint32_t led2_state = 0;
extern uint32_t _stack;
static uint32_t rev;
void dfu_detach(void)
{
/* Disconnect USB cable by resetting USB Device
and pulling USB_DP low*/
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
/* Pull PB0 (T_NRST) low
*/
rcc_periph_clock_enable(RCC_GPIOB);
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0);
gpio_clear(GPIOB, GPIO0);
SCB_VTOR = 0;
platform_request_boot();
scb_reset_core();
}
void stlink_set_rev(void)
{
int i;
/* First, get Board revision by pulling PC13/14 up. Read
* 11 for ST-Link V1, e.g. on VL Discovery, tag as rev 0
* 10 for ST-Link V2, e.g. on F4 Discovery, tag as rev 1
*/
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(GPIOC, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, GPIO14 | GPIO13);
gpio_set(GPIOC, GPIO14 | GPIO13);
for (i = 0; i < 100; i++)
rev = (~(gpio_get(GPIOC, GPIO14 | GPIO13)) >> 13) & 3;
switch (rev) {
case 0:
led_idle_run = GPIO8;
break;
default:
led_idle_run = GPIO9;
}
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
}
int main(void)
{
rev = detect_rev();
rcc_clock_setup_in_hse_8mhz_out_72mhz();
stlink_set_rev();
if (rev == 0)
led_upgrade = GPIO8;
else
led_upgrade = GPIO9;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000);
dfu_protect(UPD_MODE);
/* Handle USB disconnect/connect */
/* Just in case: Disconnect USB cable by resetting USB Device
* and pulling USB_DP low
* Device will reconnect automatically as Pull-Up is hard wired*/
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
systick_interrupt_enable();
systick_counter_enable();
if (rev > 1) /* Reconnect USB */
gpio_set(GPIOA, GPIO15);
dfu_init(&stm32f103_usb_driver, UPD_MODE);
dfu_main();
@ -114,15 +70,15 @@ void dfu_event(void)
void sys_tick_handler(void)
{
if (rev == 0) {
gpio_toggle(GPIOA, led_idle_run);
gpio_toggle(GPIOA, led_upgrade);
} else {
if (led2_state & 1) {
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
gpio_set(GPIOA, led_idle_run);
GPIO_CNF_OUTPUT_PUSHPULL, led_upgrade);
gpio_set(GPIOA, led_upgrade);
} else {
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_ANALOG, led_idle_run);
GPIO_CNF_INPUT_ANALOG, led_upgrade);
}
led2_state++;
}

View File

@ -34,56 +34,26 @@
#include <libopencm3/stm32/adc.h>
uint8_t running_status;
volatile uint32_t timeout_counter;
uint16_t led_idle_run;
/* Pins PC[14:13] are used to detect hardware revision. Read
* 11 for STLink V1 e.g. on VL Discovery, tag as hwversion 0
* 10 for STLink V2 e.g. on F4 Discovery, tag as hwversion 1
*/
uint16_t srst_pin;
static uint32_t rev;
int platform_hwversion(void)
{
static int hwversion = -1;
int i;
if (hwversion == -1) {
gpio_set_mode(GPIOC, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, GPIO14 | GPIO13);
gpio_set(GPIOC, GPIO14 | GPIO13);
for (i = 0; i<10; i++)
hwversion = ~(gpio_get(GPIOC, GPIO14 | GPIO13) >> 13) & 3;
switch (hwversion)
{
case 0:
led_idle_run = GPIO8;
break;
default:
led_idle_run = GPIO9;
}
}
return hwversion;
return rev;
}
void platform_init(void)
{
rev = detect_rev();
rcc_clock_setup_in_hse_8mhz_out_72mhz();
/* Enable peripherals */
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_CRC);
/* On Rev 1 unconditionally activate MCO on PORTA8 with HSE
* platform_hwversion() also needed to initialize led_idle_run!
*/
if (platform_hwversion() == 1)
{
RCC_CFGR &= ~(0xf << 24);
RCC_CFGR |= (RCC_CFGR_MCO_HSECLK << 24);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8);
if (rev == 0) {
led_idle_run = GPIO8;
srst_pin = SRST_PIN_V1;
} else {
led_idle_run = GPIO9;
srst_pin = SRST_PIN_V2;
}
/* Setup GPIO ports */
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ,
@ -92,8 +62,6 @@ void platform_init(void)
GPIO_CNF_OUTPUT_PUSHPULL, TCK_PIN);
gpio_set_mode(TDI_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, TDI_PIN);
uint16_t srst_pin = platform_hwversion() == 0 ?
SRST_PIN_V1 : SRST_PIN_V2;
gpio_set(SRST_PORT, srst_pin);
gpio_set_mode(SRST_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, srst_pin);
@ -106,51 +74,26 @@ void platform_init(void)
SCB_VTOR = (uint32_t)&vector_table;
platform_timing_init();
if (rev > 1) /* Reconnect USB */
gpio_set(GPIOA, GPIO15);
cdcacm_init();
usbuart_init();
}
void platform_srst_set_val(bool assert)
{
uint16_t pin;
pin = platform_hwversion() == 0 ? SRST_PIN_V1 : SRST_PIN_V2;
if (assert)
gpio_clear(SRST_PORT, pin);
gpio_clear(SRST_PORT, srst_pin);
else
gpio_set(SRST_PORT, pin);
gpio_set(SRST_PORT, srst_pin);
}
bool platform_srst_get_val()
{
uint16_t pin;
pin = platform_hwversion() == 0 ? SRST_PIN_V1 : SRST_PIN_V2;
return gpio_get(SRST_PORT, pin) == 0;
return gpio_get(SRST_PORT, srst_pin) == 0;
}
const char *platform_target_voltage(void)
{
return "unknown";
}
void platform_request_boot(void)
{
/* Disconnect USB cable by resetting USB Device and pulling USB_DP low*/
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
/* Assert bootloader pin */
uint32_t crl = GPIOA_CRL;
rcc_periph_clock_enable(RCC_GPIOA);
/* Enable Pull on GPIOA1. We don't rely on the external pin
* really pulled, but only on the value of the CNF register
* changed from the reset value
*/
crl &= 0xffffff0f;
crl |= 0x80;
GPIOA_CRL = crl;
}

View File

@ -110,6 +110,8 @@ extern uint16_t led_idle_run;
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, led_idle_run, state);}
#define SET_ERROR_STATE(x)
extern uint32_t detect_rev(void);
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf

View File

@ -0,0 +1,102 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2017 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
*
* 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
* 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,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
/* return 0 for stlink V1, 1 for stlink V2 and 2 for stlink V2.1 */
uint32_t detect_rev(void)
{
uint32_t rev;
int res;
while (RCC_CFGR & 0xf) /* Switch back to HSI. */
RCC_CFGR &= ~3;
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_CRC);
/* First, get Board revision by pulling PC13/14 up. Read
* 11 for ST-Link V1, e.g. on VL Discovery, tag as rev 0
* 00 for ST-Link V2, e.g. on F4 Discovery, tag as rev 1
* 01 for ST-Link V2, else, tag as rev 1
*/
gpio_set_mode(GPIOC, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, GPIO14 | GPIO13);
gpio_set(GPIOC, GPIO14 | GPIO13);
for (int i = 0; i < 100; i ++)
res = gpio_get(GPIOC, GPIO13);
if (res)
rev = 0;
else {
/* Check for V2.1 boards.
* PA15/TDI is USE_RENUM, pulled with 10 k to U5V on V2.1,
* Otherwise unconnected. Enable pull low. If still high.
* it is V2.1.*/
rcc_periph_clock_enable(RCC_AFIO);
AFIO_MAPR |= 0x02000000; /* Release from TDI.*/
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, GPIO15);
gpio_clear(GPIOA, GPIO15);
for (int i = 0; i < 100; i++)
res = gpio_get(GPIOA, GPIO15);
if (res) {
rev = 2;
/* Pull PWR_ENn low.*/
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO15);
gpio_clear(GPIOB, GPIO15);
/* Pull USB_RENUM low!*/
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO15);
gpio_clear(GPIOA, GPIO15);
} else
/* Catch F4 Disco board with both resistors fitted.*/
rev = 1;
/* On Rev > 0 unconditionally activate MCO on PORTA8 with HSE! */
RCC_CFGR &= ~(0xf << 24);
RCC_CFGR |= (RCC_CFGR_MCO_HSECLK << 24);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8);
}
if (rev < 2) {
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
}
return rev;
}
void platform_request_boot(void)
{
uint32_t crl = GPIOA_CRL;
/* Assert bootloader marker.
* Enable Pull on GPIOA1. We don't rely on the external pin
* really pulled, but only on the value of the CNF register
* changed from the reset value
*/
crl &= 0xffffff0f;
crl |= 0x80;
GPIOA_CRL = crl;
SCB_VTOR = 0;
}

View File

@ -24,108 +24,57 @@
#include <libopencm3/cm3/scb.h>
#include "usbdfu.h"
#include "general.h"
#include "platform.h"
static uint8_t rev;
static uint16_t led_idle_run;
static uint32_t rev;
static uint16_t led_bootloader;
static uint16_t pin_nrst;
static uint32_t led2_state = 0;
uint32_t app_address = 0x08002000;
static int stlink_test_nrst(void)
static bool stlink_test_nrst(void)
{
/* Test if JRST/NRST is pulled down*/
uint16_t nrst;
uint16_t pin;
uint32_t systick_value;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(0xffffff); /* no underflow for about 16.7 seconds*/
systick_counter_enable();
/* systick ist now running with 1 MHz, systick counts down */
/* First, get Board revision by pulling PC13/14 up. Read
* 11 for ST-Link V1, e.g. on VL Discovery, tag as rev 0
* 10 for ST-Link V2, e.g. on F4 Discovery, tag as rev 1
*/
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(GPIOC, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, GPIO14 | GPIO13);
gpio_set(GPIOC, GPIO14 | GPIO13);
systick_value = systick_get_value();
while (systick_get_value() > (systick_value - 1000)); /* Wait 1 msec*/
rev = (~(gpio_get(GPIOC, GPIO14 | GPIO13)) >> 13) & 3;
switch (rev) {
case 0:
pin = GPIO1;
led_idle_run = GPIO8;
break;
default:
pin = GPIO0;
led_idle_run = GPIO9;
}
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
rcc_periph_clock_enable(RCC_GPIOB);
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, pin | GPIO15);
if (gpio_get(GPIOB, GPIO15)) {
/* ST890 is active low */
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
gpio_clear(GPIOB, GPIO15);
}
gpio_set(GPIOB, pin);
systick_value = systick_get_value();
while (systick_get_value() > (systick_value - 20000)); /* Wait 20 msec*/
nrst = gpio_get(GPIOB, pin);
systick_counter_disable();
return (nrst) ? 1 : 0;
GPIO_CNF_INPUT_PULL_UPDOWN, pin_nrst);
gpio_set(GPIOB, pin_nrst);
for (int i = 0; i < 10000; i++)
nrst = gpio_get(GPIOB, pin_nrst);
return (nrst) ? true : false;
}
void dfu_detach(void)
{
/* Disconnect USB cable by resetting USB Device
and pulling USB_DP low*/
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
scb_reset_system();
}
int main(void)
{
/* Check the force bootloader pin*/
rcc_periph_clock_enable(RCC_GPIOA);
/* Check value of GPIOA1 configuration. This pin is unconnected on
* STLink V1 and V2. If we have a value other than the reset value (0x4),
* we have a warm start and request Bootloader entry
*/
rev = detect_rev();
if (rev == 0) {
led_bootloader = GPIO8;
pin_nrst = GPIO1;
} else {
led_bootloader = GPIO9;
pin_nrst = GPIO0;
}
if(((GPIOA_CRL & 0x40) == 0x40) && stlink_test_nrst())
dfu_jump_app_if_valid();
dfu_protect(DFU_MODE);
rcc_clock_setup_in_hse_8mhz_out_72mhz();
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000);
/* Handle USB disconnect/connect */
/* Just in case: Disconnect USB cable by resetting USB Device
* and pulling USB_DP low
* Device will reconnect automatically as Pull-Up is hard wired*/
rcc_periph_reset_pulse(RST_USB);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
systick_interrupt_enable();
systick_counter_enable();
if (rev > 1)
gpio_set(GPIOA, GPIO15);
dfu_init(&stm32f103_usb_driver, DFU_MODE);
dfu_main();
@ -138,16 +87,16 @@ void dfu_event(void)
void sys_tick_handler(void)
{
if (rev == 0) {
gpio_toggle(GPIOA, led_idle_run);
gpio_toggle(GPIOA, led_bootloader);
} else {
if (led2_state & 1) {
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
GPIO_CNF_OUTPUT_PUSHPULL, led_bootloader);
gpio_clear(GPIOA, led_bootloader);
} else {
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_ANALOG, led_idle_run);
GPIO_CNF_INPUT_ANALOG, led_bootloader);
}
led2_state++;
}
}