Merge pull request #281 from UweBonnes/nucleo144

stlink: Use common initialization and detect V2.1 boards.
This commit is contained in:
Gareth McMullin 2017-09-23 10:36:46 +12:00 committed by GitHub
commit 98ab873784
8 changed files with 213 additions and 224 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

@ -24,16 +24,30 @@ Ignoring the chip marking and using an F103C8 blindly as a F103Cb is done
already with few problems on many china boards (e.g. blue pill). Probably
this second approach will work for many of the older STLinks.
Use at your own risk!
dfu-util cares for the size and refuses to programm above the announced size:
> dfu-util -S E4D078EA -s 0x08002000:leave -D blackmagic.bin
dfu-util 0.9
...
dfu-util: Last page at 0x0801093f is not writeable
With DFU upload available in the bootloader, you can verify by uploading the
binary from flash and comparing it against the binary downloaded.
- Download new BMP binary (if not already done)
dfu-util -s 0x08002000:leave:force -D blackmagic.bin
- Get length of binary
Flash above the announced size with recent bootloader/BMP:
==========================================================
script/stm32_mem.py does not care for the announced size:
> ../scripts/stm32_mem.py blackmagic.bin
...
USB Device Firmware Upgrade - Host Utility -- version 1.2
...
Programming memory at 0x08010800
All operations complete!
Get length of binary
> ls -l blackmagic.bin
-rwxr-xr-x 1 bon users 57372 15. Apr 14:17 blackmagic.bin
- Upload binary from flash
> dfu-util -s 0x08002000:leave:force:57372 -U blackmagic.bin.1
- Compare
-rwxr-xr-x 1 bon users 59712 21. Sep 22:47 blackmagic.bin
Actual file size may differ!
Upload binary from flash with the exact size
> dfu-util -s 0x08002000:leave:force:59712 -U blackmagic.bin.1
Compare
> diff blackmagic.bin*
No differences should get reported!

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++;
}
}