Skip to content

Commit

Permalink
Add support for STLink V3
Browse files Browse the repository at this point in the history
Flash programming is broken
  • Loading branch information
martonmiklos committed Apr 21, 2020
1 parent 82ac538 commit 09ea99a
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 159 deletions.
68 changes: 64 additions & 4 deletions include/stlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ extern "C" {
//#define Q_BUF_LEN 96
#define Q_BUF_LEN (1024 * 100)

// STLINK_DEBUG_RESETSYS, etc:
// STLINK_DEBUG_RESETSYS, etc:
enum target_state {
TARGET_UNKNOWN = 0,
TARGET_RUNNING = 1,
TARGET_HALTED = 2,
TARGET_RESET = 3,
TARGET_DEBUG_RUNNING = 4,
};

#define STLINK_CORE_RUNNING 0x80
#define STLINK_CORE_HALTED 0x81
#define STLINK_CORE_STAT_UNKNOWN -1

#define STLINK_GET_VERSION 0xf1
#define STLINK_GET_CURRENT_MODE 0xf5
Expand All @@ -52,6 +59,11 @@ extern "C" {

#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43

#define STLINK_APIV3_SET_COM_FREQ 0x61
#define STLINK_APIV3_GET_COM_FREQ 0x62

#define STLINK_APIV3_GET_VERSION_EX 0xFB

// Baud rate divisors for SWDCLK
#define STLINK_SWDCLK_4MHZ_DIVISOR 0
#define STLINK_SWDCLK_1P8MHZ_DIVISOR 1
Expand All @@ -68,7 +80,45 @@ extern "C" {

#define STLINK_SERIAL_MAX_SIZE 64

/* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
#define STLINK_V3_MAX_FREQ_NB 10

/* Cortex Debug Control Block */
#define DCB_DHCSR 0xE000EDF0
#define DCB_DCRSR 0xE000EDF4
#define DCB_DCRDR 0xE000EDF8
#define DCB_DEMCR 0xE000EDFC

/* DCB_DHCSR bit and field definitions */
#define DBGKEY (0xA05F << 16)
#define C_DEBUGEN (1 << 0)
#define C_HALT (1 << 1)
#define C_STEP (1 << 2)
#define C_MASKINTS (1 << 3)
#define S_REGRDY (1 << 16)
#define S_HALT (1 << 17)
#define S_SLEEP (1 << 18)
#define S_LOCKUP (1 << 19)
#define S_RETIRE_ST (1 << 24)
#define S_RESET_ST (1 << 25)


/*
* Map the relevant features, quirks and workaround for specific firmware
* version of stlink
*/
#define STLINK_F_HAS_TRACE (1<<0)
#define STLINK_F_HAS_SWD_SET_FREQ (1<<1)
#define STLINK_F_HAS_JTAG_SET_FREQ (1<<2)
#define STLINK_F_HAS_MEM_16BIT (1<<3)
#define STLINK_F_HAS_GETLASTRWSTATUS2 (1<<4)
#define STLINK_F_HAS_DAP_REG (1<<5)
#define STLINK_F_QUIRK_JTAG_DP_READ (1<<6)
#define STLINK_F_HAS_AP_INIT (1<<7)
#define STLINK_F_HAS_DPBANKSEL (1<<8)
#define STLINK_F_HAS_RW8_512BYTES (1<<9)


/* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
#define C_BUF_LEN 32

enum stlink_flash_type {
Expand Down Expand Up @@ -111,12 +161,22 @@ typedef struct flash_loader {
uint8_t revision;
} cortex_m3_cpuid_t;

enum stlink_jtag_api_version {
STLINK_JTAG_API_V1 = 1,
STLINK_JTAG_API_V2,
STLINK_JTAG_API_V3,
};

typedef struct stlink_version_ {
uint32_t stlink_v;
uint32_t jtag_v;
uint32_t swim_v;
uint32_t st_vid;
uint32_t stlink_pid;
/** jtag api version supported */
enum stlink_jtag_api_version jtag_api;
/** one bit for each feature supported. See macros STLINK_F_* */
uint32_t flags;
} stlink_version_t;

enum transport_type {
Expand Down Expand Up @@ -144,7 +204,7 @@ typedef struct flash_loader {
int verbose;
uint32_t core_id; // set by stlink_core_id(), result from STLINK_DEBUGREADCOREID
uint32_t chip_id; // set by stlink_load_device_params(), used to identify flash and sram
int core_stat; // set by stlink_status(), values STLINK_CORE_xxxxx
enum target_state core_stat; // set by stlink_status()

char serial[STLINK_SERIAL_MAX_SIZE];
int serial_size;
Expand Down
48 changes: 29 additions & 19 deletions include/stlink/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@
#define STLINK_COMMANDS_H_

enum stlink_debug_commands {
STLINK_DEBUG_ENTER_JTAG = 0x00,
STLINK_DEBUG_GETSTATUS = 0x01,
STLINK_DEBUG_FORCEDEBUG = 0x02,
STLINK_DEBUG_RESETSYS = 0x03,
STLINK_DEBUG_READALLREGS = 0x04,
STLINK_DEBUG_READREG = 0x05,
STLINK_DEBUG_WRITEREG = 0x06,
STLINK_DEBUG_READMEM_32BIT = 0x07,
STLINK_DEBUG_WRITEMEM_32BIT = 0x08,
STLINK_DEBUG_RUNCORE = 0x09,
STLINK_DEBUG_STEPCORE = 0x0a,
STLINK_DEBUG_SETFP = 0x0b,
STLINK_DEBUG_WRITEMEM_8BIT = 0x0d,
STLINK_DEBUG_CLEARFP = 0x0e,
STLINK_DEBUG_WRITEDEBUGREG = 0x0f,
STLINK_DEBUG_ENTER = 0x20,
STLINK_DEBUG_EXIT = 0x21,
STLINK_DEBUG_READCOREID = 0x22,
STLINK_DEBUG_ENTER_SWD = 0xa3
STLINK_DEBUG_ENTER_JTAG = 0x00,
STLINK_DEBUG_GETSTATUS = 0x01,
STLINK_DEBUG_FORCEDEBUG = 0x02,
STLINK_DEBUG_APIV1_RESETSYS = 0x03,
STLINK_DEBUG_APIV1_READALLREGS = 0x04,
STLINK_DEBUG_APIV1_READREG = 0x05,
STLINK_DEBUG_APIV1_WRITEREG = 0x06,
STLINK_DEBUG_READMEM_32BIT = 0x07,
STLINK_DEBUG_WRITEMEM_32BIT = 0x08,
STLINK_DEBUG_RUNCORE = 0x09,
STLINK_DEBUG_STEPCORE = 0x0a,
STLINK_DEBUG_APIV1_SETFP = 0x0b,
STLINK_DEBUG_WRITEMEM_8BIT = 0x0d,
STLINK_DEBUG_APIV1_CLEARFP = 0x0e,
STLINK_DEBUG_APIV1_WRITEDEBUGREG = 0x0f,
STLINK_DEBUG_APIV1_ENTER = 0x20,
STLINK_DEBUG_EXIT = 0x21,
STLINK_DEBUG_READCOREID = 0x22,
STLINK_DEBUG_APIV2_ENTER = 0x30,
STLINK_DEBUG_APIV2_READ_IDCODES = 0x31,
STLINK_DEBUG_APIV2_RESETSYS = 0x32,
STLINK_DEBUG_APIV2_READREG = 0x33,
STLINK_DEBUG_APIV2_WRITEREG = 0x34,
STLINK_DEBUG_APIV2_WRITEDEBUGREG = 0x35,
STLINK_DEBUG_APIV2_READDEBUGREG = 0x36,
STLINK_DEBUG_APIV2_READALLREGS = 0x3A,
STLINK_DEBUG_APIV2_GETLASTRWSTATUS = 0x3B,
STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 = 0x3E,
STLINK_DEBUG_ENTER_SWD = 0xa3
};

#endif /* STLINK_COMMANDS_H_ */
2 changes: 1 addition & 1 deletion include/stlink/tools/flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <stlink.h>

#define DEBUG_LOG_LEVEL 100
#define STND_LOG_LEVEL 50
#define STND_LOG_LEVEL 100

enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4};
enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1};
Expand Down
14 changes: 9 additions & 5 deletions include/stlink/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
extern "C" {
#endif

#define STLINK_USB_VID_ST 0x0483
#define STLINK_USB_PID_STLINK 0x3744
#define STLINK_USB_PID_STLINK_32L 0x3748
#define STLINK_USB_PID_STLINK_32L_AUDIO 0x374a
#define STLINK_USB_PID_STLINK_NUCLEO 0x374b
#define STLINK_USB_VID_ST 0x0483
#define STLINK_USB_PID_STLINK 0x3744
#define STLINK_USB_PID_STLINK_32L 0x3748
#define STLINK_USB_PID_STLINK_32L_AUDIO 0x374a
#define STLINK_USB_PID_STLINK_NUCLEO 0x374b
#define STLINK_USB_PID_STLINK_V3_USBLOADER 0x374d
#define STLINK_USB_PID_STLINK_V3E_PID 0x374e
#define STLINK_USB_PID_STLINK_V3S_PID 0x374f
#define STLINK_USB_PID_STLINK_V3_2VCP_PID 0x3753

#define STLINK_SG_SIZE 31
#define STLINK_CMD_SIZE 16
Expand Down
100 changes: 59 additions & 41 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,23 +892,48 @@ int stlink_status(stlink_t *sl) {
* @param sl stlink context, assumed to contain valid data in the buffer
* @param slv output parsed version object
*/
void _parse_version(stlink_t *sl, stlink_version_t *slv) {
uint32_t b0 = sl->q_buf[0]; //lsb
uint32_t b1 = sl->q_buf[1];
uint32_t b2 = sl->q_buf[2];
uint32_t b3 = sl->q_buf[3];
uint32_t b4 = sl->q_buf[4];
uint32_t b5 = sl->q_buf[5]; //msb

// b0 b1 || b2 b3 | b4 b5
// 4b | 6b | 6b || 2B | 2B
// stlink_v | jtag_v | swim_v || st_vid | stlink_pid

slv->stlink_v = (b0 & 0xf0) >> 4;
slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6);
slv->swim_v = b1 & 0x3f;
slv->st_vid = (b3 << 8) | b2;
slv->stlink_pid = (b5 << 8) | b4;
void _parse_version(stlink_t *sl, stlink_version_t *slv)
{
sl->version.flags = 0;
if (sl->version.stlink_v < 3) {
uint32_t b0 = sl->q_buf[0]; //lsb
uint32_t b1 = sl->q_buf[1];
uint32_t b2 = sl->q_buf[2];
uint32_t b3 = sl->q_buf[3];
uint32_t b4 = sl->q_buf[4];
uint32_t b5 = sl->q_buf[5]; //msb

// b0 b1 || b2 b3 | b4 b5
// 4b | 6b | 6b || 2B | 2B
// stlink_v | jtag_v | swim_v || st_vid | stlink_pid

slv->stlink_v = (b0 & 0xf0) >> 4;
slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6);
slv->swim_v = b1 & 0x3f;
slv->st_vid = (b3 << 8) | b2;
slv->stlink_pid = (b5 << 8) | b4;
/* ST-LINK/V1 from J11 switch to api-v2 (and support SWD) */
if (slv->stlink_v == 1)
slv->jtag_api = slv->jtag_v > 11? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1;
else {
slv->jtag_api = STLINK_JTAG_API_V2;
/* preferred API to get last R/W status from J15 */
if (sl->version.jtag_v >= 15)
sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
}
} else {
// V3 uses different version format, for reference see OpenOCD source
// (that was written from docs available from ST under NDA):
// https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965
slv->stlink_v = sl->q_buf[0];
slv->swim_v = sl->q_buf[1];
slv->jtag_v = sl->q_buf[2];
slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]);
slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]);
slv->jtag_api = STLINK_JTAG_API_V3;
/* preferred API to get last R/W status */
sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
}
return;
}

Expand Down Expand Up @@ -1065,13 +1090,8 @@ int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, struct s

bool stlink_is_core_halted(stlink_t *sl)
{
bool ret = false;

stlink_status(sl);
if (sl->q_buf[0] == STLINK_CORE_HALTED)
ret = true;

return ret;
stlink_status(sl);
return sl->core_stat == TARGET_HALTED;
}

int stlink_step(stlink_t *sl) {
Expand Down Expand Up @@ -1140,29 +1160,29 @@ void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
// this function is called by stlink_status()
// do not call stlink_core_stat() directly, always use stlink_status()
void stlink_core_stat(stlink_t *sl) {
if (sl->q_len <= 0)
return;

switch (sl->q_buf[0]) {
case STLINK_CORE_RUNNING:
sl->core_stat = STLINK_CORE_RUNNING;
switch (sl->core_stat ) {
case TARGET_RUNNING:
DLOG(" core status: running\n");
return;
case STLINK_CORE_HALTED:
sl->core_stat = STLINK_CORE_HALTED;
case TARGET_HALTED:
DLOG(" core status: halted\n");
return;
case TARGET_RESET:
DLOG(" core status: reset\n");
return;
case TARGET_DEBUG_RUNNING:
DLOG(" core status: debug running\n");
return;
default:
sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
fprintf(stderr, " core status: unknown\n");
DLOG(" core status: unknown\n");
}
}

void stlink_print_data(stlink_t * sl) {
if (sl->q_len <= 0 || sl->verbose < UDEBUG)
return;
if (sl->verbose > 2)
fprintf(stdout, "data_len = %d 0x%x\n", sl->q_len, sl->q_len);
DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len);

for (int i = 0; i < sl->q_len; i++) {
if (i % 16 == 0) {
Expand All @@ -1173,9 +1193,9 @@ void stlink_print_data(stlink_t * sl) {
fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
*/
}
fprintf(stdout, " %02x", (unsigned int) sl->q_buf[i]);
DLOG(" %02x", (unsigned int) sl->q_buf[i]);
}
fputs("\n\n", stdout);
DLOG("\n\n");
}

/* memory mapped file */
Expand Down Expand Up @@ -2059,17 +2079,15 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t
/* erase each page */
int page_count = 0;
for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + (uint32_t) off)) {
/* addr must be an addr inside the page */
// addr must be an addr inside the page
if (stlink_erase_flash_page(sl, addr + (uint32_t) off) == -1) {
ELOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
return -1;
}
fprintf(stdout,"\rFlash page at addr: 0x%08lx erased",
ILOG("Flash page at addr: 0x%08lx erased\n",
(unsigned long)(addr + off));
fflush(stdout);
page_count++;
}
fprintf(stdout,"\n");
ILOG("Finished erasing %d pages of %d (%#x) bytes\n",
page_count, sl->flash_pgsz, sl->flash_pgsz);

Expand Down
4 changes: 3 additions & 1 deletion src/flash_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,9 @@ int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t*
}

memcpy(sl->q_buf, loader_code, loader_size);
stlink_write_mem32(sl, sl->sram_base, loader_size);
int ret = stlink_write_mem32(sl, sl->sram_base, loader_size);
if (ret)
return ret;

*addr = sl->sram_base;
*size = loader_size;
Expand Down
2 changes: 1 addition & 1 deletion src/gdbserver/gdb-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ int serve(stlink_t *sl, st_state_t *st) {
}

stlink_status(sl);
if(sl->core_stat == STLINK_CORE_HALTED) {
if(sl->core_stat == TARGET_HALTED) {
struct stlink_reg reg;
int ret;
stm32_addr_t pc;
Expand Down
2 changes: 1 addition & 1 deletion src/logging.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include "stlink/logging.h"

static int max_level = UINFO;
static int max_level = UDEBUG;

int ugly_init(int maximum_threshold) {
max_level = maximum_threshold;
Expand Down
Loading

0 comments on commit 09ea99a

Please sign in to comment.