Merge pull request #12 from UweBonnes/master

Make adaption to different STM32 boards easier
This commit is contained in:
Gareth McMullin 2013-02-18 00:49:35 -08:00
commit acda4bd46c
47 changed files with 2788 additions and 839 deletions

6
.gitignore vendored
View File

@ -1,3 +1,9 @@
blackmagic
blackmagic.bin
blackmagic_dfu
blackmagic_dfu.bin
blackmagic_dfu.hex
mapfile
*.o *.o
*.d *.d
.*.swp .*.swp

15
HACKING
View File

@ -9,6 +9,11 @@ resides in the 'src' directory.
Compiling for the native hardware Compiling for the native hardware
--------------------------------- ---------------------------------
Run
git submodule init
git submodule update
after cloning blackmagic to fill the libopencm3 directory.
To build the firmware for the standard hardware platform run 'make' in the To build the firmware for the standard hardware platform run 'make' in the
src directory. You will require a GCC cross compiler for ARM Cortex-M3 src directory. You will require a GCC cross compiler for ARM Cortex-M3
targets. You will also need to have the libopenstm32 library installed. targets. You will also need to have the libopenstm32 library installed.
@ -39,6 +44,16 @@ over USB:
The device should reset and re-enumerate as a CDC-ACM device implementing The device should reset and re-enumerate as a CDC-ACM device implementing
the GDB protocol. the GDB protocol.
Errors when compiling libopencm3
-------------------------------
If while compiling libopencm3 you get an error like
arm-none-eabi/bin/ld: error: cdcacm.elf uses VFP register arguments, \
arm-none-eabi/lib/thumb/v7m/libc.a(lib_a-memcpy-stub.o) does not
your toolchain and libopencm3 disagree on the calling convention for floation
point functions on the F4. Change in
lib/stm32/f4/Makefile and examples/stm32/f4/Makefile.include all apperance of
-mfloat-abi=hard to -mfloat-abi=soft
This doesn't matter for blackmagic, as it doesn't use floating point.
Compiling as a Linux application using FT2232 hardware Compiling as a Linux application using FT2232 hardware
------------------------------------------------------ ------------------------------------------------------

5
README
View File

@ -38,6 +38,11 @@ instead of JTAG to connect to the target.
Once attached, all the standard GDB commands may be used to start and control Once attached, all the standard GDB commands may be used to start and control
the execution of the embedded application. the execution of the embedded application.
The peripheral registers are not included in the memory map provided to GDB.
I suggest you add the command "set mem inaccessible-by-default off' to
your '.gdbinit'. That will allow you to access addresses outside of
the memory map. It will treat anything outside of the memory map as
RAM.
Project layout Project layout
============== ==============

View File

@ -21,6 +21,7 @@ from time import sleep
import struct import struct
from sys import stdout, argv from sys import stdout, argv
import argparse
import usb import usb
import dfu import dfu
@ -60,11 +61,15 @@ def stm32_manifest(dev):
if __name__ == "__main__": if __name__ == "__main__":
print print
print "USB Device Firmware Upgrade - Host Utility -- version 1.1" print "USB Device Firmware Upgrade - Host Utility -- version 1.2"
print "Copyright (C) 2011 Black Sphere Technologies" print "Copyright (C) 2011 Black Sphere Technologies"
print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>" print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print print
parser = argparse.ArgumentParser()
parser.add_argument("progfile", help="Binary file to program")
parser.add_argument("-s", "--serial_target", help="Match Serial Number")
args = parser.parse_args()
devs = dfu.finddevs() devs = dfu.finddevs()
if not devs: if not devs:
print "No devices found!" print "No devices found!"
@ -73,13 +78,22 @@ if __name__ == "__main__":
for dev in devs: for dev in devs:
dfudev = dfu.dfu_device(*dev) dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30) man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 30) product = dfudev.handle.getString(dfudev.dev.iProduct, 64)
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
if args.serial_target:
if man == "Black Sphere Technologies" and serial_no == args.serial_target: break
if man == "STMicroelectronics" and serial_no == args.serial_target: break
else:
if man == "Black Sphere Technologies": break if man == "Black Sphere Technologies": break
if man == "STMicroelectronics": break if man == "STMicroelectronics": break
print "Device %s: ID %04x:%04x %s - %s" % (dfudev.dev.filename, print "Device %s: ID %04x:%04x %s - %s\n\tSerial %s" % (
dfudev.dev.idVendor, dfudev.dev.idProduct, man, product) dfudev.dev.filename, dfudev.dev.idVendor,
dfudev.dev.idProduct, man, product, serial_no)
if args.serial_target and serial_no != args.serial_target:
print "Serial number doesn't match!\n"
exit(-2)
try: try:
state = dfudev.get_state() state = dfudev.get_state()
except: except:
@ -92,13 +106,20 @@ if __name__ == "__main__":
dfudev.make_idle() dfudev.make_idle()
bin = open(argv[1], "rb").read() bin = open(args.progfile, "rb").read()
if product.find("F4") :
addr = 0x8004000
else:
addr = 0x8002000 addr = 0x8002000
while bin: while bin:
print ("Programming memory at 0x%08X\r" % addr), print ("Programming memory at 0x%08X\r" % addr),
stdout.flush() stdout.flush()
try:
stm32_erase(dfudev, addr) stm32_erase(dfudev, addr)
except:
print "\nErase Timed out\n"
break
stm32_write(dfudev, bin[:1024]) stm32_write(dfudev, bin[:1024])
bin = bin[1024:] bin = bin[1024:]

View File

@ -47,6 +47,7 @@ blackmagic: $(OBJ)
clean: host_clean clean: host_clean
$(RM) *.o *.d *~ blackmagic $(HOSTFILES) $(RM) *.o *.d *~ blackmagic $(HOSTFILES)
$(RM) platforms/*/*.o platforms/*/*.d mapfile
-include *.d -include *.d

View File

@ -21,6 +21,7 @@
#include "platform.h" #include "platform.h"
#include "target.h" #include "target.h"
#if !defined(STM32F1) && !defined(STM32F4)
static const uint32_t crc32_table[] = { static const uint32_t crc32_table[] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
@ -107,4 +108,31 @@ uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
} }
return crc; return crc;
} }
#else
#include <libopencm3/stm32/crc.h>
uint32_t generic_crc32(struct target_s *target, uint32_t base, int len)
{
uint32_t data;
uint8_t byte;
CRC_CR |= CRC_CR_RESET;
while (len >3) {
if (target_mem_read_words(target, &data, base, 1) != 0)
return -1;
CRC_DR = data;
base+=4;
len -= 4;
}
while (len--) {
if (target_mem_read_bytes(target, &byte, base, 1) != 0)
return -1;
CRC_DR = byte;
base++;
}
return CRC_DR;
}
#endif

View File

@ -21,6 +21,11 @@
#ifndef __GDB_IF_H #ifndef __GDB_IF_H
#define __GDB_IF_H #define __GDB_IF_H
#if !defined(LIBFTDI)
#include <libopencm3/usb/usbd.h>
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
#endif
int gdb_if_init(void); int gdb_if_init(void);
unsigned char gdb_if_getchar(void); unsigned char gdb_if_getchar(void);
unsigned char gdb_if_getchar_to(int timeout); unsigned char gdb_if_getchar_to(int timeout);

View File

@ -26,4 +26,3 @@ void traceswo_init(void);
void trace_buf_drain(usbd_device *dev, uint8_t ep); void trace_buf_drain(usbd_device *dev, uint8_t ep);
#endif #endif

View File

@ -31,4 +31,3 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep);
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep); void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep);
#endif #endif

View File

@ -58,6 +58,8 @@ static struct jtag_dev_descr_s {
.descr = "ST Microelectronics: STM32, Low density."}, .descr = "ST Microelectronics: STM32, Low density."},
{.idcode = 0x06414041, .idmask = 0x0FFFFFFF, {.idcode = 0x06414041, .idmask = 0x0FFFFFFF,
.descr = "ST Microelectronics: STM32, High density."}, .descr = "ST Microelectronics: STM32, High density."},
{.idcode = 0x06416041, .idmask = 0x0FFFFFFF,
.descr = "ST Microelectronics: STM32L."},
{.idcode = 0x06418041, .idmask = 0x0FFFFFFF, {.idcode = 0x06418041, .idmask = 0x0FFFFFFF,
.descr = "ST Microelectronics: STM32, Connectivity Line."}, .descr = "ST Microelectronics: STM32, Connectivity Line."},
{.idcode = 0x06420041, .idmask = 0x0FFFFFFF, {.idcode = 0x06420041, .idmask = 0x0FFFFFFF,

View File

@ -34,10 +34,15 @@
#include "target.h" #include "target.h"
int int
main(void) main(int argc, char **argv)
{ {
#if defined(LIBFTDI)
assert(platform_init(argc, argv) == 0);
#else
(void) argc;
(void) argv;
assert(platform_init() == 0); assert(platform_init() == 0);
#endif
PLATFORM_SET_FATAL_ERROR_RECOVERY(); PLATFORM_SET_FATAL_ERROR_RECOVERY();
gdb_main(); gdb_main();

View File

@ -0,0 +1,36 @@
CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
-DSTM32F4 -DF4DISCOVERY -I../libopencm3/include
LDFLAGS_BOOT = -lopencm3_stm32f4 -Wl,--defsym,_stack=0x20020000 \
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \
-L../libopencm3/lib
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8010000
VPATH += platforms/stm32
SRC += cdcacm.c \
platform.c \
traceswo.c \
usbuart.c \
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic.bin: blackmagic
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu: usbdfu.o
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
host_clean:
-rm blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex

View File

@ -0,0 +1,17 @@
Application start address:
=========================
Use 0x8010000
- lower 3 16 k pages may be used for parameter storage
- Erasing a single 64 k Page is faster then erasing 2 16 k Pages
eventual the 64 k page
Internal boot loader:
====================
When we request invokation of a bootloader from inside the application,
we boot the device internal bootloader with the blue botton pressed.
That way, we can easy exchange the custom bootloader via the device
internale bootloader

View File

@ -0,0 +1,208 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/syscfg.h>
#include <libopencm3/usb/usbd.h>
#include "platform.h"
#include "jtag_scan.h"
#include <usbuart.h>
#include <ctype.h>
uint8_t running_status;
volatile uint32_t timeout_counter;
jmp_buf fatal_error_jmpbuf;
static void morse_update(void);
int platform_init(void)
{
rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
/* Enable peripherals */
rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN);
/* Set up USB Pins and alternate function*/
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
GPIO9 | GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
GPIOA_OSPEEDR &=~0xfc;
GPIOA_OSPEEDR |= 0xa8;
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
TMS_PIN | TCK_PIN | TDI_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE,
TDO_PIN);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
LED_UART | LED_IDLE_RUN | LED_ERROR | LED_SPARE1);
/* Setup heartbeat timer */
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(168000000/(10*8)); /* Interrupt us at 10 Hz */
SCB_SHPR(11) &= ~((15 << 4) & 0xff);
SCB_SHPR(11) |= ((14 << 4) & 0xff);
systick_interrupt_enable();
systick_counter_enable();
usbuart_init();
SCB_VTOR = 0x10000; // Relocate interrupt vector table here
cdcacm_init();
jtag_scan(NULL);
return 0;
}
void platform_delay(uint32_t delay)
{
timeout_counter = delay;
while(timeout_counter);
}
void sys_tick_handler(void)
{
if(running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN);
if(timeout_counter)
timeout_counter--;
morse_update();
}
/* Morse code patterns and lengths */
static const struct {
uint16_t code;
uint8_t bits;
} morse_letter[] = {
{ 0b00011101, 8}, // 'A' .-
{ 0b000101010111, 12}, // 'B' -...
{ 0b00010111010111, 14}, // 'C' -.-.
{ 0b0001010111, 10}, // 'D' -..
{ 0b0001, 4}, // 'E' .
{ 0b000101110101, 12}, // 'F' ..-.
{ 0b000101110111, 12}, // 'G' --.
{ 0b0001010101, 10}, // 'H' ....
{ 0b000101, 6}, // 'I' ..
{0b0001110111011101, 16}, // 'J' .---
{ 0b000111010111, 12}, // 'K' -.-
{ 0b000101011101, 12}, // 'L' .-..
{ 0b0001110111, 10}, // 'M' --
{ 0b00010111, 8}, // 'N' -.
{ 0b00011101110111, 14}, // 'O' ---
{ 0b00010111011101, 14}, // 'P' .--.
{0b0001110101110111, 16}, // 'Q' --.-
{ 0b0001011101, 10}, // 'R' .-.
{ 0b00010101, 8}, // 'S' ...
{ 0b000111, 6}, // 'T' -
{ 0b0001110101, 10}, // 'U' ..-
{ 0b000111010101, 12}, // 'V' ...-
{ 0b000111011101, 12}, // 'W' .--
{ 0b00011101010111, 14}, // 'X' -..-
{0b0001110111010111, 16}, // 'Y' -.--
{ 0b00010101110111, 14}, // 'Z' --..
};
const char *morse_msg;
static const char * volatile morse_ptr;
static char morse_repeat;
void morse(const char *msg, char repeat)
{
morse_msg = morse_ptr = msg;
morse_repeat = repeat;
SET_ERROR_STATE(0);
}
static void morse_update(void)
{
static uint16_t code;
static uint8_t bits;
if(!morse_ptr) return;
if(!bits) {
char c = *morse_ptr++;
if(!c) {
if(morse_repeat) {
morse_ptr = morse_msg;
c = *morse_ptr++;
} else {
morse_ptr = 0;
return;
}
}
if((c >= 'A') && (c <= 'Z')) {
c -= 'A';
code = morse_letter[c].code;
bits = morse_letter[c].bits;
} else {
code = 0; bits = 4;
}
}
SET_ERROR_STATE(code & 1);
code >>= 1; bits--;
}
const char *platform_target_voltage(void)
{
return "ABSENT!";
}
void assert_boot_pin(void)
{
if (gpio_get(GPIOA, GPIO0)) {
/* Jump to the built in bootloader by mapping System flash */
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_SYSCFGEN);
SYSCFG_MEMRM &= ~3;
SYSCFG_MEMRM |= 1;
}
else {
/* Flag Bootloader Request by mimicing a pushed USER button*/
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO0);
gpio_set(GPIOA, GPIO0);
}
}

View File

@ -0,0 +1,213 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include <libopencm3/stm32/f4/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <setjmp.h>
#include <alloca.h>
#include "gdb_packet.h"
#define INLINE_GPIO
#define CDCACM_PACKET_SIZE 64
#define PLATFORM_HAS_TRACESWO
#define BOARD_IDENT "Black Magic Probe (F4Discovery), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (F4Discovery"
extern usbd_device *usbdev;
#define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3
/* Important pin mappings for STM32 implementation:
*
* LED0 = PD12 (Green LED : Running)
* LED1 = PD13 (Orange LED : Idle)
* LED2 = PD12 (Red LED : Error)
*
* TPWR = XXX (input) -- analogue on mini design ADC1, ch8
* nTRST = PD0
* SRST_OUT = PD1
* TDI = PA1
* TMS = PA3 (input for SWDP)
* TCK = PA8
* TDO = PB4 (input)
* nSRST = PD2 (input)
*
* USB cable pull-up: PA8
* USB VBUS detect: PB13 -- New on mini design.
* Enable pull up for compatibility.
* Force DFU mode button: PB12
*/
/* Hardware definitions... */
#define JTAG_PORT GPIOA
#define TDI_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT GPIOB
#define TDI_PIN GPIO1
#define TMS_PIN GPIO3
#define TCK_PIN GPIO2
#define TDO_PIN GPIO4
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_PIN TMS_PIN
#define SWCLK_PIN TCK_PIN
#define TRST_PORT GPIOD
#define TRST_PIN GPIO0
#define SRST_PORT GPIOD
#define SRST_PIN GPIO1
#define LED_PORT GPIOD
#define LED_PORT_UART GPIOD
#define LED_UART GPIO12
#define LED_IDLE_RUN GPIO13
#define LED_ERROR GPIO14
#define LED_SPARE1 GPIO15
#define TMS_SET_MODE() gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, TMS_PIN);
#define SWDIO_MODE_FLOAT() gpio_mode_setup(SWDIO_PORT, GPIO_MODE_INPUT, \
GPIO_PUPD_NONE, SWDIO_PIN);
#define SWDIO_MODE_DRIVE() gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN);
#define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority.
*/
#define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_APB_ENR RCC_APB1ENR
#define USBUSART_CLK_ENABLE RCC_APB1ENR_USART3EN
#define USBUSART_TX_PORT GPIOD
#define USBUSART_TX_PIN GPIO8
#define USBUSART_RX_PORT GPIOD
#define USBUSART_RX_PIN GPIO9
#define USBUSART_ISR usart3_isr
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN)
#define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR tim3_isr
#define DEBUG(...)
extern uint8_t running_status;
extern volatile uint32_t timeout_counter;
extern jmp_buf fatal_error_jmpbuf;
extern const char *morse_msg;
#define gpio_set_val(port, pin, val) do { \
if(val) \
gpio_set((port), (pin)); \
else \
gpio_clear((port), (pin)); \
} while(0)
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
#define PLATFORM_FATAL_ERROR(error) { \
if(running_status) gdb_putpacketz("X1D"); \
else gdb_putpacketz("EFF"); \
running_status = 0; \
target_list_free(); \
morse("TARGET LOST.", 1); \
longjmp(fatal_error_jmpbuf, (error)); \
}
int platform_init(void);
void morse(const char *msg, char repeat);
const char *platform_target_voltage(void);
int platform_hwversion(void);
void platform_delay(uint32_t delay);
/* <cdcacm.c> */
void cdcacm_init(void);
/* Returns current usb configuration, or 0 if not configured. */
int cdcacm_get_config(void);
int cdcacm_get_dtr(void);
/* <platform.h> */
void uart_usb_buf_drain(uint8_t ep);
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
#define vasprintf vasiprintf
#ifdef INLINE_GPIO
static inline void _gpio_set(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
#define gpio_set _gpio_set
static inline void _gpio_clear(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios<<16;
}
#define gpio_clear _gpio_clear
static inline u16 _gpio_get(u32 gpioport, u16 gpios)
{
return (u16)GPIO_IDR(gpioport) & gpios;
}
#define gpio_get _gpio_get
#endif
#endif
#define disconnect_usb() do {usbd_disconnect(usbdev,1); nvic_disable_irq(USB_IRQ);} while(0)
void assert_boot_pin(void);
#define setup_vbus_irq()

View File

@ -1 +1,2 @@
CFLAGS += -DLIBFTDI
LDFLAGS += -lftdi -lusb LDFLAGS += -lftdi -lusb

View File

@ -55,14 +55,6 @@ int jtagtap_init(void)
assert(ftdic != NULL); assert(ftdic != NULL);
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_MPSSE)) != 0) {
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
}
assert(ftdi_write_data(ftdic, "\x86\x00\x00\x80\xA8\xAB", 6) == 6);
/* Go to JTAG mode for SWJ-DP */ /* Go to JTAG mode for SWJ-DP */
for(int i = 0; i <= 50; i++) jtagtap_next(1, 0); /* Reset SW-DP */ for(int i = 0; i <= 50; i++) jtagtap_next(1, 0); /* Reset SW-DP */
jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */ jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */

View File

@ -32,9 +32,125 @@ struct ftdi_context *ftdic;
static uint8_t outbuf[BUF_SIZE]; static uint8_t outbuf[BUF_SIZE];
static uint16_t bufptr = 0; static uint16_t bufptr = 0;
int platform_init(void) static struct cable_desc_s {
int vendor;
int product;
int interface;
uint8_t dbus_data;
uint8_t dbus_ddr;
uint8_t cbus_data;
uint8_t cbus_ddr;
char *description;
char * name;
} cable_desc[] = {
{
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.description = "FTDIJTAG",
.name = "ftdijtag"
},
{
.vendor = 0x15b1,
.product = 0x0003,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.name = "olimex"
},
{
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.name = "turtelizer"
},
{
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.name = "jtaghs1"
},
{
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.dbus_data = 0xA8,
.dbus_ddr = 0xAB,
.name = "ftdi"
},
{
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x0B,
.name = "ft232h"
},
{
.vendor = 0x0403,
.product = 0x6011,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x0B,
.name = "ft4232h"
},
{
.vendor = 0x15ba,
.product = 0x002b,
.interface = INTERFACE_A,
.dbus_data = 0x08,
.dbus_ddr = 0x1B,
.cbus_data = 0x00,
.cbus_ddr = 0x08,
.name = "arm-usb-ocd-h"
},
};
int platform_init(int argc, char **argv)
{ {
int err; int err;
int c;
int index = 0;
char *serial = NULL;
char * cablename = "ftdi";
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
SET_BITS_HIGH, 0,0};
while((c = getopt(argc, argv, "c:s:")) != -1) {
switch(c) {
case 'c':
cablename = optarg;
break;
case 's':
serial = optarg;
break;
}
}
for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
index++)
if (strcmp(cable_desc[index].name, cablename) == 0)
break;
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])){
fprintf(stderr, "No cable matching %s found\n",cablename);
return -1;
}
if (cable_desc[index].dbus_data)
ftdi_init[4]= cable_desc[index].dbus_data;
if (cable_desc[index].dbus_ddr)
ftdi_init[5]= cable_desc[index].dbus_ddr;
if (cable_desc[index].cbus_data)
ftdi_init[7]= cable_desc[index].cbus_data;
if(cable_desc[index].cbus_ddr)
ftdi_init[8]= cable_desc[index].cbus_ddr;
if(ftdic) { if(ftdic) {
ftdi_usb_close(ftdic); ftdi_usb_close(ftdic);
@ -46,12 +162,14 @@ int platform_init(void)
ftdi_get_error_string(ftdic)); ftdi_get_error_string(ftdic));
abort(); abort();
} }
if((err = ftdi_set_interface(ftdic, INTERFACE_A)) != 0) { if((err = ftdi_set_interface(ftdic, cable_desc[index].interface)) != 0) {
fprintf(stderr, "ftdi_set_interface: %d: %s\n", fprintf(stderr, "ftdi_set_interface: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); abort();
} }
if((err = ftdi_usb_open(ftdic, FT2232_VID, FT2232_PID)) != 0) { if((err = ftdi_usb_open_desc(
ftdic, cable_desc[index].vendor, cable_desc[index].product,
cable_desc[index].description, serial)) != 0) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n", fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
abort(); abort();
@ -78,6 +196,14 @@ int platform_init(void)
abort(); abort();
} }
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_MPSSE)) != 0) {
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
}
assert(ftdi_write_data(ftdic, ftdi_init, 9) == 9);
assert(gdb_if_init() == 0); assert(gdb_if_init() == 0);
jtag_scan(NULL); jtag_scan(NULL);

View File

@ -40,12 +40,12 @@
#define PLATFORM_FATAL_ERROR(error) abort() #define PLATFORM_FATAL_ERROR(error) abort()
#define PLATFORM_SET_FATAL_ERROR_RECOVERY() #define PLATFORM_SET_FATAL_ERROR_RECOVERY()
#define morse(x, y) do {} while(0) #define morse(x, y) fprintf(stderr,"%s\n", x)
#define morse_msg 0 #define morse_msg 0
extern struct ftdi_context *ftdic; extern struct ftdi_context *ftdic;
int platform_init(void); int platform_init(int argc, char **argv);
const char *platform_target_voltage(void); const char *platform_target_voltage(void);
void platform_delay(uint32_t delay); void platform_delay(uint32_t delay);

View File

@ -3,7 +3,8 @@ CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -I../libopencm3/include -DSTM32F1 -DBLACKMAGIC -I../libopencm3/include
LDFLAGS_BOOT = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20005000 \ LDFLAGS_BOOT = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20005000 \
-Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc -lnosys \ -Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \

View File

@ -26,13 +26,14 @@
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h> #include <libopencm3/stm32/usart.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/f1/adc.h> #include <libopencm3/stm32/f1/adc.h>
#include "platform.h" #include "platform.h"
#include "jtag_scan.h" #include "jtag_scan.h"
#include "usbuart.h" #include <usbuart.h>
#include <ctype.h> #include <ctype.h>
@ -262,3 +263,44 @@ const char *platform_target_voltage(void)
return ret; return ret;
} }
void assert_boot_pin(void)
{
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOB, GPIO12);
}
void exti15_10_isr(void)
{
if (gpio_get(USB_VBUS_PORT, USB_VBUS_PIN)) {
/* Drive pull-up high if VBUS connected */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
} else {
/* Allow pull-up to float if VBUS disconnected */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
}
exti_reset_request(USB_VBUS_PIN);
}
void setup_vbus_irq(void)
{
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS);
nvic_enable_irq(USB_VBUS_IRQ);
gpio_set(USB_VBUS_PORT, USB_VBUS_PIN);
gpio_set(USB_PU_PORT, USB_PU_PIN);
gpio_set_mode(USB_VBUS_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, USB_VBUS_PIN);
/* Configure EXTI for USB VBUS monitor */
exti_select_source(USB_VBUS_PIN, USB_VBUS_PORT);
exti_set_trigger(USB_VBUS_PIN, EXTI_TRIGGER_BOTH);
exti_enable_request(USB_VBUS_PIN);
exti15_10_isr();
}

View File

@ -35,6 +35,8 @@
#define INLINE_GPIO #define INLINE_GPIO
#define CDCACM_PACKET_SIZE 64 #define CDCACM_PACKET_SIZE 64
#define PLATFORM_HAS_TRACESWO #define PLATFORM_HAS_TRACESWO
#define BOARD_IDENT "Black Magic Probe, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")"
#define DFU_IDENT "Black Magic Firmware Upgrade"
extern usbd_device *usbdev; extern usbd_device *usbdev;
#define CDCACM_GDB_ENDPOINT 1 #define CDCACM_GDB_ENDPOINT 1
@ -90,18 +92,50 @@ extern usbd_device *usbdev;
#define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ #define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ
#define LED_PORT GPIOB #define LED_PORT GPIOB
#define LED_PORT_UART GPIOB
#define LED_UART GPIO2 #define LED_UART GPIO2
#define LED_IDLE_RUN GPIO10 #define LED_IDLE_RUN GPIO10
#define LED_ERROR GPIO11 #define LED_ERROR GPIO11
#define TMS_SET_MODE() \
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN);
#define SWDIO_MODE_FLOAT() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_INPUT, \
GPIO_CNF_INPUT_FLOAT, SWDIO_PIN);
#define SWDIO_MODE_DRIVE() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, SWDIO_PIN);
#define UART_PIN_SETUP() \
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_2_MHZ, \
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN);
#define USB_DRIVER stm32f103_usb_driver
#define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ
#define USB_ISR usb_lp_can_rx0_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained. * For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USART1 (1 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USB_VBUS (14 << 4) #define IRQ_PRI_USB_VBUS (14 << 4)
#define IRQ_PRI_TIM3 (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART1
#define USBUSART_CR1 USART1_CR1
#define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_APB_ENR RCC_APB2ENR
#define USBUSART_CLK_ENABLE RCC_APB2ENR_USART1EN
#define USBUSART_PORT GPIOA
#define USBUSART_TX_PIN GPIO9
#define USBUSART_ISR usart1_isr
#define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN)
#define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR tim3_isr
#define DEBUG(...) #define DEBUG(...)
@ -175,3 +209,6 @@ static inline u16 _gpio_get(u32 gpioport, u16 gpios)
#endif #endif
#define disconnect_usb() gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT, 0, USB_PU_PIN);
void assert_boot_pin(void);
void setup_vbus_irq(void);

View File

@ -1,333 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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 <string.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/stm32/f1/gpio.h>
#include <libopencm3/stm32/f1/flash.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/dfu.h>
#define APP_ADDRESS 0x08002000
/* Commands sent with wBlockNum == 0 as per ST implementation. */
#define CMD_SETADDR 0x21
#define CMD_ERASE 0x41
#define FLASH_OBP_RDP 0x1FFFF800
#define FLASH_OBP_WRP10 0x1FFFF808
#define FLASH_OBP_RDP_KEY 0x5aa5
usbd_device *usbdev;
/* We need a special large control buffer for this device: */
u8 usbd_control_buffer[1024];
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
static char *get_dev_unique_id(char *serial_no);
static struct {
u8 buf[sizeof(usbd_control_buffer)];
u16 len;
u32 addr;
u16 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 = 0x6017,
.bcdDevice = 0x0100,
.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 = 1024,
.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),
};
const struct usb_interface ifaces[] = {{
.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,
};
static char serial_no[9];
static const char *usb_strings[] = {
"Black Sphere Technologies",
"Black Magic Probe (Upgrade)",
serial_no,
/* This string is used by ST Microelectronics' DfuSe utility */
"@Internal Flash /0x08000000/8*001Ka,120*001Kg"
};
static u8 usbdfu_getstatus(u32 *bwPollTimeout)
{
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;
}
}
static void
usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req)
{
int i;
(void)req;
switch(usbdfu_state) {
case STATE_DFU_DNBUSY:
flash_unlock();
if(prog.blocknum == 0) {
if ((*(u32*)(prog.buf+1) < 0x8002000) ||
(*(u32*)(prog.buf+1) >= 0x8020000)) {
usbd_ep_stall_set(dev, 0, 1);
return;
}
switch(prog.buf[0]) {
case CMD_ERASE:
flash_erase_page(*(u32*)(prog.buf+1));
case CMD_SETADDR:
prog.addr = *(u32*)(prog.buf+1);
}
} else {
u32 baseaddr = prog.addr +
((prog.blocknum - 2) *
dfu_function.wTransferSize);
for(i = 0; i < prog.len; i += 2)
flash_program_half_word(baseaddr + i,
*(u16*)(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:
/* USB device must detach, we just reset... */
scb_reset_system();
return; /* Will never return */
default:
return;
}
}
static int usbdfu_control_request(usbd_device *dev,
struct usb_setup_data *req, u8 **buf, u16 *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
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: {
u32 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;
}
int main(void)
{
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
if(gpio_get(GPIOB, GPIO12)) {
/* Boot the application if it's valid */
if((*(volatile u32*)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address */
SCB_VTOR = APP_ADDRESS & 0xFFFF;
/* Initialise master stack pointer */
asm volatile ("msr msp, %0"::"g"
(*(volatile u32*)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);
}
rcc_clock_setup_in_hse_8mhz_out_72mhz();
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO8);
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO11);
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000);
systick_interrupt_enable();
systick_counter_enable();
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO2 | GPIO10);
get_dev_unique_id(serial_no);
usbdev = usbd_init(&stm32f103_usb_driver,
&dev, &config, usb_strings, 4);
usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer));
usbd_register_control_callback(usbdev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
usbdfu_control_request);
gpio_set(GPIOA, GPIO8);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO8);
while (1)
usbd_poll(usbdev);
}
static char *get_dev_unique_id(char *s)
{
volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8;
uint32_t unique_id = *unique_id_p +
*(unique_id_p + 1) +
*(unique_id_p + 2);
int i;
/* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
}
for(i = 0; i < 8; i++)
if(s[i] > '9')
s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
}
void sys_tick_handler()
{
gpio_toggle(GPIOB, GPIO11); /* LED2 on/off */
}

View File

@ -3,22 +3,33 @@ CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -mcpu=cortex-m3 -mthumb \ CFLAGS += -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -I../libopencm3/include -DSTM32F1 -DDISCOVERY_STLINK -I../libopencm3/include
LDFLAGS = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20005000 \ LDFLAGS_BOOT = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20005000 \
-Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc -lnosys \ -Wl,-T,platforms/stm32/stlink.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \
-L../libopencm3/lib -L../libopencm3/lib
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000
VPATH += platforms/stm32 VPATH += platforms/stm32
SRC += cdcacm.c \ SRC += cdcacm.c \
platform.c \ platform.c \
usbuart.c \
all: blackmagic.bin all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic.bin: blackmagic blackmagic.bin: blackmagic
$(OBJCOPY) -O binary $^ $@ $(OBJCOPY) -O binary $^ $@
host_clean: blackmagic_dfu: usbdfu.o
-rm blackmagic.bin $(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
host_clean:
-rm blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex

View File

@ -0,0 +1,11 @@
Find a description how to modify a Discovery Board to use it's Stlink as
black magic debug at
http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe
Differences between V1/V2
V1 V2
ID Pins PC13/14 unconnected PC 13 pulled low
LED STLINK PA8, active High PA9, Dual Led
MCO Out NA PA8
RESET(Target) T_JRST(PB1) NRST (PB0)

View File

@ -1,309 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements a the USB Communications Device Class - Abstract
* Control Model (CDC-ACM) as defined in CDC PSTN subclass 1.2.
* A Device Firmware Upgrade (DFU 1.1) class interface is provided for
* field firmware upgrade.
*
* The device's unique id is used as the USB serial number string.
*/
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/stm32/f1/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/f1/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/dfu.h>
#include <stdlib.h>
#include "platform.h"
usbd_device *usbdev;
static char *get_dev_unique_id(char *serial_no);
static int configured;
static int cdcacm_gdb_dtr = 1;
static const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0xEF, /* Miscellaneous Device */
.bDeviceSubClass = 2, /* Common Class */
.bDeviceProtocol = 1, /* Interface Association */
.bMaxPacketSize0 = 64,
.idVendor = 0x1D50,
.idProduct = 0x6018,
.bcdDevice = 0x0100,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1,
};
/* This notification endpoint isn't implemented. According to CDC spec its
* optional, but its absence causes a NULL pointer dereference in Linux cdc_acm
* driver. */
static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16,
.bInterval = 255,
}};
static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1,
}, {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1,
}};
static const struct {
struct usb_cdc_header_descriptor header;
struct usb_cdc_call_management_descriptor call_mgmt;
struct usb_cdc_acm_descriptor acm;
struct usb_cdc_union_descriptor cdc_union;
} __attribute__((packed)) gdb_cdcacm_functional_descriptors = {
.header = {
.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_HEADER,
.bcdCDC = 0x0110,
},
.call_mgmt = {
.bFunctionLength =
sizeof(struct usb_cdc_call_management_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
.bmCapabilities = 0,
.bDataInterface = 1,
},
.acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_ACM,
.bmCapabilities = 2, /* SET_LINE_CODING supported */
},
.cdc_union = {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
.bControlInterface = 0,
.bSubordinateInterface0 = 1,
}
};
static const struct usb_interface_descriptor gdb_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_CDC,
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 4,
.endpoint = gdb_comm_endp,
.extra = &gdb_cdcacm_functional_descriptors,
.extralen = sizeof(gdb_cdcacm_functional_descriptors)
}};
static const struct usb_interface_descriptor gdb_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
.endpoint = gdb_data_endp,
}};
static const struct usb_iface_assoc_descriptor gdb_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = 0,
.bInterfaceCount = 2,
.bFunctionClass = USB_CLASS_CDC,
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
.bFunctionProtocol = USB_CDC_PROTOCOL_AT,
.iFunction = 0,
};
static const struct usb_interface ifaces[] = {{
.num_altsetting = 1,
.iface_assoc = &gdb_assoc,
.altsetting = gdb_comm_iface,
}, {
.num_altsetting = 1,
.altsetting = gdb_data_iface,
}};
static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 2,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
.bMaxPower = 0x32,
.interface = ifaces,
};
char serial_no[9];
static const char *usb_strings[] = {
"Black Sphere Technologies",
"Black Magic Probe",
serial_no,
"Black Magic GDB Server",
};
static int cdcacm_control_request(usbd_device *dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
(void)complete;
(void)buf;
(void)len;
switch(req->bRequest) {
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
/* Ignore if not for GDB interface */
if(req->wIndex != 0)
return 1;
cdcacm_gdb_dtr = req->wValue & 1;
return 1;
case USB_CDC_REQ_SET_LINE_CODING:
if(*len < sizeof(struct usb_cdc_line_coding))
return 0;
switch(req->wIndex) {
case 0:
return 1; /* Ignore on GDB Port */
default:
return 0;
}
}
return 0;
}
int cdcacm_get_config(void)
{
return configured;
}
int cdcacm_get_dtr(void)
{
return cdcacm_gdb_dtr;
}
static void cdcacm_set_config(usbd_device *dev, u16 wValue)
{
configured = wValue;
/* GDB interface */
usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL);
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL);
usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
usbd_register_control_callback(dev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
cdcacm_control_request);
/* Notify the host that DCD is asserted.
* Allows the use of /dev/tty* devices on *BSD/MacOS
*/
char buf[10];
struct usb_cdc_notification *notif = (void*)buf;
/* We echo signals back to host as notification */
notif->bmRequestType = 0xA1;
notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
notif->wValue = 0;
notif->wIndex = 0;
notif->wLength = 2;
buf[8] = 3; /* DCD | DSR */
buf[9] = 0;
usbd_ep_write_packet(dev, 0x82, buf, 10);
}
void cdcacm_init(void)
{
void exti15_10_isr(void);
get_dev_unique_id(serial_no);
usbdev = usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings, 4);
usbd_register_set_config_callback(usbdev, cdcacm_set_config);
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
}
void usb_lp_can_rx0_isr(void)
{
usbd_poll(usbdev);
}
static char *get_dev_unique_id(char *s)
{
volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8;
uint32_t unique_id = *unique_id_p +
*(unique_id_p + 1) +
*(unique_id_p + 2);
int i;
/* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
}
for(i = 0; i < 8; i++)
if(s[i] > '9')
s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
}

View File

@ -25,13 +25,14 @@
#include <libopencm3/stm32/f1/rcc.h> #include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/f1/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/usart.h> #include <libopencm3/stm32/usart.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/f1/adc.h> #include <libopencm3/stm32/f1/adc.h>
#include "platform.h" #include "platform.h"
#include "jtag_scan.h" #include "jtag_scan.h"
#include <usbuart.h>
#include <ctype.h> #include <ctype.h>
@ -40,6 +41,34 @@ volatile uint32_t timeout_counter;
jmp_buf fatal_error_jmpbuf; jmp_buf fatal_error_jmpbuf;
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
*/
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;
}
int platform_init(void) int platform_init(void)
{ {
rcc_clock_setup_in_hse_8mhz_out_72mhz(); rcc_clock_setup_in_hse_8mhz_out_72mhz();
@ -48,7 +77,19 @@ int platform_init(void)
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN); rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN); rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
/* 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);
}
/* Setup GPIO ports */ /* Setup GPIO ports */
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN); GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN);
@ -58,14 +99,20 @@ int platform_init(void)
GPIO_CNF_OUTPUT_PUSHPULL, TDI_PIN); GPIO_CNF_OUTPUT_PUSHPULL, TDI_PIN);
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, LED_IDLE_RUN); GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
/* Setup heartbeat timer */ /* Setup heartbeat timer */
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8); systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000); /* Interrupt us at 10 Hz */ systick_set_reload(900000); /* Interrupt us at 10 Hz */
SCB_SHPR(11) &= ~((15 << 4) & 0xff);
SCB_SHPR(11) |= ((14 << 4) & 0xff);
systick_interrupt_enable(); systick_interrupt_enable();
systick_counter_enable(); systick_counter_enable();
usbuart_init();
SCB_VTOR = 0x2000; // Relocate interrupt vector table here
cdcacm_init(); cdcacm_init();
jtag_scan(NULL); jtag_scan(NULL);
@ -82,7 +129,7 @@ void platform_delay(uint32_t delay)
void sys_tick_handler(void) void sys_tick_handler(void)
{ {
if(running_status) if(running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN); gpio_toggle(LED_PORT, led_idle_run);
if(timeout_counter) if(timeout_counter)
timeout_counter--; timeout_counter--;
@ -100,3 +147,29 @@ const char *platform_target_voltage(void)
{ {
return "unknown"; return "unknown";
} }
void disconnect_usb(void)
{
/* Disconnect USB cable by resetting USB Device and pulling USB_DP low*/
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
}
void assert_boot_pin(void)
{
uint32_t crl = GPIOA_CRL;
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
/* 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;
}
void setup_vbus_irq(void){};

View File

@ -33,10 +33,13 @@
#include "gdb_packet.h" #include "gdb_packet.h"
#define INLINE_GPIO #define INLINE_GPIO
#define CDCACM_PACKET_SIZE 64
#define BOARD_IDENT "Black Magic Probe (STLINK), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (STLINK)"
extern usbd_device *usbdev; extern usbd_device *usbdev;
#define CDCACM_PACKET_SIZE 64
#define CDCACM_GDB_ENDPOINT 1 #define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
@ -75,10 +78,44 @@ extern usbd_device *usbdev;
#define SWCLK_PIN TCK_PIN #define SWCLK_PIN TCK_PIN
#define LED_PORT GPIOA #define LED_PORT GPIOA
/* The value line discovery board stlink has it's led on PA8 /* Use PC14 for a "dummy" uart led. So we can observere at least with scope*/
* All other stlinks have the led connected to PA9 instead and MCO to PA8 #define LED_PORT_UART GPIOC
#define LED_UART GPIO14
#define TMS_SET_MODE() \
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN);
#define SWDIO_MODE_FLOAT() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_INPUT, \
GPIO_CNF_INPUT_FLOAT, SWDIO_PIN);
#define SWDIO_MODE_DRIVE() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, SWDIO_PIN);
#define UART_PIN_SETUP() \
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_2_MHZ, \
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN);
#define USB_DRIVER stm32f103_usb_driver
#define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ
#define USB_ISR usb_lp_can_rx0_isr
/* Interrupt priorities. Low numbers are high priority.
* For now USART2 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define LED_IDLE_RUN GPIO9 #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USB_VBUS (14 << 4)
#define IRQ_PRI_TIM3 (0 << 4)
#define USBUSART USART2
#define USBUSART_CR1 USART2_CR1
#define USBUSART_IRQ NVIC_USART2_IRQ
#define USBUSART_APB_ENR RCC_APB1ENR
#define USBUSART_CLK_ENABLE RCC_APB1ENR_USART2EN
#define USBUSART_PORT GPIOA
#define USBUSART_TX_PIN GPIO2
#define USBUSART_ISR usart2_isr
#define DEBUG(...) #define DEBUG(...)
@ -96,8 +133,9 @@ extern const char *morse_msg;
gpio_clear((port), (pin)); \ gpio_clear((port), (pin)); \
} while(0) } while(0)
extern uint16_t led_idle_run;
#define SET_RUN_STATE(state) {running_status = (state);} #define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);} #define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, led_idle_run, state);}
#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);} #define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
#define PLATFORM_FATAL_ERROR(error) { \ #define PLATFORM_FATAL_ERROR(error) { \
@ -119,6 +157,9 @@ void cdcacm_init(void);
int cdcacm_get_config(void); int cdcacm_get_config(void);
int cdcacm_get_dtr(void); int cdcacm_get_dtr(void);
/* <platform.h> */
void uart_usb_buf_drain(uint8_t ep);
/* Use newlib provided integer only stdio functions */ /* Use newlib provided integer only stdio functions */
#define sscanf siscanf #define sscanf siscanf
#define sprintf siprintf #define sprintf siprintf
@ -146,3 +187,5 @@ static inline u16 _gpio_get(u32 gpioport, u16 gpios)
#endif #endif
void disconnect_usb(void);
void assert_boot_pin(void);

View File

@ -26,10 +26,7 @@
* The device's unique id is used as the USB serial number string. * The device's unique id is used as the USB serial number string.
*/ */
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/f1/gpio.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h> #include <libopencm3/usb/cdc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
@ -37,8 +34,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "platform.h" #include "platform.h"
#include "traceswo.h" #include "gdb_if.h"
#include "usbuart.h" #if defined(PLATFORM_HAS_TRACESWO)
#include <traceswo.h>
#endif
#include <usbuart.h>
#define DFU_IF_NO 4 #define DFU_IF_NO 4
@ -310,6 +310,7 @@ static const struct usb_iface_assoc_descriptor dfu_assoc = {
.iFunction = 6, .iFunction = 6,
}; };
#if defined(PLATFORM_HAS_TRACESWO)
static const struct usb_endpoint_descriptor trace_endp[] = {{ static const struct usb_endpoint_descriptor trace_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -343,6 +344,7 @@ static const struct usb_iface_assoc_descriptor trace_assoc = {
.bFunctionProtocol = 0xFF, .bFunctionProtocol = 0xFF,
.iFunction = 7, .iFunction = 7,
}; };
#endif
static const struct usb_interface ifaces[] = {{ static const struct usb_interface ifaces[] = {{
.num_altsetting = 1, .num_altsetting = 1,
@ -362,17 +364,23 @@ static const struct usb_interface ifaces[] = {{
.num_altsetting = 1, .num_altsetting = 1,
.iface_assoc = &dfu_assoc, .iface_assoc = &dfu_assoc,
.altsetting = &dfu_iface, .altsetting = &dfu_iface,
#if defined(PLATFORM_HAS_TRACESWO)
}, { }, {
.num_altsetting = 1, .num_altsetting = 1,
.iface_assoc = &trace_assoc, .iface_assoc = &trace_assoc,
.altsetting = &trace_iface, .altsetting = &trace_iface,
#endif
}}; }};
static const struct usb_config_descriptor config = { static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
#if defined(PLATFORM_HAS_TRACESWO)
.bNumInterfaces = 6, .bNumInterfaces = 6,
#else
.bNumInterfaces = 5,
#endif
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
@ -385,12 +393,14 @@ char serial_no[9];
static const char *usb_strings[] = { static const char *usb_strings[] = {
"Black Sphere Technologies", "Black Sphere Technologies",
"Black Magic Probe", BOARD_IDENT,
serial_no, serial_no,
"Black Magic GDB Server", "Black Magic GDB Server",
"Black Magic UART Port", "Black Magic UART Port",
"Black Magic Firmware Upgrade", DFU_IDENT,
#if defined(PLATFORM_HAS_TRACESWO)
"Black Magic Trace Capture", "Black Magic Trace Capture",
#endif
}; };
static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req) static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
@ -399,12 +409,10 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
(void)req; (void)req;
/* Disconnect USB cable */ /* Disconnect USB cable */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT, 0, USB_PU_PIN); disconnect_usb();
/* Assert boot-request pin */ /* Assert boot-request pin */
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, assert_boot_pin();
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOB, GPIO12);
/* Reset core to enter bootloader */ /* Reset core to enter bootloader */
scb_reset_core(); scb_reset_core();
@ -478,7 +486,7 @@ static void cdcacm_set_config(usbd_device *dev, u16 wValue)
/* GDB interface */ /* GDB interface */
usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, gdb_usb_out_cb);
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, NULL);
usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
@ -490,9 +498,11 @@ static void cdcacm_set_config(usbd_device *dev, u16 wValue)
CDCACM_PACKET_SIZE, usbuart_usb_in_cb); CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
#if defined(PLATFORM_HAS_TRACESWO)
/* Trace interface */ /* Trace interface */
usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK,
64, trace_buf_drain); 64, trace_buf_drain);
#endif
usbd_register_control_callback(dev, usbd_register_control_callback(dev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
@ -526,53 +536,27 @@ void cdcacm_init(void)
get_dev_unique_id(serial_no); get_dev_unique_id(serial_no);
usbdev = usbd_init(&stm32f103_usb_driver, usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings, sizeof(usb_strings)/sizeof(char *));
&dev, &config, usb_strings, 7);
usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer)); usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbdev, cdcacm_set_config); usbd_register_set_config_callback(usbdev, cdcacm_set_config);
nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, IRQ_PRI_USB); nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); nvic_enable_irq(USB_IRQ);
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS); setup_vbus_irq();
nvic_enable_irq(USB_VBUS_IRQ);
gpio_set(USB_VBUS_PORT, USB_VBUS_PIN);
gpio_set(USB_PU_PORT, USB_PU_PIN);
gpio_set_mode(USB_VBUS_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, USB_VBUS_PIN);
/* Configure EXTI for USB VBUS monitor */
exti_select_source(USB_VBUS_PIN, USB_VBUS_PORT);
exti_set_trigger(USB_VBUS_PIN, EXTI_TRIGGER_BOTH);
exti_enable_request(USB_VBUS_PIN);
exti15_10_isr();
} }
void usb_lp_can_rx0_isr(void) void USB_ISR(void)
{ {
usbd_poll(usbdev); usbd_poll(usbdev);
} }
void exti15_10_isr(void)
{
if (gpio_get(USB_VBUS_PORT, USB_VBUS_PIN)) {
/* Drive pull-up high if VBUS connected */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
} else {
/* Allow pull-up to float if VBUS disconnected */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
}
exti_reset_request(USB_VBUS_PIN);
}
static char *get_dev_unique_id(char *s) static char *get_dev_unique_id(char *s)
{ {
#if defined(STM32F4)
volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFF7A10;
#else
volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8; volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8;
#endif
uint32_t unique_id = *unique_id_p + uint32_t unique_id = *unique_id_p +
*(unique_id_p + 1) + *(unique_id_p + 1) +
*(unique_id_p + 2); *(unique_id_p + 2);
@ -589,4 +573,3 @@ static char *get_dev_unique_id(char *s)
return s; return s;
} }

View File

@ -0,0 +1,29 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
/* Include the common ld script from libopenstm32. */
INCLUDE libopencm3_stm32f4.ld

View File

@ -28,9 +28,11 @@
#include "gdb_if.h" #include "gdb_if.h"
static uint32_t count_out; static uint32_t count_out;
static uint32_t count_new;
static uint32_t count_in; static uint32_t count_in;
static uint32_t out_ptr; static uint32_t out_ptr;
static uint8_t buffer_out[CDCACM_PACKET_SIZE]; static uint8_t buffer_out[CDCACM_PACKET_SIZE];
static uint8_t double_buffer_out[CDCACM_PACKET_SIZE];
static uint8_t buffer_in[CDCACM_PACKET_SIZE]; static uint8_t buffer_in[CDCACM_PACKET_SIZE];
void gdb_if_putchar(unsigned char c, int flush) void gdb_if_putchar(unsigned char c, int flush)
@ -49,18 +51,29 @@ void gdb_if_putchar(unsigned char c, int flush)
} }
} }
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
count_new = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT,
double_buffer_out, CDCACM_PACKET_SIZE);
}
unsigned char gdb_if_getchar(void) unsigned char gdb_if_getchar(void)
{ {
while(!(out_ptr < count_out)) { while(!(out_ptr < count_out)) {
/* Detach if port closed */ /* Detach if port closed */
if(!cdcacm_get_dtr()) if(!cdcacm_get_dtr())
return 0x04; return 0x04;
while(cdcacm_get_config() != 1); while(cdcacm_get_config() != 1);
count_out = usbd_ep_read_packet(usbdev, CDCACM_GDB_ENDPOINT, if (count_new) {
buffer_out, CDCACM_PACKET_SIZE); memcpy(buffer_out, double_buffer_out,count_new);
count_out = count_new;
count_new = 0;
out_ptr = 0; out_ptr = 0;
} }
}
return buffer_out[out_ptr++]; return buffer_out[out_ptr++];
} }
@ -74,9 +87,13 @@ unsigned char gdb_if_getchar_to(int timeout)
if(!cdcacm_get_dtr()) if(!cdcacm_get_dtr())
return 0x04; return 0x04;
count_out = usbd_ep_read_packet(usbdev, CDCACM_GDB_ENDPOINT, while(cdcacm_get_config() != 1);
buffer_out, CDCACM_PACKET_SIZE); if (count_new) {
memcpy(buffer_out, double_buffer_out,count_new);
count_out = count_new;
count_new = 0;
out_ptr = 0; out_ptr = 0;
}
} while(timeout_counter && !(out_ptr < count_out)); } while(timeout_counter && !(out_ptr < count_out));
if(out_ptr < count_out) if(out_ptr < count_out)

View File

@ -25,11 +25,11 @@
#include "general.h" #include "general.h"
#include "jtagtap.h" #include "jtagtap.h"
#include "platform.h"
int jtagtap_init(void) int jtagtap_init(void)
{ {
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, TMS_SET_MODE();
GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN);
/* Go to JTAG mode for SWJ-DP */ /* Go to JTAG mode for SWJ-DP */
for(int i = 0; i <= 50; i++) jtagtap_next(1, 0); /* Reset SW-DP */ for(int i = 0; i <= 50; i++) jtagtap_next(1, 0); /* Reset SW-DP */

View File

@ -0,0 +1,28 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* Include the common ld script from libopenstm32. */
INCLUDE libopencm3_stm32f1.ld

View File

@ -0,0 +1,28 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
/* Include the common ld script from libopenstm32. */
INCLUDE libopencm3_stm32f1.ld

View File

@ -39,13 +39,11 @@ static void swdptap_turnaround(uint8_t dir)
olddir = dir; olddir = dir;
if(dir) if(dir)
gpio_set_mode(SWDIO_PORT, GPIO_MODE_INPUT, SWDIO_MODE_FLOAT();
GPIO_CNF_INPUT_FLOAT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
if(!dir) if(!dir)
gpio_set_mode(SWDIO_PORT, GPIO_MODE_OUTPUT_50_MHZ, SWDIO_MODE_DRIVE();
GPIO_CNF_OUTPUT_PUSHPULL, SWDIO_PIN);
} }
static uint8_t swdptap_bit_in(void) static uint8_t swdptap_bit_in(void)

View File

@ -40,12 +40,13 @@
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <string.h> #include <string.h>
#include "platform.h"
void traceswo_init(void) void traceswo_init(void)
{ {
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN); TRACE_TIM_CLK_EN();
timer_reset(TIM3); timer_reset(TRACE_TIM);
/* Refer to ST doc RM0008 - STM32F10xx Reference Manual. /* Refer to ST doc RM0008 - STM32F10xx Reference Manual.
* Section 14.3.4 - 14.3.6 (General Purpose Timer - Input Capture) * Section 14.3.4 - 14.3.6 (General Purpose Timer - Input Capture)
@ -54,29 +55,29 @@ void traceswo_init(void)
*/ */
/* Use TI1 as capture input for CH1 and CH2 */ /* Use TI1 as capture input for CH1 and CH2 */
timer_ic_set_input(TIM3, TIM_IC1, TIM_IC_IN_TI1); timer_ic_set_input(TRACE_TIM, TIM_IC1, TIM_IC_IN_TI1);
timer_ic_set_input(TIM3, TIM_IC2, TIM_IC_IN_TI1); timer_ic_set_input(TRACE_TIM, TIM_IC2, TIM_IC_IN_TI1);
/* Capture CH1 on rising edge, CH2 on falling edge */ /* Capture CH1 on rising edge, CH2 on falling edge */
timer_ic_set_polarity(TIM3, TIM_IC1, TIM_IC_RISING); timer_ic_set_polarity(TRACE_TIM, TIM_IC1, TIM_IC_RISING);
timer_ic_set_polarity(TIM3, TIM_IC2, TIM_IC_FALLING); timer_ic_set_polarity(TRACE_TIM, TIM_IC2, TIM_IC_FALLING);
/* Trigger on Filtered Timer Input 1 (TI1FP1) */ /* Trigger on Filtered Timer Input 1 (TI1FP1) */
timer_slave_set_trigger(TIM3, TIM_SMCR_TS_IT1FP1); timer_slave_set_trigger(TRACE_TIM, TIM_SMCR_TS_IT1FP1);
/* Slave reset mode: reset counter on trigger */ /* Slave reset mode: reset counter on trigger */
timer_slave_set_mode(TIM3, TIM_SMCR_SMS_RM); timer_slave_set_mode(TRACE_TIM, TIM_SMCR_SMS_RM);
/* Enable capture interrupt */ /* Enable capture interrupt */
nvic_set_priority(NVIC_TIM3_IRQ, IRQ_PRI_TIM3); nvic_set_priority(TRACE_IRQ, IRQ_PRI_TRACE);
nvic_enable_irq(NVIC_TIM3_IRQ); nvic_enable_irq(TRACE_IRQ);
timer_enable_irq(TIM3, TIM_DIER_CC1IE); timer_enable_irq(TRACE_TIM, TIM_DIER_CC1IE);
/* Enable the capture channels */ /* Enable the capture channels */
timer_ic_enable(TIM3, TIM_IC1); timer_ic_enable(TRACE_TIM, TIM_IC1);
timer_ic_enable(TIM3, TIM_IC2); timer_ic_enable(TRACE_TIM, TIM_IC2);
timer_enable_counter(TIM3); timer_enable_counter(TRACE_TIM);
} }
static uint8_t trace_usb_buf[64]; static uint8_t trace_usb_buf[64];
@ -107,9 +108,9 @@ void trace_buf_drain(usbd_device *dev, uint8_t ep)
#define ALLOWED_DUTY_ERROR 5 #define ALLOWED_DUTY_ERROR 5
void tim3_isr(void) void trace_isr(void)
{ {
uint16_t sr = TIM_SR(TIM3); uint16_t sr = TIM_SR(TRACE_TIM);
uint16_t duty, cycle; uint16_t duty, cycle;
static uint16_t bt; static uint16_t bt;
static uint8_t lastbit; static uint8_t lastbit;
@ -120,13 +121,13 @@ void tim3_isr(void)
/* Reset decoder state if capture overflowed */ /* Reset decoder state if capture overflowed */
if (sr & (TIM_SR_CC1OF | TIM_SR_UIF)) { if (sr & (TIM_SR_CC1OF | TIM_SR_UIF)) {
timer_clear_flag(TIM3, TIM_SR_CC1OF | TIM_SR_UIF); timer_clear_flag(TRACE_TIM, TIM_SR_CC1OF | TIM_SR_UIF);
if (!(sr & (TIM_SR_CC2IF | TIM_SR_CC1IF))) if (!(sr & (TIM_SR_CC2IF | TIM_SR_CC1IF)))
goto flush_and_reset; goto flush_and_reset;
} }
cycle = TIM_CCR1(TIM3); cycle = TIM_CCR1(TRACE_TIM);
duty = TIM_CCR2(TIM3); duty = TIM_CCR2(TRACE_TIM);
/* Reset decoder state if crazy shit happened */ /* Reset decoder state if crazy shit happened */
if ((bt && (((duty / bt) > 2) || ((duty / bt) == 0))) || (duty == 0)) if ((bt && (((duty / bt) > 2) || ((duty / bt) == 0))) || (duty == 0))
@ -147,9 +148,9 @@ void tim3_isr(void)
bt = duty; bt = duty;
lastbit = 1; lastbit = 1;
halfbit = 0; halfbit = 0;
timer_set_period(TIM3, duty * 6); timer_set_period(TRACE_TIM, duty * 6);
timer_clear_flag(TIM3, TIM_SR_UIF); timer_clear_flag(TRACE_TIM, TIM_SR_UIF);
timer_enable_irq(TIM3, TIM_DIER_UIE); timer_enable_irq(TRACE_TIM, TIM_DIER_UIE);
} else { } else {
/* If high time is extended we need to flip the bit */ /* If high time is extended we need to flip the bit */
if ((duty / bt) > 1) { if ((duty / bt) > 1) {
@ -179,12 +180,10 @@ void tim3_isr(void)
return; return;
flush_and_reset: flush_and_reset:
timer_set_period(TIM3, -1); timer_set_period(TRACE_TIM, -1);
timer_disable_irq(TIM3, TIM_DIER_UIE); timer_disable_irq(TRACE_TIM, TIM_DIER_UIE);
trace_buf_push(decbuf, decbuf_pos >> 3); trace_buf_push(decbuf, decbuf_pos >> 3);
bt = 0; bt = 0;
decbuf_pos = 0; decbuf_pos = 0;
memset(decbuf, 0, sizeof(decbuf)); memset(decbuf, 0, sizeof(decbuf));
} }

View File

@ -0,0 +1,626 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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 <string.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#if defined(STM32F1)
#include <libopencm3/stm32/f1/flash.h>
#elif defined(STM32F2)
#include <libopencm3/stm32/f2/flash.h>
#elif defined(STM32F4)
#include <libopencm3/stm32/f4/flash.h>
#else
#warning "Unhandled STM32 family"
#endif
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/dfu.h>
/* Commands sent with wBlockNum == 0 as per ST implementation. */
#define CMD_SETADDR 0x21
#define CMD_ERASE 0x41
#define FLASH_OBP_RDP 0x1FFFF800
#define FLASH_OBP_WRP10 0x1FFFF808
#define FLASH_OBP_RDP_KEY 0x5aa5
usbd_device *usbdev;
/* We need a special large control buffer for this device: */
u8 usbd_control_buffer[1024];
#if defined (STM32_CAN)
#define FLASHBLOCKSIZE 2048
#else
#define FLASHBLOCKSIZE 1024
#endif
#if defined(DISCOVERY_STLINK)
uint8_t rev;
uint16_t led_idle_run;
u32 led2_state = 0;
int stlink_test_nrst(void) {
/* Test if JRST/NRST is pulled down*/
int i;
uint16_t nrst;
uint16_t pin;
/* 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_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
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:
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_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, pin);
gpio_set(GPIOB, pin);
for (i=0; i< 100; i++)
nrst = gpio_get(GPIOB, pin);
return (nrst)?1:0;
}
#endif
static u32 max_address;
#if defined (STM32F4)
#define APP_ADDRESS 0x08010000
static u32 sector_addr[] = {0x8000000, 0x8004000, 0x8008000, 0x800c000,
0x8010000, 0x8020000, 0x8040000, 0x8060000,
0x8080000, 0x80a0000, 0x80c0000, 0x80e0000,
0x8100000, 0};
u16 sector_erase_time[12]= {500, 500, 500, 500,
1100,
2600, 2600, 2600, 2600, 2600, 2600, 2600};
u8 sector_num = 0xff;
/* Find the sector number for a given address*/
void get_sector_num(u32 addr)
{
int i = 0;
while(sector_addr[i+1]) {
if (addr < sector_addr[i+1])
break;
i++;
}
if (!sector_addr[i])
return;
sector_num = i;
}
void check_and_do_sector_erase(u32 addr)
{
if(addr == sector_addr[sector_num]) {
flash_erase_sector((sector_num & 0x1f)<<3, FLASH_PROGRAM_X32);
}
}
#else
#define APP_ADDRESS 0x08002000
static uint32_t last_erased_page=0xffffffff;
void check_and_do_sector_erase(u32 sector)
{
sector &= (~(FLASHBLOCKSIZE-1));
if (sector != last_erased_page) {
flash_erase_page(sector);
last_erased_page = sector;
}
}
#endif
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
static char *get_dev_unique_id(char *serial_no);
static struct {
u8 buf[sizeof(usbd_control_buffer)];
u16 len;
u32 addr;
u16 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 = 0x6017,
.bcdDevice = 0x0100,
.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 = 1024,
.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),
};
const struct usb_interface ifaces[] = {{
.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,
};
static char serial_no[9];
static const char *usb_strings[] = {
"Black Sphere Technologies",
#if defined(BLACKMAGIC)
"Black Magic Probe (Upgrade), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")",
#elif defined(DISCOVERY_STLINK)
"Black Magic (Upgrade) for STLink/Discovery, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")",
#elif defined(STM32_CAN)
"Black Magic (Upgrade) for STM32_CAN, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")",
#elif defined(F4DISCOVERY)
"Black Magic (Upgrade) for F4Discovery, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")",
#elif defined(USPS_F407)
"Black Magic (Upgrade) for USPS_F407, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")",
#else
#warning "Unhandled board"
#endif
serial_no,
/* This string is used by ST Microelectronics' DfuSe utility */
#if defined(BLACKMAGIC)
"@Internal Flash /0x08000000/8*001Ka,120*001Kg"
#elif defined(DISCOVERY_STLINK)
"@Internal Flash /0x08000000/8*001Ka,56*001Kg"
#elif defined(STM32_CAN)
"@Internal Flash /0x08000000/4*002Ka,124*002Kg"
#elif defined(F4DISCOVERY) || defined(USPS_F407)
"@Internal Flash /0x08000000/1*016Ka,3*016Kg,1*064Kg,7*128Kg"
#else
#warning "Unhandled board"
#endif
};
static u8 usbdfu_getstatus(u32 *bwPollTimeout)
{
switch(usbdfu_state) {
case STATE_DFU_DNLOAD_SYNC:
usbdfu_state = STATE_DFU_DNBUSY;
#if defined(STM32F4)
/* Programming 256 word with 100 us(max) per word*/
*bwPollTimeout = 26;
/* Erase for big pages on STM2/4 needs "long" time
Try not to hit USB timeouts*/
if ((prog.blocknum == 0) && (prog.buf[0] == CMD_ERASE)) {
u32 addr = *(u32 *)(prog.buf + 1);
get_sector_num(addr);
if(addr == sector_addr[sector_num])
*bwPollTimeout = sector_erase_time[sector_num];
}
#else
*bwPollTimeout = 100;
#endif
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 void
usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req)
{
int i;
(void)req;
switch(usbdfu_state) {
case STATE_DFU_DNBUSY:
flash_unlock();
if(prog.blocknum == 0) {
u32 addr = *(u32 *)(prog.buf + 1);
if (addr < APP_ADDRESS ||
(addr >= max_address)) {
flash_lock();
usbd_ep_stall_set(dev, 0, 1);
return;
}
switch(prog.buf[0]) {
case CMD_ERASE:
check_and_do_sector_erase(addr);
case CMD_SETADDR:
prog.addr = addr;
}
} else {
u32 baseaddr = prog.addr +
((prog.blocknum - 2) *
dfu_function.wTransferSize);
#if defined (STM32F4)
for(i = 0; i < prog.len; i += 4)
flash_program_word(baseaddr + i,
*(u32*)(prog.buf+i),
FLASH_PROGRAM_X32);
#else
for(i = 0; i < prog.len; i += 2)
flash_program_half_word(baseaddr + i,
*(u16*)(prog.buf+i));
#endif
}
flash_lock();
/* We jump straight to dfuDNLOAD-IDLE,
* skipping dfuDNLOAD-SYNC
*/
usbdfu_state = STATE_DFU_DNLOAD_IDLE;
return;
case STATE_DFU_MANIFEST:
#if defined (DISCOVERY_STLINK)
/* Disconnect USB cable by resetting USB Device
and pulling USB_DP low*/
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
#else
/* USB device must detach, we just reset... */
#endif
scb_reset_system();
return; /* Will never return */
default:
return;
}
}
static int usbdfu_control_request(usbd_device *dev,
struct usb_setup_data *req, u8 **buf, u16 *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
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: {
u32 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;
}
int main(void)
{
/* Check the force bootloader pin*/
#if defined (DISCOVERY_STLINK)
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
/* 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
*/
if(((GPIOA_CRL & 0x40) == 0x40) && stlink_test_nrst()) {
#elif defined (STM32_CAN)
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
if(!gpio_get(GPIOA, GPIO0)) {
#elif defined (F4DISCOVERY)
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
if(!gpio_get(GPIOA, GPIO0)) {
#elif defined (USPS_F407)
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN);
/* Pull up an look if external pulled low or if we restart with PB1 low*/
GPIOB_PUPDR |= 4;
{
int i;
for(i=0; i<100000; i++) __asm__("NOP");
}
if(gpio_get(GPIOB, GPIO1)) {
#else
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
if(gpio_get(GPIOB, GPIO12)) {
#endif
/* Boot the application if it's valid */
#if defined (STM32F4)
/* Vector table may be anywhere in 128 kByte RAM
CCM not handled*/
if((*(volatile u32*)APP_ADDRESS & 0x2FFC0000) == 0x20000000) {
#else
if((*(volatile u32*)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
#endif
/* Set vector table base address */
SCB_VTOR = APP_ADDRESS & 0x1FFFFF; /* Max 2 MByte Flash*/
/* Initialise master stack pointer */
asm volatile ("msr msp, %0"::"g"
(*(volatile u32*)APP_ADDRESS));
/* Jump to application */
(*(void(**)())(APP_ADDRESS + 4))();
}
}
#if defined (STM32F4)
if ((FLASH_OPTCR & 0x10000) != 0) {
flash_program_option_bytes(FLASH_OPTCR & ~0x10000);
flash_lock_option_bytes();
}
#else
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);
/* CL Device: Protect 2 bits with (2 * 2k pages each)*/
/* MD Device: Protect 2 bits with (4 * 1k pages each)*/
flash_program_option_bytes(FLASH_OBP_WRP10, 0x03FC);
}
#endif
/* Set up clock*/
#if defined (F4DISCOVERY) || defined(USPS_F407)
rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(2100000);
#else
rcc_clock_setup_in_hse_8mhz_out_72mhz();
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000);
#endif
/* Handle USB disconnect/connect */
#if defined(DISCOVERY_STLINK)
/* 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_peripheral_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
gpio_clear(GPIOA, GPIO12);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
#elif defined(F4DISCOVERY)
#elif defined(USPS_F407)
#elif defined(STM32_CAN)
#else
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO8);
#endif
systick_interrupt_enable();
systick_counter_enable();
get_dev_unique_id(serial_no);
/* Handle LEDs */
#if defined(F4DISCOVERY)
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN);
gpio_clear(GPIOD, GPIO12 | GPIO13 | GPIO14 |GPIO15);
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
GPIO12 | GPIO13 | GPIO14 |GPIO15);
#elif defined(USPS_F407)
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN);
gpio_clear(GPIOB, GPIO2);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
GPIO2);
#elif defined (STM32_CAN)
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO0);
#else
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO11);
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO2 | GPIO10);
#endif
/* Set up USB*/
#if defined(STM32_CAN)
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
usbdev = usbd_init(&stm32f107_usb_driver,
&dev, &config, usb_strings, 4);
#elif defined(STM32F2)||defined(STM32F4)
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN);
/* Set up USB Pins and alternate function*/
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
GPIO9 | GPIO10 | GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO10| GPIO11 | GPIO12);
usbdev = usbd_init(&stm32f107_usb_driver,
&dev, &config, usb_strings, 4);
#else
usbdev = usbd_init(&stm32f103_usb_driver,
&dev, &config, usb_strings, 4);
#endif
usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer));
usbd_register_control_callback(usbdev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
usbdfu_control_request);
#if defined(BLACKMAGIG)
gpio_set(GPIOA, GPIO8);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO8);
#endif
while (1)
usbd_poll(usbdev);
}
static char *get_dev_unique_id(char *s)
{
#if defined(STM32F4) || defined(STM32F2)
#define UNIQUE_SERIAL_R 0x1FFF7A10
#define FLASH_SIZE_R 0x1fff7A22
#elif defined(STM32F3)
#define UNIQUE_SERIAL_R 0x1FFFF7AC
#define FLASH_SIZE_R 0x1fff77cc
#elif defined(STM32L1)
#define UNIQUE_SERIAL_R 0x1ff80050
#define FLASH_SIZE_R 0x1FF8004C
#else
#define UNIQUE_SERIAL_R 0x1FFFF7E8;
#define FLASH_SIZE_R 0x1ffff7e0
#endif
volatile uint32_t *unique_id_p = (volatile uint32_t *)UNIQUE_SERIAL_R;
uint32_t unique_id = *unique_id_p +
*(unique_id_p + 1) +
*(unique_id_p + 2);
int i;
/* Calculated the upper flash limit from the exported data
in theparameter block*/
max_address = (*(u32 *) FLASH_SIZE_R) <<10;
/* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
}
for(i = 0; i < 8; i++)
if(s[i] > '9')
s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
}
void sys_tick_handler()
{
#if defined(DISCOVERY_STLINK)
if (rev == 0)
gpio_toggle(GPIOA, led_idle_run);
else
{
if (led2_state & 1)
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, led_idle_run);
else
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_ANALOG, led_idle_run);
led2_state++;
}
#elif defined (F4DISCOVERY)
gpio_toggle(GPIOD, GPIO12); /* Green LED on/off */
#elif defined (USPS_F407)
gpio_toggle(GPIOB, GPIO2); /* Green LED on/off */
#elif defined(STM32_CAN)
gpio_toggle(GPIOB, GPIO0); /* LED2 on/off */
#else
gpio_toggle(GPIOB, GPIO11); /* LED2 on/off */
#endif
}

View File

@ -18,70 +18,70 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/stm32/f1/rcc.h> #include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/f1/gpio.h> #include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h> #include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scs.h> #include <libopencm3/cm3/scs.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h> #include <libopencm3/usb/cdc.h>
#include "platform.h" #include <platform.h>
void usbuart_init(void) void usbuart_init(void)
{ {
#if defined(BLACKMAGIC)
/* On mini hardware, UART and SWD share connector pins. /* On mini hardware, UART and SWD share connector pins.
* Don't enable UART if we're being debugged. */ * Don't enable UART if we're being debugged. */
if ((platform_hwversion() == 1) && (SCS_DEMCR & SCS_DEMCR_TRCENA)) if ((platform_hwversion() == 1) && (SCS_DEMCR & SCS_DEMCR_TRCENA))
return; return;
#endif
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_USART1EN); rcc_peripheral_enable_clock(&USBUSART_APB_ENR, USBUSART_CLK_ENABLE);
/* UART1 TX to 'alternate function output push-pull' */ UART_PIN_SETUP();
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
/* Setup UART parameters. */ /* Setup UART parameters. */
usart_set_baudrate(USART1, 38400); usart_set_baudrate(USBUSART, 38400);
usart_set_databits(USART1, 8); usart_set_databits(USBUSART, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1); usart_set_stopbits(USBUSART, USART_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX_RX); usart_set_mode(USBUSART, USART_MODE_TX_RX);
usart_set_parity(USART1, USART_PARITY_NONE); usart_set_parity(USBUSART, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); usart_set_flow_control(USBUSART, USART_FLOWCONTROL_NONE);
/* Finally enable the USART. */ /* Finally enable the USART. */
usart_enable(USART1); usart_enable(USBUSART);
/* Enable interrupts */ /* Enable interrupts */
USART1_CR1 |= USART_CR1_RXNEIE; USBUSART_CR1 |= USART_CR1_RXNEIE;
nvic_set_priority(NVIC_USART1_IRQ, IRQ_PRI_USART1); nvic_set_priority(USBUSART_IRQ, IRQ_PRI_USBUSART);
nvic_enable_irq(NVIC_USART1_IRQ); nvic_enable_irq(USBUSART_IRQ);
} }
void usbuart_set_line_coding(struct usb_cdc_line_coding *coding) void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
{ {
usart_set_baudrate(USART1, coding->dwDTERate); usart_set_baudrate(USBUSART, coding->dwDTERate);
usart_set_databits(USART1, coding->bDataBits); usart_set_databits(USBUSART, coding->bDataBits);
switch(coding->bCharFormat) { switch(coding->bCharFormat) {
case 0: case 0:
usart_set_stopbits(USART1, USART_STOPBITS_1); usart_set_stopbits(USBUSART, USART_STOPBITS_1);
break; break;
case 1: case 1:
usart_set_stopbits(USART1, USART_STOPBITS_1_5); usart_set_stopbits(USBUSART, USART_STOPBITS_1_5);
break; break;
case 2: case 2:
usart_set_stopbits(USART1, USART_STOPBITS_2); usart_set_stopbits(USBUSART, USART_STOPBITS_2);
break; break;
} }
switch(coding->bParityType) { switch(coding->bParityType) {
case 0: case 0:
usart_set_parity(USART1, USART_PARITY_NONE); usart_set_parity(USBUSART, USART_PARITY_NONE);
break; break;
case 1: case 1:
usart_set_parity(USART1, USART_PARITY_ODD); usart_set_parity(USBUSART, USART_PARITY_ODD);
break; break;
case 2: case 2:
usart_set_parity(USART1, USART_PARITY_EVEN); usart_set_parity(USBUSART, USART_PARITY_EVEN);
break; break;
} }
} }
@ -94,16 +94,18 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT, int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT,
buf, CDCACM_PACKET_SIZE); buf, CDCACM_PACKET_SIZE);
#if defined(BLACKMAGIC)
/* Don't bother if uart is disabled. /* Don't bother if uart is disabled.
* This will be the case on mini while we're being debugged. * This will be the case on mini while we're being debugged.
*/ */
if(!(RCC_APB2ENR & RCC_APB2ENR_USART1EN)) if(!(RCC_APB2ENR & RCC_APB2ENR_USART1EN))
return; return;
#endif
gpio_set(LED_PORT, LED_UART); gpio_set(LED_PORT_UART, LED_UART);
for(int i = 0; i < len; i++) for(int i = 0; i < len; i++)
usart_send_blocking(USART1, buf[i]); usart_send_blocking(USBUSART, buf[i]);
gpio_clear(LED_PORT, LED_UART); gpio_clear(LED_PORT_UART, LED_UART);
} }
static uint8_t uart_usb_buf[CDCACM_PACKET_SIZE]; static uint8_t uart_usb_buf[CDCACM_PACKET_SIZE];
@ -112,7 +114,7 @@ static uint8_t uart_usb_buf_size;
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep) void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{ {
if (!uart_usb_buf_size) { if (!uart_usb_buf_size) {
gpio_clear(LED_PORT, LED_UART); gpio_clear(LED_PORT_UART, LED_UART);
return; return;
} }
@ -120,11 +122,17 @@ void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
uart_usb_buf_size = 0; uart_usb_buf_size = 0;
} }
void usart1_isr(void) void USBUSART_ISR(void)
{ {
char c = usart_recv(USART1); char c = usart_recv(USBUSART);
gpio_set(LED_PORT, LED_UART); /* Don't try to write until we are configured.
* Otherwise enumeration hanged in some cases.
*/
if (cdcacm_get_config() != 1)
return;
gpio_set(LED_PORT_UART, LED_UART);
/* Try to send now */ /* Try to send now */
if (usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, &c, 1) == 1) if (usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, &c, 1) == 1)
@ -138,4 +146,3 @@ void usart1_isr(void)
uart_usb_buf[uart_usb_buf_size++] = c; uart_usb_buf[uart_usb_buf_size++] = c;
} }

View File

@ -0,0 +1,35 @@
CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -DSTM32_CAN -I../libopencm3/include
LDFLAGS_BOOT = -lopencm3_stm32f1 -Wl,--defsym,_stack=0x20010000 \
-Wl,-T,platforms/stm32/stm32_can.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \
-L../libopencm3/lib
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000
VPATH += platforms/stm32
SRC += cdcacm.c \
platform.c \
usbuart.c \
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic.bin: blackmagic
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu: usbdfu.o
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
host_clean:
-rm blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex

View File

@ -0,0 +1,197 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/f1/adc.h>
#include "platform.h"
#include "jtag_scan.h"
#include <usbuart.h>
#include <ctype.h>
uint8_t running_status;
volatile uint32_t timeout_counter;
jmp_buf fatal_error_jmpbuf;
static void morse_update(void);
int platform_init(void)
{
/* Enable peripherals */
rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
rcc_clock_setup_in_hse_8mhz_out_72mhz();
/* Setup GPIO ports */
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
TMS_PIN);
gpio_set_mode(TCK_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
TCK_PIN | TDI_PIN);
gpio_set_mode(TCK_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT,
TDO_PIN);
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
LED_UART | LED_IDLE_RUN | LED_ERROR);
/* Setup heartbeat timer */
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000); /* Interrupt us at 10 Hz */
SCB_SHPR(11) &= ~((15 << 4) & 0xff);
SCB_SHPR(11) |= ((14 << 4) & 0xff);
systick_interrupt_enable();
systick_counter_enable();
usbuart_init();
SCB_VTOR = 0x2000; // Relocate interrupt vector table here
cdcacm_init();
jtag_scan(NULL);
return 0;
}
void platform_delay(uint32_t delay)
{
timeout_counter = delay;
while(timeout_counter);
}
void sys_tick_handler(void)
{
if(running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN);
if(timeout_counter)
timeout_counter--;
morse_update();
}
/* Morse code patterns and lengths */
static const struct {
uint16_t code;
uint8_t bits;
} morse_letter[] = {
{ 0b00011101, 8}, // 'A' .-
{ 0b000101010111, 12}, // 'B' -...
{ 0b00010111010111, 14}, // 'C' -.-.
{ 0b0001010111, 10}, // 'D' -..
{ 0b0001, 4}, // 'E' .
{ 0b000101110101, 12}, // 'F' ..-.
{ 0b000101110111, 12}, // 'G' --.
{ 0b0001010101, 10}, // 'H' ....
{ 0b000101, 6}, // 'I' ..
{0b0001110111011101, 16}, // 'J' .---
{ 0b000111010111, 12}, // 'K' -.-
{ 0b000101011101, 12}, // 'L' .-..
{ 0b0001110111, 10}, // 'M' --
{ 0b00010111, 8}, // 'N' -.
{ 0b00011101110111, 14}, // 'O' ---
{ 0b00010111011101, 14}, // 'P' .--.
{0b0001110101110111, 16}, // 'Q' --.-
{ 0b0001011101, 10}, // 'R' .-.
{ 0b00010101, 8}, // 'S' ...
{ 0b000111, 6}, // 'T' -
{ 0b0001110101, 10}, // 'U' ..-
{ 0b000111010101, 12}, // 'V' ...-
{ 0b000111011101, 12}, // 'W' .--
{ 0b00011101010111, 14}, // 'X' -..-
{0b0001110111010111, 16}, // 'Y' -.--
{ 0b00010101110111, 14}, // 'Z' --..
};
const char *morse_msg;
static const char * volatile morse_ptr;
static char morse_repeat;
void morse(const char *msg, char repeat)
{
morse_msg = morse_ptr = msg;
morse_repeat = repeat;
SET_ERROR_STATE(0);
}
static void morse_update(void)
{
static uint16_t code;
static uint8_t bits;
if(!morse_ptr) return;
if(!bits) {
char c = *morse_ptr++;
if(!c) {
if(morse_repeat) {
morse_ptr = morse_msg;
c = *morse_ptr++;
} else {
morse_ptr = 0;
return;
}
}
if((c >= 'A') && (c <= 'Z')) {
c -= 'A';
code = morse_letter[c].code;
bits = morse_letter[c].bits;
} else {
code = 0; bits = 4;
}
}
SET_ERROR_STATE(code & 1);
code >>= 1; bits--;
}
const char *platform_target_voltage(void)
{
return "ABSENT!";
}
void assert_boot_pin(void)
{
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO0);
gpio_set(GPIOA, GPIO0);
}

View File

@ -0,0 +1,196 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include <libopencm3/stm32/f1/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <setjmp.h>
#include <alloca.h>
#include "gdb_packet.h"
#define INLINE_GPIO
#define CDCACM_PACKET_SIZE 64
/*#define PLATFORM_HAS_TRACESWO*/
extern usbd_device *usbdev;
#define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3
#define BOARD_IDENT "Black Magic Probe (STM32_CAN), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (STM32_CAN)"
/* Important pin mappings for STM32 implementation:
*
* LED0 = PB2 (Yellow LED : Running)
* LED1 = PB10 (Yellow LED : Idle)
* LED2 = PB11 (Red LED : Error)
*
* TPWR = RB0 (input) -- analogue on mini design ADC1, ch8
* nTRST = PC9
* SRST_OUT = NA
* TDI = PC12
* TMS = PB14(input for SWDP)
* TCK = PC10
* TDO = PC11(input)
* nSRST = PA7 (input)
*
* Force DFU mode button: PA0 Read High for Bootloader Req
*/
/* Hardware definitions... */
#define TDI_PORT GPIOC
#define TMS_PORT GPIOB
#define TCK_PORT GPIOC
#define TDO_PORT GPIOC
#define TDI_PIN GPIO12
#define TMS_PIN GPIO14
#define TCK_PIN GPIO10
#define TDO_PIN GPIO11
#define SWDIO_PORT TMS_PORT
#define SWCLK_PORT TCK_PORT
#define SWDIO_PIN TMS_PIN
#define SWCLK_PIN TCK_PIN
//#define TRST_PORT GPIOC
//#define TRST_PIN GPIO9
#define LED_PORT GPIOB
#define LED_PORT_UART GPIOB
#define LED_UART GPIO0
#define LED_IDLE_RUN GPIO1
#define LED_ERROR GPIO12
#define TMS_SET_MODE() \
gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN);
#define SWDIO_MODE_FLOAT() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_INPUT, \
GPIO_CNF_INPUT_FLOAT, SWDIO_PIN);
#define SWDIO_MODE_DRIVE() \
gpio_set_mode(SWDIO_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
GPIO_CNF_OUTPUT_PUSHPULL, SWDIO_PIN);
#define UART_PIN_SETUP() \
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_2_MHZ, \
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN);
#define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority.
*/
#define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_TIM3 (0 << 4)
#define USBUSART USART2
#define USBUSART_CR1 USART2_CR1
#define USBUSART_IRQ NVIC_USART2_IRQ
#define USBUSART_APB_ENR RCC_APB1ENR
#define USBUSART_CLK_ENABLE RCC_APB1ENR_USART2EN
#define USBUSART_PORT GPIOA
#define USBUSART_TX_PIN GPIO2
#define USBUSART_ISR usart2_isr
#define DEBUG(...)
extern uint8_t running_status;
extern volatile uint32_t timeout_counter;
extern jmp_buf fatal_error_jmpbuf;
extern const char *morse_msg;
#define gpio_set_val(port, pin, val) do { \
if(val) \
gpio_set((port), (pin)); \
else \
gpio_clear((port), (pin)); \
} while(0)
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
#define PLATFORM_FATAL_ERROR(error) { \
if(running_status) gdb_putpacketz("X1D"); \
else gdb_putpacketz("EFF"); \
running_status = 0; \
target_list_free(); \
morse("TARGET LOST.", 1); \
longjmp(fatal_error_jmpbuf, (error)); \
}
int platform_init(void);
void morse(const char *msg, char repeat);
const char *platform_target_voltage(void);
int platform_hwversion(void);
void platform_delay(uint32_t delay);
/* <cdcacm.c> */
void cdcacm_init(void);
/* Returns current usb configuration, or 0 if not configured. */
int cdcacm_get_config(void);
int cdcacm_get_dtr(void);
/* <platform.h> */
void uart_usb_buf_drain(uint8_t ep);
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
#define vasprintf vasiprintf
#ifdef INLINE_GPIO
static inline void _gpio_set(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
#define gpio_set _gpio_set
static inline void _gpio_clear(u32 gpioport, u16 gpios)
{
GPIO_BRR(gpioport) = gpios;
}
#define gpio_clear _gpio_clear
static inline u16 _gpio_get(u32 gpioport, u16 gpios)
{
return (u16)GPIO_IDR(gpioport) & gpios;
}
#define gpio_get _gpio_get
#endif
#endif
#define disconnect_usb() usbd_disconnect(usbdev,1)
void assert_boot_pin(void);
#define setup_vbus_irq()

View File

@ -0,0 +1,36 @@
CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
-DSTM32F4 -DUSPS_F407 -I../libopencm3/include
LDFLAGS_BOOT = -lopencm3_stm32f4 -Wl,--defsym,_stack=0x20020000 \
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \
-L../libopencm3/lib
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8010000
VPATH += platforms/stm32
SRC += cdcacm.c \
platform.c \
traceswo.c \
usbuart.c \
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic.bin: blackmagic
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu: usbdfu.o
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
host_clean:
-rm blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex

View File

@ -0,0 +1,22 @@
Hardware
========
Find eagle schematics at
https://github.com/UweBonnes/wiki_fuer_alex/tree/master/layout
The board can be used for F1/L1/F2 and F4 with some changed parts,
see the datasheet and hints in the schematic
JTAG: Reuse the JTAG Connector, unconnect JTAG Tap and reuse JTAG pins
in inverse direction.
Forced boot request: Connect Jumper Wire X11-34/X11-40 to pull PC15
to ground
System Bootloader: Jumper Boot0 to '1'
Led: PB2 (Boot1)
Application start address:
=========================
Use 0x8010000
- lower 3 16 k pages may be used for parameter storage
- Erasing a single 64 k Page is faster then erasing 2 16 k Pages
eventual the 64 k page

View File

@ -0,0 +1,207 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/syscfg.h>
#include <libopencm3/usb/usbd.h>
#include "platform.h"
#include "jtag_scan.h"
#include <usbuart.h>
#include <ctype.h>
uint8_t running_status;
volatile uint32_t timeout_counter;
jmp_buf fatal_error_jmpbuf;
static void morse_update(void);
int platform_init(void)
{
rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
/* Enable peripherals */
rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN);
rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN);
/* Fix all flaoting pins*/
gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN,
0x1ff);
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN,
0xffe2);
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN,
0xf3ff);
/* Set up USB Pins and alternate function*/
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
GPIO9 | GPIO10| GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO10| GPIO11 | GPIO12);
/* Set TMS/TCK/TDI to high speed*/
GPIOA_OSPEEDR &=~0xfc00;
GPIOA_OSPEEDR |= 0xa800;
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
TMS_PIN | TCK_PIN | TDI_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE,
TDO_PIN | TRST_PIN);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
LED_UART );
/* Setup heartbeat timer */
systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
systick_set_reload(168000000/(10*8)); /* Interrupt us at 10 Hz */
SCB_SHPR(11) &= ~((15 << 4) & 0xff);
SCB_SHPR(11) |= ((14 << 4) & 0xff);
systick_interrupt_enable();
systick_counter_enable();
usbuart_init();
SCB_VTOR = 0x10000; // Relocate interrupt vector table here
cdcacm_init();
jtag_scan(NULL);
return 0;
}
void platform_delay(uint32_t delay)
{
timeout_counter = delay;
while(timeout_counter);
}
void sys_tick_handler(void)
{
if(timeout_counter)
timeout_counter--;
morse_update();
}
/* Morse code patterns and lengths */
static const struct {
uint16_t code;
uint8_t bits;
} morse_letter[] = {
{ 0b00011101, 8}, // 'A' .-
{ 0b000101010111, 12}, // 'B' -...
{ 0b00010111010111, 14}, // 'C' -.-.
{ 0b0001010111, 10}, // 'D' -..
{ 0b0001, 4}, // 'E' .
{ 0b000101110101, 12}, // 'F' ..-.
{ 0b000101110111, 12}, // 'G' --.
{ 0b0001010101, 10}, // 'H' ....
{ 0b000101, 6}, // 'I' ..
{0b0001110111011101, 16}, // 'J' .---
{ 0b000111010111, 12}, // 'K' -.-
{ 0b000101011101, 12}, // 'L' .-..
{ 0b0001110111, 10}, // 'M' --
{ 0b00010111, 8}, // 'N' -.
{ 0b00011101110111, 14}, // 'O' ---
{ 0b00010111011101, 14}, // 'P' .--.
{0b0001110101110111, 16}, // 'Q' --.-
{ 0b0001011101, 10}, // 'R' .-.
{ 0b00010101, 8}, // 'S' ...
{ 0b000111, 6}, // 'T' -
{ 0b0001110101, 10}, // 'U' ..-
{ 0b000111010101, 12}, // 'V' ...-
{ 0b000111011101, 12}, // 'W' .--
{ 0b00011101010111, 14}, // 'X' -..-
{0b0001110111010111, 16}, // 'Y' -.--
{ 0b00010101110111, 14}, // 'Z' --..
};
const char *morse_msg;
static const char * volatile morse_ptr;
static char morse_repeat;
void morse(const char *msg, char repeat)
{
morse_msg = morse_ptr = msg;
morse_repeat = repeat;
SET_ERROR_STATE(0);
}
static void morse_update(void)
{
static uint16_t code;
static uint8_t bits;
if(!morse_ptr) return;
if(!bits) {
char c = *morse_ptr++;
if(!c) {
if(morse_repeat) {
morse_ptr = morse_msg;
c = *morse_ptr++;
} else {
morse_ptr = 0;
return;
}
}
if((c >= 'A') && (c <= 'Z')) {
c -= 'A';
code = morse_letter[c].code;
bits = morse_letter[c].bits;
} else {
code = 0; bits = 4;
}
}
SET_ERROR_STATE(code & 1);
code >>= 1; bits--;
}
const char *platform_target_voltage(void)
{
return "ABSENT!";
}
void assert_boot_pin(void)
{
/* Flag Bootloader Request by mimicing a pushed USER button*/
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO1);
gpio_clear(GPIOB, GPIO11);
}

View File

@ -0,0 +1,208 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements the platform specific functions for the STM32
* implementation.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include <libopencm3/stm32/f4/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <setjmp.h>
#include <alloca.h>
#include "gdb_packet.h"
#define INLINE_GPIO
#define CDCACM_PACKET_SIZE 64
#define PLATFORM_HAS_TRACESWO
#define BOARD_IDENT "Black Magic Probe (USPS_F407), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (USPS_F407)"
extern usbd_device *usbdev;
#define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3
/* Important pin mappings for STM32 implementation:
*
* LED0 = PB2
* TPWR = XXX (input) -- analogue on mini design ADC1, ch8
* nTRST = PD0
* SRST_OUT = PD1
* TDI = PA1
* TMS = PA3 (input for SWDP)
* TCK = PA8
* TDO = PB4 (input)
* nSRST = PD2 (input)
*
* USB cable pull-up: PA8
* USB VBUS detect: PB13 -- New on mini design.
* Enable pull up for compatibility.
* Force DFU mode button: PB1
*/
/* Hardware definitions... */
#define JTAG_PORT GPIOA
#define TDI_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT GPIOB
#define TMS_PIN GPIO13
#define TCK_PIN GPIO14
#define TDI_PIN GPIO15
#define TDO_PIN GPIO3
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_PIN TMS_PIN
#define SWCLK_PIN TCK_PIN
#define TRST_PORT TDO_PORT
#define TRST_PIN GPIO4
#define SRST_PORT GPIOB
#define SRST_PIN GPIO4
#define LED_PORT GPIOB
#define LED_PORT_UART GPIOB
#define LED_UART GPIO2
#define TMS_SET_MODE() gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, TMS_PIN);
#define SWDIO_MODE_FLOAT() gpio_mode_setup(SWDIO_PORT, GPIO_MODE_INPUT, \
GPIO_PUPD_NONE, SWDIO_PIN);
#define SWDIO_MODE_DRIVE() gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN);
#define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority.
*/
#define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_APB_ENR RCC_APB1ENR
#define USBUSART_CLK_ENABLE RCC_APB1ENR_USART3EN
#define USBUSART_TX_PORT GPIOC
#define USBUSART_TX_PIN GPIO10
#define USBUSART_RX_PORT GPIOC
#define USBUSART_RX_PIN GPIO11
#define USBUSART_ISR usart3_isr
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN)
#define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR tim3_isr
#define DEBUG(...)
extern uint8_t running_status;
extern volatile uint32_t timeout_counter;
extern jmp_buf fatal_error_jmpbuf;
extern const char *morse_msg;
#define gpio_set_val(port, pin, val) do { \
if(val) \
gpio_set((port), (pin)); \
else \
gpio_clear((port), (pin)); \
} while(0)
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state)
#define SET_ERROR_STATE(state)
#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);}
#define PLATFORM_FATAL_ERROR(error) { \
if(running_status) gdb_putpacketz("X1D"); \
else gdb_putpacketz("EFF"); \
running_status = 0; \
target_list_free(); \
morse("TARGET LOST.", 1); \
longjmp(fatal_error_jmpbuf, (error)); \
}
int platform_init(void);
void morse(const char *msg, char repeat);
const char *platform_target_voltage(void);
int platform_hwversion(void);
void platform_delay(uint32_t delay);
/* <cdcacm.c> */
void cdcacm_init(void);
/* Returns current usb configuration, or 0 if not configured. */
int cdcacm_get_config(void);
int cdcacm_get_dtr(void);
/* <platform.h> */
void uart_usb_buf_drain(uint8_t ep);
/* Use newlib provided integer only stdio functions */
#define sscanf siscanf
#define sprintf siprintf
#define vasprintf vasiprintf
#ifdef INLINE_GPIO
static inline void _gpio_set(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
#define gpio_set _gpio_set
static inline void _gpio_clear(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios<<16;
}
#define gpio_clear _gpio_clear
static inline u16 _gpio_get(u32 gpioport, u16 gpios)
{
return (u16)GPIO_IDR(gpioport) & gpios;
}
#define gpio_get _gpio_get
#endif
#endif
#define disconnect_usb() do {usbd_disconnect(usbdev,1); nvic_disable_irq(USB_IRQ);} while(0)
void assert_boot_pin(void);
#define setup_vbus_irq()

View File

@ -93,6 +93,7 @@ static const char stm32hd_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define FLASH_OBR (FPEC_BASE+0x1C) #define FLASH_OBR (FPEC_BASE+0x1C)
#define FLASH_WRPR (FPEC_BASE+0x20) #define FLASH_WRPR (FPEC_BASE+0x20)
#define FLASH_CR_OBL_LAUNCH (1<<13)
#define FLASH_CR_OPTWRE (1 << 9) #define FLASH_CR_OPTWRE (1 << 9)
#define FLASH_CR_STRT (1 << 6) #define FLASH_CR_STRT (1 << 6)
#define FLASH_CR_OPTER (1 << 5) #define FLASH_CR_OPTER (1 << 5)
@ -104,6 +105,7 @@ static const char stm32hd_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define FLASH_OBP_RDP 0x1FFFF800 #define FLASH_OBP_RDP 0x1FFFF800
#define FLASH_OBP_RDP_KEY 0x5aa5 #define FLASH_OBP_RDP_KEY 0x5aa5
#define FLASH_OBP_RDP_KEY_F3 0x55AA
#define KEY1 0x45670123 #define KEY1 0x45670123
#define KEY2 0xCDEF89AB #define KEY2 0xCDEF89AB
@ -153,10 +155,9 @@ uint16_t stm32f1_flash_write_stub[] = {
bool stm32f1_probe(struct target_s *target) bool stm32f1_probe(struct target_s *target)
{ {
uint32_t idcode;
idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE); target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE) & 0xfff;
switch(idcode & 0xFFF) { switch(target->idcode) {
case 0x410: /* Medium density */ case 0x410: /* Medium density */
case 0x412: /* Low denisty */ case 0x412: /* Low denisty */
case 0x420: /* Value Line, Low-/Medium density */ case 0x420: /* Value Line, Low-/Medium density */
@ -164,7 +165,7 @@ bool stm32f1_probe(struct target_s *target)
target->xml_mem_map = stm32f1_xml_memory_map; target->xml_mem_map = stm32f1_xml_memory_map;
target->flash_erase = stm32md_flash_erase; target->flash_erase = stm32md_flash_erase;
target->flash_write = stm32f1_flash_write; target->flash_write = stm32f1_flash_write;
target_add_commands(target, stm32f1_cmd_list, "STM32"); target_add_commands(target, stm32f1_cmd_list, "STM32 LD/MD");
return true; return true;
case 0x414: /* High density */ case 0x414: /* High density */
case 0x418: /* Connectivity Line */ case 0x418: /* Connectivity Line */
@ -173,7 +174,7 @@ bool stm32f1_probe(struct target_s *target)
target->xml_mem_map = stm32hd_xml_memory_map; target->xml_mem_map = stm32hd_xml_memory_map;
target->flash_erase = stm32hd_flash_erase; target->flash_erase = stm32hd_flash_erase;
target->flash_write = stm32f1_flash_write; target->flash_write = stm32f1_flash_write;
target_add_commands(target, stm32f1_cmd_list, "STM32"); target_add_commands(target, stm32f1_cmd_list, "STM32 HD/CL");
return true; return true;
case 0x422: /* STM32F30x */ case 0x422: /* STM32F30x */
case 0x432: /* STM32F37x */ case 0x432: /* STM32F37x */
@ -181,18 +182,18 @@ bool stm32f1_probe(struct target_s *target)
target->xml_mem_map = stm32hd_xml_memory_map; target->xml_mem_map = stm32hd_xml_memory_map;
target->flash_erase = stm32hd_flash_erase; target->flash_erase = stm32hd_flash_erase;
target->flash_write = stm32f1_flash_write; target->flash_write = stm32f1_flash_write;
target_add_commands(target, stm32f1_cmd_list, "STM32"); target_add_commands(target, stm32f1_cmd_list, "STM32F3");
return true; return true;
} }
idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE_F0); target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE_F0) & 0xfff;
switch(idcode & 0xFFF) { switch(target->idcode) {
case 0x440: /* STM32F0 */ case 0x440: /* STM32F0 */
target->driver = stm32f0_driver_str; target->driver = stm32f0_driver_str;
target->xml_mem_map = stm32f1_xml_memory_map; target->xml_mem_map = stm32f1_xml_memory_map;
target->flash_erase = stm32md_flash_erase; target->flash_erase = stm32md_flash_erase;
target->flash_write = stm32f1_flash_write; target->flash_write = stm32f1_flash_write;
target_add_commands(target, stm32f1_cmd_list, "STM32"); target_add_commands(target, stm32f1_cmd_list, "STM32F0");
return true; return true;
} }
@ -338,15 +339,24 @@ static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value)
static bool stm32f1_cmd_option(target *t, int argc, char *argv[]) static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
{ {
uint32_t addr, val; uint32_t addr, val;
uint32_t flash_obp_rdp_key;
ADIv5_AP_t *ap = adiv5_target_ap(t); ADIv5_AP_t *ap = adiv5_target_ap(t);
switch(t->idcode) {
case 0x422: /* STM32F30x */
case 0x432: /* STM32F37x */
case 0x440: /* STM32F0 */
flash_obp_rdp_key = FLASH_OBP_RDP_KEY_F3;
break;
default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY;
}
stm32f1_flash_unlock(ap); stm32f1_flash_unlock(ap);
adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY1); adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY1);
adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY2); adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY2);
if ((argc == 2) && !strcmp(argv[1], "erase")) { if ((argc == 2) && !strcmp(argv[1], "erase")) {
stm32f1_option_erase(t); stm32f1_option_erase(t);
stm32f1_option_write(t, FLASH_OBP_RDP, FLASH_OBP_RDP_KEY); stm32f1_option_write(t, FLASH_OBP_RDP, flash_obp_rdp_key);
} else if (argc == 3) { } else if (argc == 3) {
addr = strtol(argv[1], NULL, 0); addr = strtol(argv[1], NULL, 0);
val = strtol(argv[2], NULL, 0); val = strtol(argv[2], NULL, 0);
@ -356,6 +366,15 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
gdb_out("usage: monitor option <addr> <value>\n"); gdb_out("usage: monitor option <addr> <value>\n");
} }
if (0 && flash_obp_rdp_key == FLASH_OBP_RDP_KEY_F3) {
/* Reload option bytes on F0 and F3*/
val = adiv5_ap_mem_read(ap, FLASH_CR);
val |= FLASH_CR_OBL_LAUNCH;
stm32f1_option_write(t, FLASH_CR, val);
val &= ~FLASH_CR_OBL_LAUNCH;
stm32f1_option_write(t, FLASH_CR, val);
}
for (int i = 0; i < 0xf; i += 4) { for (int i = 0; i < 0xf; i += 4) {
addr = 0x1ffff800 + i; addr = 0x1ffff800 + i;
val = adiv5_ap_mem_read(ap, addr); val = adiv5_ap_mem_read(ap, addr);

View File

@ -36,6 +36,15 @@
#include "general.h" #include "general.h"
#include "adiv5.h" #include "adiv5.h"
#include "target.h" #include "target.h"
#include "command.h"
static bool stm32f4_cmd_option(target *t, int argc, char *argv[]);
const struct command_s stm32f4_cmd_list[] = {
{"option", (cmd_handler)stm32f4_cmd_option, "Manipulate option bytes"},
{NULL, NULL, NULL}
};
static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, int len); static int stm32f4_flash_erase(struct target_s *target, uint32_t addr, int len);
static int stm32f4_flash_write(struct target_s *target, uint32_t dest, static int stm32f4_flash_write(struct target_s *target, uint32_t dest,
@ -85,9 +94,16 @@ static const char stm32f4_xml_memory_map[] = "<?xml version=\"1.0\"?>"
#define FLASH_SR_BSY (1 << 16) #define FLASH_SR_BSY (1 << 16)
#define FLASH_OPTCR_OPTLOCK (1 << 0)
#define FLASH_OPTCR_OPTSTRT (1 << 1)
#define FLASH_OPTCR_RESERVED 0xf0000013
#define KEY1 0x45670123 #define KEY1 0x45670123
#define KEY2 0xCDEF89AB #define KEY2 0xCDEF89AB
#define OPTKEY1 0x08192A3B
#define OPTKEY2 0x4C5D6E7F
#define SR_ERROR_MASK 0xF2 #define SR_ERROR_MASK 0xF2
#define SR_EOP 0x01 #define SR_EOP 0x01
@ -145,6 +161,7 @@ bool stm32f4_probe(struct target_s *target)
target->xml_mem_map = stm32f4_xml_memory_map; target->xml_mem_map = stm32f4_xml_memory_map;
target->flash_erase = stm32f4_flash_erase; target->flash_erase = stm32f4_flash_erase;
target->flash_write = stm32f4_flash_write; target->flash_write = stm32f4_flash_write;
target_add_commands(target, stm32f4_cmd_list, "STM32F4");
return true; return true;
} }
return false; return false;
@ -234,3 +251,45 @@ static int stm32f4_flash_write(struct target_s *target, uint32_t dest,
return 0; return 0;
} }
static bool stm32f4_option_write(target *t, uint32_t value)
{
ADIv5_AP_t *ap = adiv5_target_ap(t);
adiv5_ap_mem_write(ap, FLASH_OPTKEYR, OPTKEY1);
adiv5_ap_mem_write(ap, FLASH_OPTKEYR, OPTKEY2);
value &= ~FLASH_OPTCR_RESERVED;
while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return -1;
/* WRITE option bytes instruction */
adiv5_ap_mem_write(ap, FLASH_OPTCR, value);
adiv5_ap_mem_write(ap, FLASH_OPTCR, value | FLASH_OPTCR_OPTSTRT);
/* Read FLASH_SR to poll for BSY bit */
while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return false;
adiv5_ap_mem_write(ap, FLASH_OPTCR, value | FLASH_OPTCR_OPTLOCK);
return true;
}
static bool stm32f4_cmd_option(target *t, int argc, char *argv[])
{
uint32_t addr, val;
ADIv5_AP_t *ap = adiv5_target_ap(t);
if ((argc == 3) && !strcmp(argv[1], "write")) {
val = strtoul(argv[2], NULL, 0);
stm32f4_option_write(t, val);
} else {
gdb_out("usage: monitor option write <value>\n");
}
for (int i = 0; i < 0xf; i += 8) {
addr = 0x1fffC000 + i;
val = adiv5_ap_mem_read(ap, addr);
gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF);
}
return true;
}