kopia lustrzana https://github.com/stlink-org/stlink
Initial commit of workable stm32l debug
Move towards a standard libstlink, with backends for libusb (stm32l discovery) and scsi passthrough (stm32vl discovery) and a common front end. Verified that stm32l branch works much the same, but more to go for stm32vl.pull/29/head
rodzic
8be7cea215
commit
d060c3c040
|
@ -0,0 +1,44 @@
|
|||
|
||||
VPATH=src
|
||||
|
||||
SOURCES_LIB=stlink-common.c stlink-usb.c #stlink-sg.c
|
||||
OBJS_LIB=$(SOURCES_LIB:.c=.o)
|
||||
|
||||
CFLAGS+=-DCONFIG_USE_LIBUSB
|
||||
#CFLAGS+=-DCONFIG_USE_LIBSG
|
||||
CFLAGS+= -std=gnu99
|
||||
CFLAGS+=-Wall -Wextra
|
||||
|
||||
LDFLAGS=-lstlink -lusb-1.0 -L.
|
||||
|
||||
LIBRARY=libstlink.a
|
||||
|
||||
all: $(LIBRARY) test_usb #test_sg
|
||||
|
||||
$(LIBRARY): $(OBJS_LIB)
|
||||
@echo "objs are $(OBJS_LIB)"
|
||||
$(AR) -cr $@ $^
|
||||
@echo "done making library"
|
||||
|
||||
|
||||
test_sg: test_sg.o $(LIBRARY)
|
||||
@echo "building test_sg"
|
||||
$(CC) $(LDFLAGS) -o $@
|
||||
|
||||
test_usb: test_usb.o $(LIBRARY)
|
||||
@echo "building test_usb"
|
||||
$(CC) test_usb.o $(LDFLAGS) -o $@
|
||||
@echo "done linking"
|
||||
|
||||
%.o: %.c
|
||||
@echo "building $^ into $@"
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
@echo "done compiling"
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS_LIB)
|
||||
rm -rf $(LIBRARY)
|
||||
rm -rf test_usb*
|
||||
rm -rf test_sg*
|
||||
|
||||
.PHONY: clean all
|
|
@ -1,22 +0,0 @@
|
|||
PRG := st-util
|
||||
DEBUG := #-DDEBUG
|
||||
|
||||
all: $(PRG)
|
||||
|
||||
LIBS := \
|
||||
-lsgutils2
|
||||
|
||||
OBJS += \
|
||||
stlink-hw.o gdb-remote.o gdb-server.o
|
||||
|
||||
$(PRG): $(OBJS)
|
||||
gcc -o $(PRG) $(OBJS) $(LIBS)
|
||||
|
||||
%.o: ../src/%.c
|
||||
gcc -O3 -g3 -Wall -Werror -c -std=gnu99 -MMD -MP \
|
||||
-fno-strict-aliasing -Wno-unused $(DEBUG) \
|
||||
-MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)"\
|
||||
-o "$@" "$<"
|
||||
|
||||
clean:
|
||||
@rm -vf *.d *.o $(PRG)
|
|
@ -0,0 +1,351 @@
|
|||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
#include "stlink-common.h"
|
||||
|
||||
void D(stlink_t *sl, char *txt) {
|
||||
if (sl->verbose > 1)
|
||||
fputs(txt, stderr);
|
||||
}
|
||||
|
||||
void DD(stlink_t *sl, char *format, ...) {
|
||||
if (sl->verbose > 0) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vfprintf(stderr, format, list);
|
||||
va_end(list);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegates to the backends...
|
||||
|
||||
void stlink_close(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_close ***\n");
|
||||
sl->backend->close(sl);
|
||||
|
||||
free(sl);
|
||||
}
|
||||
|
||||
void stlink_exit_debug_mode(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_exit_debug_mode ***\n");
|
||||
sl->backend->exit_debug_mode(sl);
|
||||
}
|
||||
|
||||
void stlink_enter_swd_mode(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_enter_swd_mode ***\n");
|
||||
sl->backend->enter_swd_mode(sl);
|
||||
}
|
||||
|
||||
void stlink_exit_dfu_mode(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_exit_duf_mode ***\n");
|
||||
sl->backend->exit_dfu_mode(sl);
|
||||
}
|
||||
|
||||
void stlink_core_id(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_core_id ***\n");
|
||||
sl->backend->core_id(sl);
|
||||
DD(sl, "core_id = 0x%08x\n", sl->core_id);
|
||||
}
|
||||
|
||||
void stlink_reset(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_reset ***\n");
|
||||
sl->backend->reset(sl);
|
||||
|
||||
}
|
||||
|
||||
void stlink_run(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_core_id ***\n");
|
||||
sl->backend->run(sl);
|
||||
DD(sl, "core_id = 0x%08x\n", sl->core_id);
|
||||
}
|
||||
|
||||
void stlink_status(stlink_t *sl) {
|
||||
D(sl, "\n*** stlink_core_id ***\n");
|
||||
sl->backend->status(sl);
|
||||
stlink_core_stat(sl);
|
||||
DD(sl, "core_id = 0x%08x\n", sl->core_id);
|
||||
}
|
||||
|
||||
void stlink_version(stlink_t *sl) {
|
||||
D(sl, "*** looking up stlink version\n");
|
||||
sl->backend->version(sl);
|
||||
}
|
||||
|
||||
void stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
D(sl, "\n*** stlink_write_mem32 ***\n");
|
||||
if (len % 4 != 0) {
|
||||
fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
|
||||
return;
|
||||
}
|
||||
sl->backend->write_mem32(sl, addr, len);
|
||||
}
|
||||
|
||||
void stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
D(sl, "\n*** stlink_write_mem8 ***\n");
|
||||
sl->backend->write_mem8(sl, addr, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// End of delegates.... Common code below here...
|
||||
|
||||
// Endianness
|
||||
// http://www.ibm.com/developerworks/aix/library/au-endianc/index.html
|
||||
// const int i = 1;
|
||||
// #define is_bigendian() ( (*(char*)&i) == 0 )
|
||||
|
||||
static inline unsigned int is_bigendian(void) {
|
||||
static volatile const unsigned int i = 1;
|
||||
return *(volatile const char*) &i == 0;
|
||||
}
|
||||
|
||||
uint16_t read_uint16(const unsigned char *c, const int pt) {
|
||||
uint32_t ui;
|
||||
char *p = (char *) &ui;
|
||||
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
p[0] = c[pt];
|
||||
p[1] = c[pt + 1];
|
||||
} else {
|
||||
p[0] = c[pt + 1];
|
||||
p[1] = c[pt];
|
||||
}
|
||||
return ui;
|
||||
}
|
||||
|
||||
void stlink_core_stat(stlink_t *sl) {
|
||||
if (sl->q_len <= 0)
|
||||
return;
|
||||
|
||||
stlink_print_data(sl);
|
||||
|
||||
switch (sl->q_buf[0]) {
|
||||
case STLINK_CORE_RUNNING:
|
||||
sl->core_stat = STLINK_CORE_RUNNING;
|
||||
DD(sl, " core status: running\n");
|
||||
return;
|
||||
case STLINK_CORE_HALTED:
|
||||
sl->core_stat = STLINK_CORE_HALTED;
|
||||
DD(sl, " core status: halted\n");
|
||||
return;
|
||||
default:
|
||||
sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
|
||||
fprintf(stderr, " core status: unknown\n");
|
||||
}
|
||||
}
|
||||
|
||||
void stlink_print_data(stlink_t *sl) {
|
||||
if (sl->q_len <= 0 || sl->verbose < 2)
|
||||
return;
|
||||
if (sl->verbose > 2)
|
||||
fprintf(stdout, "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) {
|
||||
/*
|
||||
if (sl->q_data_dir == Q_DATA_OUT)
|
||||
fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
|
||||
else
|
||||
fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
|
||||
*/
|
||||
}
|
||||
fprintf(stdout, " %02x", (unsigned int) sl->q_buf[i]);
|
||||
}
|
||||
fputs("\n\n", stdout);
|
||||
}
|
||||
|
||||
/* memory mapped file */
|
||||
|
||||
typedef struct mapped_file {
|
||||
uint8_t* base;
|
||||
size_t len;
|
||||
} mapped_file_t;
|
||||
|
||||
#define MAPPED_FILE_INITIALIZER { NULL, 0 }
|
||||
|
||||
static int map_file(mapped_file_t* mf, const char* path) {
|
||||
int error = -1;
|
||||
struct stat st;
|
||||
|
||||
const int fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "open(%s) == -1\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) == -1) {
|
||||
fprintf(stderr, "fstat() == -1\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
mf->base = (uint8_t*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (mf->base == MAP_FAILED) {
|
||||
fprintf(stderr, "mmap() == MAP_FAILED\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
mf->len = st.st_size;
|
||||
|
||||
/* success */
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
close(fd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void unmap_file(mapped_file_t* mf) {
|
||||
munmap((void*) mf->base, mf->len);
|
||||
mf->base = (unsigned char*) MAP_FAILED;
|
||||
mf->len = 0;
|
||||
}
|
||||
|
||||
static int check_file
|
||||
(stlink_t* sl, mapped_file_t* mf, stm32_addr_t addr) {
|
||||
size_t off;
|
||||
|
||||
for (off = 0; off < mf->len; off += sl->flash_pgsz) {
|
||||
size_t aligned_size;
|
||||
|
||||
/* adjust last page size */
|
||||
size_t cmp_size = sl->flash_pgsz;
|
||||
if ((off + sl->flash_pgsz) > mf->len)
|
||||
cmp_size = mf->len - off;
|
||||
|
||||
aligned_size = cmp_size;
|
||||
if (aligned_size & (4 - 1))
|
||||
aligned_size = (cmp_size + 4) & ~(4 - 1);
|
||||
|
||||
stlink_read_mem32(sl, addr + off, aligned_size);
|
||||
|
||||
if (memcmp(sl->q_buf, mf->base + off, cmp_size))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stlink_fwrite_sram
|
||||
(stlink_t * sl, const char* path, stm32_addr_t addr) {
|
||||
/* write the file in sram at addr */
|
||||
|
||||
int error = -1;
|
||||
size_t off;
|
||||
mapped_file_t mf = MAPPED_FILE_INITIALIZER;
|
||||
|
||||
if (map_file(&mf, path) == -1) {
|
||||
fprintf(stderr, "map_file() == -1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check addr range is inside the sram */
|
||||
if (addr < sl->sram_base) {
|
||||
fprintf(stderr, "addr too low\n");
|
||||
goto on_error;
|
||||
} else if ((addr + mf.len) < addr) {
|
||||
fprintf(stderr, "addr overruns\n");
|
||||
goto on_error;
|
||||
} else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) {
|
||||
fprintf(stderr, "addr too high\n");
|
||||
goto on_error;
|
||||
} else if ((addr & 3) || (mf.len & 3)) {
|
||||
/* todo */
|
||||
fprintf(stderr, "unaligned addr or size\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* do the copy by 1k blocks */
|
||||
for (off = 0; off < mf.len; off += 1024) {
|
||||
size_t size = 1024;
|
||||
if ((off + size) > mf.len)
|
||||
size = mf.len - off;
|
||||
|
||||
memcpy(sl->q_buf, mf.base + off, size);
|
||||
|
||||
/* round size if needed */
|
||||
if (size & 3)
|
||||
size += 2;
|
||||
|
||||
stlink_write_mem32(sl, addr + off, size);
|
||||
}
|
||||
|
||||
/* check the file ha been written */
|
||||
if (check_file(sl, &mf, addr) == -1) {
|
||||
fprintf(stderr, "check_file() == -1\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* success */
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
unmap_file(&mf);
|
||||
return error;
|
||||
}
|
||||
|
||||
int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size) {
|
||||
/* read size bytes from addr to file */
|
||||
|
||||
int error = -1;
|
||||
size_t off;
|
||||
|
||||
const int fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 00700);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "open(%s) == -1\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do the copy by 1k blocks */
|
||||
for (off = 0; off < size; off += 1024) {
|
||||
size_t read_size = 1024;
|
||||
if ((off + read_size) > size)
|
||||
read_size = off + read_size;
|
||||
|
||||
/* round size if needed */
|
||||
if (read_size & 3)
|
||||
read_size = (read_size + 4) & ~(3);
|
||||
|
||||
stlink_read_mem32(sl, addr + off, read_size);
|
||||
|
||||
if (write(fd, sl->q_buf, read_size) != (ssize_t) read_size) {
|
||||
fprintf(stderr, "write() != read_size\n");
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
close(fd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
typedef struct flash_loader {
|
||||
stm32_addr_t loader_addr; /* loader sram adddr */
|
||||
stm32_addr_t buf_addr; /* buffer sram address */
|
||||
} flash_loader_t;
|
||||
|
||||
int write_buffer_to_sram
|
||||
(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size) {
|
||||
/* write the buffer right after the loader */
|
||||
memcpy(sl->q_buf, buf, size);
|
||||
stlink_write_mem8(sl, fl->buf_addr, size);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* File: stlink-common.h
|
||||
* Bulk import from stlink-hw.h
|
||||
*
|
||||
* This should contain all the common top level stlink interfaces, regardless
|
||||
* of how the backend does the work....
|
||||
*/
|
||||
|
||||
#ifndef STLINK_COMMON_H
|
||||
#define STLINK_COMMON_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Max data transfer size.
|
||||
// 6kB = max mem32_read block, 8kB sram
|
||||
//#define Q_BUF_LEN 96
|
||||
#define Q_BUF_LEN 1024 * 100
|
||||
|
||||
// st-link vendor cmd's
|
||||
#define USB_ST_VID 0x0483
|
||||
#define USB_STLINK_PID 0x3744
|
||||
|
||||
// STLINK_DEBUG_RESETSYS, etc:
|
||||
#define STLINK_OK 0x80
|
||||
#define STLINK_FALSE 0x81
|
||||
#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
|
||||
|
||||
#define STLINK_DEBUG_COMMAND 0xF2
|
||||
#define STLINK_DFU_COMMAND 0xF3
|
||||
#define STLINK_DFU_EXIT 0x07
|
||||
|
||||
// STLINK_GET_CURRENT_MODE
|
||||
#define STLINK_DEV_DFU_MODE 0x00
|
||||
#define STLINK_DEV_MASS_MODE 0x01
|
||||
#define STLINK_DEV_DEBUG_MODE 0x02
|
||||
#define STLINK_DEV_UNKNOWN_MODE -1
|
||||
|
||||
// jtag mode cmds
|
||||
#define STLINK_DEBUG_ENTER 0x20
|
||||
#define STLINK_DEBUG_EXIT 0x21
|
||||
#define STLINK_DEBUG_READCOREID 0x22
|
||||
#define STLINK_DEBUG_GETSTATUS 0x01
|
||||
#define STLINK_DEBUG_FORCEDEBUG 0x02
|
||||
#define STLINK_DEBUG_RESETSYS 0x03
|
||||
#define STLINK_DEBUG_READALLREGS 0x04
|
||||
#define STLINK_DEBUG_READREG 0x05
|
||||
#define STLINK_DEBUG_WRITEREG 0x06
|
||||
#define STLINK_DEBUG_READMEM_32BIT 0x07
|
||||
#define STLINK_DEBUG_WRITEMEM_32BIT 0x08
|
||||
#define STLINK_DEBUG_RUNCORE 0x09
|
||||
#define STLINK_DEBUG_STEPCORE 0x0a
|
||||
#define STLINK_DEBUG_SETFP 0x0b
|
||||
#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d
|
||||
#define STLINK_DEBUG_CLEARFP 0x0e
|
||||
#define STLINK_DEBUG_WRITEDEBUGREG 0x0f
|
||||
#define STLINK_DEBUG_ENTER_SWD 0xa3
|
||||
#define STLINK_DEBUG_ENTER_JTAG 0x00
|
||||
|
||||
typedef struct {
|
||||
uint32_t r[16];
|
||||
uint32_t xpsr;
|
||||
uint32_t main_sp;
|
||||
uint32_t process_sp;
|
||||
uint32_t rw;
|
||||
uint32_t rw2;
|
||||
} reg;
|
||||
|
||||
typedef uint32_t stm32_addr_t;
|
||||
|
||||
enum transport_type {
|
||||
TRANSPORT_TYPE_ZERO = 0,
|
||||
TRANSPORT_TYPE_LIBSG,
|
||||
TRANSPORT_TYPE_LIBUSB,
|
||||
TRANSPORT_TYPE_INVALID
|
||||
};
|
||||
|
||||
typedef struct _stlink stlink_t;
|
||||
|
||||
typedef struct _stlink_backend {
|
||||
void (*close) (stlink_t* sl);
|
||||
void (*exit_debug_mode) (stlink_t *sl);
|
||||
void (*enter_swd_mode) (stlink_t *sl);
|
||||
void (*enter_jtag_mode) (stlink_t *stl);
|
||||
void (*exit_dfu_mode) (stlink_t *stl);
|
||||
void (*core_id) (stlink_t *stl);
|
||||
void (*reset) (stlink_t *stl);
|
||||
void (*run) (stlink_t *stl);
|
||||
void (*status) (stlink_t *stl);
|
||||
void (*version) (stlink_t *stl);
|
||||
void (*write_mem32) (stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
void (*write_mem8) (stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
} stlink_backend_t;
|
||||
|
||||
struct _stlink {
|
||||
struct _stlink_backend *backend;
|
||||
void *backend_data;
|
||||
|
||||
// Data transferred from or to device
|
||||
unsigned char q_buf[Q_BUF_LEN];
|
||||
int q_len;
|
||||
|
||||
// transport layer verboseness: 0 for no debug info, 10 for lots
|
||||
int verbose;
|
||||
uint32_t core_id;
|
||||
int core_stat;
|
||||
|
||||
|
||||
|
||||
/* medium density stm32 flash settings */
|
||||
#define STM32_FLASH_BASE 0x08000000
|
||||
#define STM32_FLASH_SIZE (128 * 1024)
|
||||
#define STM32_FLASH_PGSZ 1024
|
||||
stm32_addr_t flash_base;
|
||||
size_t flash_size;
|
||||
size_t flash_pgsz;
|
||||
|
||||
/* in flash system memory */
|
||||
#define STM32_SYSTEM_BASE 0x1ffff000
|
||||
#define STM32_SYSTEM_SIZE (2 * 1024)
|
||||
stm32_addr_t sys_base;
|
||||
size_t sys_size;
|
||||
|
||||
/* sram settings */
|
||||
#define STM32_SRAM_BASE 0x20000000
|
||||
#define STM32_SRAM_SIZE (8 * 1024)
|
||||
stm32_addr_t sram_base;
|
||||
size_t sram_size;
|
||||
|
||||
};
|
||||
|
||||
// some quick and dirty logging...
|
||||
void D(stlink_t *sl, char *txt);
|
||||
void DD(stlink_t *sl, char *format, ...);
|
||||
|
||||
//stlink_t* stlink_quirk_open(const char *dev_name, const int verbose);
|
||||
|
||||
// delegated functions...
|
||||
void stlink_enter_swd_mode(stlink_t *sl);
|
||||
void stlink_enter_jtag_mode(stlink_t *sl);
|
||||
void stlink_exit_debug_mode(stlink_t *sl);
|
||||
void stlink_exit_dfu_mode(stlink_t *sl);
|
||||
void stlink_close(stlink_t *sl);
|
||||
void stlink_core_id(stlink_t *sl);
|
||||
void stlink_reset(stlink_t *sl);
|
||||
void stlink_run(stlink_t *sl);
|
||||
void stlink_status(stlink_t *sl);
|
||||
void stlink_version(stlink_t *sl);
|
||||
void stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
void stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
|
||||
|
||||
// unprocessed
|
||||
int stlink_current_mode(stlink_t *sl);
|
||||
void stlink_force_debug(stlink_t *sl);
|
||||
void stlink_step(stlink_t *sl);
|
||||
void stlink_read_all_regs(stlink_t *sl);
|
||||
void stlink_read_reg(stlink_t *sl, int r_idx);
|
||||
void stlink_write_reg(stlink_t *sl, uint32_t reg, int idx);
|
||||
void stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
|
||||
int stlink_erase_flash_page(stlink_t* sl, stm32_addr_t page);
|
||||
int stlink_erase_flash_mass(stlink_t* sl);
|
||||
int stlink_write_flash(stlink_t* sl, stm32_addr_t address, uint8_t* data, unsigned length);
|
||||
|
||||
// privates....
|
||||
uint16_t read_uint16(const unsigned char *c, const int pt);
|
||||
void stlink_core_stat(stlink_t *sl);
|
||||
void stlink_print_data(stlink_t *sl);
|
||||
|
||||
|
||||
#include "stlink-sg.h"
|
||||
#include "stlink-usb.h"
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_COMMON_H */
|
||||
|
1915
src/stlink-hw.c
1915
src/stlink-hw.c
Plik diff jest za duży
Load Diff
203
src/stlink-hw.h
203
src/stlink-hw.h
|
@ -1,203 +0,0 @@
|
|||
#ifndef _STLINK_HW_H_
|
||||
#define _STLINK_HW_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// device access
|
||||
#define RDWR 0
|
||||
#define RO 1
|
||||
#define SG_TIMEOUT_SEC 1 // actually 1 is about 2 sec
|
||||
// Each CDB can be a total of 6, 10, 12, or 16 bytes, later version
|
||||
// of the SCSI standard also allow for variable-length CDBs (min. CDB is 6).
|
||||
// the stlink needs max. 10 bytes.
|
||||
#define CDB_6 6
|
||||
#define CDB_10 10
|
||||
#define CDB_12 12
|
||||
#define CDB_16 16
|
||||
|
||||
#define CDB_SL 10
|
||||
|
||||
// Query data flow direction.
|
||||
#define Q_DATA_OUT 0
|
||||
#define Q_DATA_IN 1
|
||||
|
||||
// The SCSI Request Sense command is used to obtain sense data
|
||||
// (error information) from a target device.
|
||||
// http://en.wikipedia.org/wiki/SCSI_Request_Sense_Command
|
||||
#define SENSE_BUF_LEN 32
|
||||
|
||||
// Max data transfer size.
|
||||
// 6kB = max mem32_read block, 8kB sram
|
||||
//#define Q_BUF_LEN 96
|
||||
#define Q_BUF_LEN 1024 * 100
|
||||
|
||||
// st-link vendor cmd's
|
||||
#define USB_ST_VID 0x0483
|
||||
#define USB_STLINK_PID 0x3744
|
||||
|
||||
// STLINK_DEBUG_RESETSYS, etc:
|
||||
#define STLINK_OK 0x80
|
||||
#define STLINK_FALSE 0x81
|
||||
#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
|
||||
|
||||
#define STLINK_DEBUG_COMMAND 0xF2
|
||||
#define STLINK_DFU_COMMAND 0xF3
|
||||
#define STLINK_DFU_EXIT 0x07
|
||||
|
||||
// STLINK_GET_CURRENT_MODE
|
||||
#define STLINK_DEV_DFU_MODE 0x00
|
||||
#define STLINK_DEV_MASS_MODE 0x01
|
||||
#define STLINK_DEV_DEBUG_MODE 0x02
|
||||
#define STLINK_DEV_UNKNOWN_MODE -1
|
||||
|
||||
// jtag mode cmds
|
||||
#define STLINK_DEBUG_ENTER 0x20
|
||||
#define STLINK_DEBUG_EXIT 0x21
|
||||
#define STLINK_DEBUG_READCOREID 0x22
|
||||
#define STLINK_DEBUG_GETSTATUS 0x01
|
||||
#define STLINK_DEBUG_FORCEDEBUG 0x02
|
||||
#define STLINK_DEBUG_RESETSYS 0x03
|
||||
#define STLINK_DEBUG_READALLREGS 0x04
|
||||
#define STLINK_DEBUG_READREG 0x05
|
||||
#define STLINK_DEBUG_WRITEREG 0x06
|
||||
#define STLINK_DEBUG_READMEM_32BIT 0x07
|
||||
#define STLINK_DEBUG_WRITEMEM_32BIT 0x08
|
||||
#define STLINK_DEBUG_RUNCORE 0x09
|
||||
#define STLINK_DEBUG_STEPCORE 0x0a
|
||||
#define STLINK_DEBUG_SETFP 0x0b
|
||||
#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d
|
||||
#define STLINK_DEBUG_CLEARFP 0x0e
|
||||
#define STLINK_DEBUG_WRITEDEBUGREG 0x0f
|
||||
#define STLINK_DEBUG_ENTER_SWD 0xa3
|
||||
#define STLINK_DEBUG_ENTER_JTAG 0x00
|
||||
|
||||
typedef struct {
|
||||
uint32_t r[16];
|
||||
uint32_t xpsr;
|
||||
uint32_t main_sp;
|
||||
uint32_t process_sp;
|
||||
uint32_t rw;
|
||||
uint32_t rw2;
|
||||
} reg;
|
||||
|
||||
typedef uint32_t stm32_addr_t;
|
||||
|
||||
enum transport_type
|
||||
{
|
||||
TRANSPORT_TYPE_ZERO = 0,
|
||||
#if CONFIG_USE_LIBSG
|
||||
TRANSPORT_TYPE_LIBSG,
|
||||
#endif /* CONFIG_USE_LIBSG */
|
||||
#if CONFIG_USE_LIBUSB
|
||||
TRANSPORT_TYPE_LIBUSB,
|
||||
#endif /* CONFIG_USE_LIBUSB */
|
||||
TRANSPORT_TYPE_INVALID
|
||||
};
|
||||
|
||||
struct stlink_libusb
|
||||
{
|
||||
libusb_device_handle* usb_handle;
|
||||
struct libusb_transfer* req_trans;
|
||||
struct libusb_transfer* rep_trans;
|
||||
unsigned int ep_req;
|
||||
unsigned int ep_rep;
|
||||
};
|
||||
|
||||
struct stlink_libsg {
|
||||
int sg_fd;
|
||||
int do_scsi_pt_err;
|
||||
// sg layer verboseness: 0 for no debug info, 10 for lots
|
||||
int verbose;
|
||||
|
||||
unsigned char cdb_cmd_blk[CDB_SL];
|
||||
|
||||
// Data transferred from or to device
|
||||
unsigned char q_buf[Q_BUF_LEN];
|
||||
int q_len;
|
||||
int q_data_dir; // Q_DATA_IN, Q_DATA_OUT
|
||||
// the start of the query data in the device memory space
|
||||
uint32_t q_addr;
|
||||
|
||||
// Sense (error information) data
|
||||
unsigned char sense_buf[SENSE_BUF_LEN];
|
||||
|
||||
uint32_t st_vid;
|
||||
uint32_t stlink_pid;
|
||||
uint32_t stlink_v;
|
||||
uint32_t jtag_v;
|
||||
uint32_t swim_v;
|
||||
uint32_t core_id;
|
||||
|
||||
reg reg;
|
||||
int core_stat;
|
||||
|
||||
/* medium density stm32 flash settings */
|
||||
#define STM32_FLASH_BASE 0x08000000
|
||||
#define STM32_FLASH_SIZE (128 * 1024)
|
||||
#define STM32_FLASH_PGSZ 1024
|
||||
stm32_addr_t flash_base;
|
||||
size_t flash_size;
|
||||
size_t flash_pgsz;
|
||||
|
||||
/* in flash system memory */
|
||||
#define STM32_SYSTEM_BASE 0x1ffff000
|
||||
#define STM32_SYSTEM_SIZE (2 * 1024)
|
||||
stm32_addr_t sys_base;
|
||||
size_t sys_size;
|
||||
|
||||
/* sram settings */
|
||||
#define STM32_SRAM_BASE 0x20000000
|
||||
#define STM32_SRAM_SIZE (8 * 1024)
|
||||
stm32_addr_t sram_base;
|
||||
size_t sram_size;
|
||||
};
|
||||
|
||||
struct stlink
|
||||
{
|
||||
enum transport_type tt;
|
||||
union {
|
||||
#if CONFIG_USE_LIBUSB
|
||||
struct stlink_libusb *libusb;
|
||||
#endif /* CONFIG_USE_LIBUSB */
|
||||
#if CONFIG_USE_LIBSG
|
||||
struct stlink_libsg *libsg;
|
||||
#endif /* CONFIG_USE_LIBSG */
|
||||
} transport;
|
||||
|
||||
unsigned char q_buf[64];
|
||||
size_t q_len;
|
||||
|
||||
/* layer independant */
|
||||
uint32_t core_id;
|
||||
};
|
||||
|
||||
|
||||
struct stlink* stlink_quirk_open(enum transport_type tt, const char *dev_name, const int verbose);
|
||||
int stlink_current_mode(struct stlink *sl);
|
||||
void stlink_enter_swd_mode(struct stlink *sl);
|
||||
void stlink_enter_jtag_mode(struct stlink *sl);
|
||||
void stlink_exit_debug_mode(struct stlink *sl);
|
||||
void stlink_core_id(struct stlink *sl);
|
||||
void stlink_status(struct stlink *sl);
|
||||
void stlink_force_debug(struct stlink *sl);
|
||||
void stlink_reset(struct stlink *sl);
|
||||
void stlink_run(struct stlink *sl);
|
||||
void stlink_step(struct stlink *sl);
|
||||
void stlink_read_all_regs(struct stlink *sl);
|
||||
void stlink_read_reg(struct stlink *sl, int r_idx);
|
||||
void stlink_write_reg(struct stlink *sl, uint32_t reg, int idx);
|
||||
void stlink_read_mem32(struct stlink *sl, uint32_t addr, uint16_t len);
|
||||
void stlink_write_mem8(struct stlink *sl, uint32_t addr, uint16_t len);
|
||||
void stlink_write_mem32(struct stlink *sl, uint32_t addr, uint16_t len);
|
||||
void stlink_close(struct stlink *sl);
|
||||
|
||||
int stlink_erase_flash_page(struct stlink* sl, stm32_addr_t page);
|
||||
int stlink_erase_flash_mass(struct stlink* sl);
|
||||
int stlink_write_flash(struct stlink* sl, stm32_addr_t address, uint8_t* data, unsigned length);
|
||||
|
||||
#endif
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* File: stlink-sg.h
|
||||
* Author: karl
|
||||
*
|
||||
* Created on October 1, 2011, 11:29 PM
|
||||
*/
|
||||
|
||||
#ifndef STLINK_SG_H
|
||||
#define STLINK_SG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stlink-common.h"
|
||||
|
||||
// device access
|
||||
#define RDWR 0
|
||||
#define RO 1
|
||||
#define SG_TIMEOUT_SEC 1 // actually 1 is about 2 sec
|
||||
// Each CDB can be a total of 6, 10, 12, or 16 bytes, later version
|
||||
// of the SCSI standard also allow for variable-length CDBs (min. CDB is 6).
|
||||
// the stlink needs max. 10 bytes.
|
||||
#define CDB_6 6
|
||||
#define CDB_10 10
|
||||
#define CDB_12 12
|
||||
#define CDB_16 16
|
||||
|
||||
#define CDB_SL 10
|
||||
|
||||
// Query data flow direction.
|
||||
#define Q_DATA_OUT 0
|
||||
#define Q_DATA_IN 1
|
||||
|
||||
// The SCSI Request Sense command is used to obtain sense data
|
||||
// (error information) from a target device.
|
||||
// http://en.wikipedia.org/wiki/SCSI_Request_Sense_Command
|
||||
#define SENSE_BUF_LEN 32
|
||||
|
||||
|
||||
|
||||
#if defined(CONFIG_USE_LIBUSB)
|
||||
struct stlink_libsg {
|
||||
int sg_fd;
|
||||
int do_scsi_pt_err;
|
||||
|
||||
unsigned char cdb_cmd_blk[CDB_SL];
|
||||
|
||||
int q_data_dir; // Q_DATA_IN, Q_DATA_OUT
|
||||
// the start of the query data in the device memory space
|
||||
uint32_t q_addr;
|
||||
|
||||
// Sense (error information) data
|
||||
unsigned char sense_buf[SENSE_BUF_LEN];
|
||||
|
||||
uint32_t st_vid;
|
||||
uint32_t stlink_pid;
|
||||
uint32_t stlink_v;
|
||||
uint32_t jtag_v;
|
||||
uint32_t swim_v;
|
||||
uint32_t core_id;
|
||||
|
||||
reg reg;
|
||||
};
|
||||
#else
|
||||
struct stlink_libsg {};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_SG_H */
|
||||
|
|
@ -0,0 +1,552 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include "stlink-common.h"
|
||||
#include "stlink-usb.h"
|
||||
|
||||
/* endianess related */
|
||||
static inline unsigned int is_bigendian(void) {
|
||||
static volatile const unsigned int i = 1;
|
||||
return *(volatile const char*) &i == 0;
|
||||
}
|
||||
|
||||
void _stlink_usb_close(stlink_t* sl) {
|
||||
struct stlink_libusb * const handle = sl->backend_data;
|
||||
// maybe we couldn't even get the usb device?
|
||||
if (handle != NULL) {
|
||||
if (handle->req_trans != NULL)
|
||||
libusb_free_transfer(handle->req_trans);
|
||||
|
||||
if (handle->rep_trans != NULL)
|
||||
libusb_free_transfer(handle->rep_trans);
|
||||
|
||||
if (handle->usb_handle != NULL)
|
||||
libusb_close(handle->usb_handle);
|
||||
|
||||
libusb_exit(handle->libusb_ctx);
|
||||
free(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_uint32(unsigned char* buf, uint32_t ui) {
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
buf[0] = ((unsigned char*) &ui)[0];
|
||||
buf[1] = ((unsigned char*) &ui)[1];
|
||||
buf[2] = ((unsigned char*) &ui)[2];
|
||||
buf[3] = ((unsigned char*) &ui)[3];
|
||||
} else {
|
||||
buf[0] = ((unsigned char*) &ui)[3];
|
||||
buf[1] = ((unsigned char*) &ui)[2];
|
||||
buf[2] = ((unsigned char*) &ui)[1];
|
||||
buf[3] = ((unsigned char*) &ui)[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void write_uint16(unsigned char* buf, uint16_t ui) {
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
buf[0] = ((unsigned char*) &ui)[0];
|
||||
buf[1] = ((unsigned char*) &ui)[1];
|
||||
} else {
|
||||
buf[0] = ((unsigned char*) &ui)[1];
|
||||
buf[1] = ((unsigned char*) &ui)[0];
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t read_uint32(const unsigned char *c, const int pt) {
|
||||
uint32_t ui;
|
||||
char *p = (char *) &ui;
|
||||
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
p[0] = c[pt];
|
||||
p[1] = c[pt + 1];
|
||||
p[2] = c[pt + 2];
|
||||
p[3] = c[pt + 3];
|
||||
} else {
|
||||
p[0] = c[pt + 3];
|
||||
p[1] = c[pt + 2];
|
||||
p[2] = c[pt + 1];
|
||||
p[3] = c[pt];
|
||||
}
|
||||
return ui;
|
||||
}
|
||||
|
||||
|
||||
struct trans_ctx {
|
||||
#define TRANS_FLAGS_IS_DONE (1 << 0)
|
||||
#define TRANS_FLAGS_HAS_ERROR (1 << 1)
|
||||
volatile unsigned long flags;
|
||||
};
|
||||
|
||||
static void on_trans_done(struct libusb_transfer * trans) {
|
||||
struct trans_ctx * const ctx = trans->user_data;
|
||||
|
||||
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
|
||||
|
||||
ctx->flags |= TRANS_FLAGS_IS_DONE;
|
||||
}
|
||||
|
||||
int submit_wait(struct stlink_libusb *slu, struct libusb_transfer * trans) {
|
||||
struct timeval start;
|
||||
struct timeval now;
|
||||
struct timeval diff;
|
||||
struct trans_ctx trans_ctx;
|
||||
enum libusb_error error;
|
||||
|
||||
trans_ctx.flags = 0;
|
||||
|
||||
/* brief intrusion inside the libusb interface */
|
||||
trans->callback = on_trans_done;
|
||||
trans->user_data = &trans_ctx;
|
||||
|
||||
if ((error = libusb_submit_transfer(trans))) {
|
||||
printf("libusb_submit_transfer(%d)\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
while (trans_ctx.flags == 0) {
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if (libusb_handle_events_timeout(slu->libusb_ctx, &timeout)) {
|
||||
printf("libusb_handle_events()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&now, &start, &diff);
|
||||
if (diff.tv_sec >= 3) {
|
||||
printf("libusb_handle_events() timeout\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
|
||||
printf("libusb_handle_events() | has_error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t send_recv(struct stlink_libusb* handle,
|
||||
unsigned char* txbuf, size_t txsize,
|
||||
unsigned char* rxbuf, size_t rxsize) {
|
||||
/* note: txbuf and rxbuf can point to the same area */
|
||||
|
||||
libusb_fill_bulk_transfer(handle->req_trans, handle->usb_handle,
|
||||
handle->ep_req,
|
||||
txbuf, txsize,
|
||||
NULL, NULL,
|
||||
0
|
||||
);
|
||||
|
||||
printf("submit_wait(req)\n");
|
||||
|
||||
if (submit_wait(handle, handle->req_trans)) return -1;
|
||||
|
||||
/* send_only */
|
||||
if (rxsize == 0) return 0;
|
||||
|
||||
/* read the response */
|
||||
|
||||
libusb_fill_bulk_transfer(handle->rep_trans, handle->usb_handle,
|
||||
handle->ep_rep, rxbuf, rxsize, NULL, NULL, 0);
|
||||
|
||||
printf("submit_wait(rep)\n");
|
||||
|
||||
if (submit_wait(handle, handle->rep_trans)) return -1;
|
||||
|
||||
return handle->rep_trans->actual_length;
|
||||
}
|
||||
|
||||
static inline int send_only
|
||||
(struct stlink_libusb* handle, unsigned char* txbuf, size_t txsize) {
|
||||
return send_recv(handle, txbuf, txsize, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
// KARL - fixme, common code! (or, one per backend)
|
||||
// candidate for common code...
|
||||
|
||||
|
||||
static int is_stlink_device(libusb_device * dev) {
|
||||
struct libusb_device_descriptor desc;
|
||||
|
||||
if (libusb_get_device_descriptor(dev, &desc))
|
||||
return 0;
|
||||
|
||||
printf("device: 0x%04x, 0x%04x\n", desc.idVendor, desc.idProduct);
|
||||
|
||||
if (desc.idVendor != 0x0483)
|
||||
return 0;
|
||||
|
||||
if (desc.idProduct != 0x3748)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _stlink_usb_version(stlink_t * sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_GET_VERSION;
|
||||
buf[1] = 0x80;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}mkdir g
|
||||
|
||||
#if 1 /* DEBUG */
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < size; ++i) printf("%02x", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
void _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
D(sl, "oops! no write32 support yet ;)\n");
|
||||
}
|
||||
|
||||
void _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
D(sl, "oops! no write8 support yet ;)\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int stlink_current_mode(stlink_t * sl) {
|
||||
int mode = -1;
|
||||
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
|
||||
buf[0] = STLINK_GET_CURRENT_MODE;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mode = (int)read_uint16(buf, 0); */
|
||||
mode = (int) buf[0];
|
||||
|
||||
#if 1 /* DEBUG */
|
||||
printf("mode == 0x%x\n", mode);
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void _stlink_usb_core_id(stlink_t * sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_READCOREID;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sl->core_id = read_uint32(buf, 0);
|
||||
}
|
||||
|
||||
void _stlink_usb_status(stlink_t * sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_GETSTATUS;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* todo: stlink_core_stat */
|
||||
|
||||
// FIXME - decode into sl->core_stat
|
||||
#if 1 /* DEBUG */
|
||||
printf("status == 0x%x\n", buf[0]);
|
||||
#endif /* DEBUG */
|
||||
|
||||
}
|
||||
|
||||
void _stlink_enter_swd_mode(stlink_t * sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = 0x30; /* needed byte */
|
||||
buf[2] = STLINK_DEBUG_ENTER_JTAG;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _stlink_usb_exit_dfu_mode(stlink_t* sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DFU_COMMAND;
|
||||
buf[1] = STLINK_DFU_EXIT;
|
||||
|
||||
size = send_only(slu, buf, 16);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _stlink_usb_reset(stlink_t * sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_RESETSYS;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stlink_step(stlink_t* sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_STEPCORE;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _stlink_usb_run(stlink_t* sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_RUNCORE;
|
||||
|
||||
size = send_recv(slu, buf, 16, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _stlink_usb_exit_debug_mode(stlink_t *sl) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_EXIT;
|
||||
|
||||
size = send_only(slu, buf, 16);
|
||||
if (size == -1) {
|
||||
printf("[!] send_only\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
struct stlink_libusb * const slu = sl->backend_data;
|
||||
unsigned char* const buf = sl->q_buf;
|
||||
ssize_t size;
|
||||
|
||||
/* assume len < sizeof(sl->q_buf) */
|
||||
|
||||
memset(buf, 0, sizeof (sl->q_buf));
|
||||
buf[0] = STLINK_DEBUG_COMMAND;
|
||||
buf[1] = STLINK_DEBUG_READMEM_32BIT;
|
||||
write_uint32(buf + 2, addr);
|
||||
write_uint16(buf + 6, len);
|
||||
#if 0
|
||||
/* windows usb logs show only one byte is used for length ... */
|
||||
buf[6] = (uint8_t) len;
|
||||
#endif
|
||||
|
||||
size = send_recv(slu, buf, 0x10, buf, sizeof (sl->q_buf));
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sl->q_len = (size_t) size;
|
||||
|
||||
stlink_print_data(sl);
|
||||
}
|
||||
|
||||
|
||||
stlink_backend_t _stlink_usb_backend = {
|
||||
_stlink_usb_close,
|
||||
_stlink_usb_exit_debug_mode,
|
||||
_stlink_enter_swd_mode,
|
||||
NULL,
|
||||
_stlink_usb_exit_dfu_mode,
|
||||
_stlink_usb_core_id,
|
||||
_stlink_usb_reset,
|
||||
_stlink_usb_run,
|
||||
_stlink_usb_status,
|
||||
_stlink_usb_version,
|
||||
_stlink_usb_write_mem32,
|
||||
_stlink_usb_write_mem8
|
||||
};
|
||||
|
||||
stlink_t* stlink_open_usb(const char *dev_name, const int verbose) {
|
||||
stlink_t* sl = NULL;
|
||||
struct stlink_libusb* slu = NULL;
|
||||
|
||||
sl = malloc(sizeof (stlink_t));
|
||||
slu = malloc(sizeof (struct stlink_libusb));
|
||||
if (sl == NULL) goto on_error;
|
||||
if (slu == NULL) goto on_error;
|
||||
|
||||
sl->verbose = verbose;
|
||||
|
||||
if (slu->libusb_ctx != NULL) {
|
||||
fprintf(stderr, "reopening with an existing context? undefined behaviour!\n");
|
||||
goto on_error;
|
||||
} else {
|
||||
if (libusb_init(&(slu->libusb_ctx))) {
|
||||
fprintf(stderr, "failed to init libusb context, wrong version of libraries?\n");
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
int error = -1;
|
||||
|
||||
libusb_device** devs = NULL;
|
||||
libusb_device* dev;
|
||||
ssize_t i;
|
||||
ssize_t count;
|
||||
int config;
|
||||
|
||||
count = libusb_get_device_list(slu->libusb_ctx, &devs);
|
||||
if (count < 0) {
|
||||
printf("libusb_get_device_list\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev = devs[i];
|
||||
if (is_stlink_device(dev)) break;
|
||||
}
|
||||
if (i == count) return NULL;
|
||||
|
||||
if (libusb_open(dev, &(slu->usb_handle))) {
|
||||
printf("libusb_open()\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
if (libusb_get_configuration(slu->usb_handle, &config)) {
|
||||
/* this may fail for a previous configured device */
|
||||
printf("libusb_get_configuration()\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
if (config != 1) {
|
||||
printf("setting new configuration (%d -> 1)\n", config);
|
||||
if (libusb_set_configuration(slu->usb_handle, 1)) {
|
||||
/* this may fail for a previous configured device */
|
||||
printf("libusb_set_configuration()\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (libusb_claim_interface(slu->usb_handle, 0)) {
|
||||
printf("libusb_claim_interface()\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
slu->req_trans = libusb_alloc_transfer(0);
|
||||
if (slu->req_trans == NULL) {
|
||||
printf("libusb_alloc_transfer\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
slu->rep_trans = libusb_alloc_transfer(0);
|
||||
if (slu->rep_trans == NULL) {
|
||||
printf("libusb_alloc_transfer\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
|
||||
slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
|
||||
|
||||
/* libusb_reset_device(slu->usb_handle); */
|
||||
|
||||
/* success */
|
||||
error = 0;
|
||||
|
||||
on_libusb_error:
|
||||
if (devs != NULL) {
|
||||
libusb_free_device_list(devs, 1);
|
||||
fprintf(stderr, "freed libusb device list\n");
|
||||
}
|
||||
|
||||
if (error == -1) {
|
||||
stlink_close(sl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sl->backend = &_stlink_usb_backend;
|
||||
sl->backend_data = slu;
|
||||
/* success */
|
||||
return sl;
|
||||
|
||||
on_error:
|
||||
if (sl != NULL) free(sl);
|
||||
if (slu != NULL) free(slu);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* File: stlink-usb.h
|
||||
* Author: karl
|
||||
*
|
||||
* Created on October 1, 2011, 11:29 PM
|
||||
*/
|
||||
|
||||
#ifndef STLINK_USB_H
|
||||
#define STLINK_USB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#if defined(CONFIG_USE_LIBUSB)
|
||||
struct stlink_libusb {
|
||||
libusb_context* libusb_ctx;
|
||||
libusb_device_handle* usb_handle;
|
||||
struct libusb_transfer* req_trans;
|
||||
struct libusb_transfer* rep_trans;
|
||||
unsigned int ep_req;
|
||||
unsigned int ep_rep;
|
||||
};
|
||||
#else
|
||||
#error "it's all bad!"
|
||||
struct stlink_libusb {};
|
||||
#endif
|
||||
|
||||
|
||||
stlink_t* stlink_open_usb(const char *dev_name, const int verbose);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_USB_H */
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* File: test_main.c
|
||||
*
|
||||
* main() ripped out of old stlink-hw.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "stlink-common.h"
|
||||
|
||||
#if 0
|
||||
int main(int argc, char *argv[]) {
|
||||
// set scpi lib debug level: 0 for no debug info, 10 for lots
|
||||
const int scsi_verbose = 2;
|
||||
char *dev_name;
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
fputs(
|
||||
"\nUsage: stlink-access-test /dev/sg0, sg1, ...\n"
|
||||
"\n*** Notice: The stlink firmware violates the USB standard.\n"
|
||||
"*** If you plug-in the discovery's stlink, wait a several\n"
|
||||
"*** minutes to let the kernel driver swallow the broken device.\n"
|
||||
"*** Watch:\ntail -f /var/log/messages\n"
|
||||
"*** This command sequence can shorten the waiting time and fix some issues.\n"
|
||||
"*** Unplug the stlink and execute once as root:\n"
|
||||
"modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:lrwsro\n\n",
|
||||
stderr);
|
||||
return EXIT_FAILURE;
|
||||
case 2:
|
||||
dev_name = argv[1];
|
||||
break;
|
||||
default:
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fputs("*** stlink access test ***\n", stderr);
|
||||
DD(sl, "Using sg_lib %s : scsi_pt %s\n", sg_lib_version(),
|
||||
scsi_pt_version());
|
||||
|
||||
struct stlink *sl = stlink_force_open(dev_name, scsi_verbose);
|
||||
if (sl == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// we are in mass mode, go to swd
|
||||
stlink_enter_swd_mode(sl);
|
||||
stlink_current_mode(sl);
|
||||
stlink_core_id(sl);
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
stlink_status(sl);
|
||||
//stlink_force_debug(sl);
|
||||
stlink_reset(sl);
|
||||
stlink_status(sl);
|
||||
#if 0
|
||||
// core system control block
|
||||
stlink_read_mem32(sl, 0xe000ed00, 4);
|
||||
DD(sl, "cpu id base register: SCB_CPUID = got 0x%08x expect 0x411fc231", read_uint32(sl->q_buf, 0));
|
||||
// no MPU
|
||||
stlink_read_mem32(sl, 0xe000ed90, 4);
|
||||
DD(sl, "mpu type register: MPU_TYPER = got 0x%08x expect 0x0", read_uint32(sl->q_buf, 0));
|
||||
|
||||
stlink_read_mem32(sl, 0xe000edf0, 4);
|
||||
DD(sl, "DHCSR = 0x%08x", read_uint32(sl->q_buf, 0));
|
||||
|
||||
stlink_read_mem32(sl, 0x4001100c, 4);
|
||||
DD(sl, "GPIOC_ODR = 0x%08x", read_uint32(sl->q_buf, 0));
|
||||
#endif
|
||||
#if 0
|
||||
// happy new year 2011: let blink all the leds
|
||||
// see "RM0041 Reference manual - STM32F100xx advanced ARM-based 32-bit MCUs"
|
||||
|
||||
#define GPIOC 0x40011000 // port C
|
||||
#define GPIOC_CRH (GPIOC + 0x04) // port configuration register high
|
||||
#define GPIOC_ODR (GPIOC + 0x0c) // port output data register
|
||||
#define LED_BLUE (1<<8) // pin 8
|
||||
#define LED_GREEN (1<<9) // pin 9
|
||||
stlink_read_mem32(sl, GPIOC_CRH, 4);
|
||||
uint32_t io_conf = read_uint32(sl->q_buf, 0);
|
||||
DD(sl, "GPIOC_CRH = 0x%08x", io_conf);
|
||||
|
||||
// set: general purpose output push-pull, output mode, max speed 10 MHz.
|
||||
write_uint32(sl->q_buf, 0x44444411);
|
||||
stlink_write_mem32(sl, GPIOC_CRH, 4);
|
||||
|
||||
clear_buf(sl);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
write_uint32(sl->q_buf, LED_BLUE | LED_GREEN);
|
||||
stlink_write_mem32(sl, GPIOC_ODR, 4);
|
||||
/* stlink_read_mem32(sl, 0x4001100c, 4); */
|
||||
/* DD(sl, "GPIOC_ODR = 0x%08x", read_uint32(sl->q_buf, 0)); */
|
||||
delay(100);
|
||||
|
||||
clear_buf(sl);
|
||||
stlink_write_mem32(sl, GPIOC_ODR, 4); // PC lo
|
||||
delay(100);
|
||||
}
|
||||
write_uint32(sl->q_buf, io_conf); // set old state
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
// TODO rtfm: stlink doesn't have flash write routines
|
||||
// writing to the flash area confuses the fw for the next read access
|
||||
|
||||
//stlink_read_mem32(sl, 0, 1024*6);
|
||||
// flash 0x08000000 128kB
|
||||
fputs("++++++++++ read a flash at 0x0800 0000\n", stderr);
|
||||
stlink_read_mem32(sl, 0x08000000, 1024 * 6); //max 6kB
|
||||
clear_buf(sl);
|
||||
stlink_read_mem32(sl, 0x08000c00, 5);
|
||||
stlink_read_mem32(sl, 0x08000c00, 4);
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x08000c00, 4);
|
||||
stlink_read_mem32(sl, 0x08000c00, 256);
|
||||
stlink_read_mem32(sl, 0x08000c00, 256);
|
||||
#endif
|
||||
#if 0
|
||||
// sram 0x20000000 8kB
|
||||
fputs("\n++++++++++ read/write 8bit, sram at 0x2000 0000 ++++++++++++++++\n\n", stderr);
|
||||
clear_buf(sl);
|
||||
stlink_write_mem8(sl, 0x20000000, 16);
|
||||
|
||||
mark_buf(sl);
|
||||
stlink_write_mem8(sl, 0x20000000, 1);
|
||||
stlink_write_mem8(sl, 0x20000001, 1);
|
||||
stlink_write_mem8(sl, 0x2000000b, 3);
|
||||
stlink_read_mem32(sl, 0x20000000, 16);
|
||||
#endif
|
||||
#if 0
|
||||
// a not aligned mem32 access doesn't work indeed
|
||||
fputs("\n++++++++++ read/write 32bit, sram at 0x2000 0000 ++++++++++++++++\n\n", stderr);
|
||||
clear_buf(sl);
|
||||
stlink_write_mem8(sl, 0x20000000, 32);
|
||||
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x20000000, 1);
|
||||
stlink_read_mem32(sl, 0x20000000, 16);
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x20000001, 1);
|
||||
stlink_read_mem32(sl, 0x20000000, 16);
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x2000000b, 3);
|
||||
stlink_read_mem32(sl, 0x20000000, 16);
|
||||
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x20000000, 17);
|
||||
stlink_read_mem32(sl, 0x20000000, 32);
|
||||
#endif
|
||||
#if 0
|
||||
// sram 0x20000000 8kB
|
||||
fputs("++++++++++ read/write 32bit, sram at 0x2000 0000 ++++++++++++\n", stderr);
|
||||
mark_buf(sl);
|
||||
stlink_write_mem8(sl, 0x20000000, 64);
|
||||
stlink_read_mem32(sl, 0x20000000, 64);
|
||||
|
||||
mark_buf(sl);
|
||||
stlink_write_mem32(sl, 0x20000000, 1024 * 8); //8kB
|
||||
stlink_read_mem32(sl, 0x20000000, 1024 * 6);
|
||||
stlink_read_mem32(sl, 0x20000000 + 1024 * 6, 1024 * 2);
|
||||
#endif
|
||||
#if 0
|
||||
stlink_read_all_regs(sl);
|
||||
stlink_step(sl);
|
||||
fputs("++++++++++ write r0 = 0x12345678\n", stderr);
|
||||
stlink_write_reg(sl, 0x12345678, 0);
|
||||
stlink_read_reg(sl, 0);
|
||||
stlink_read_all_regs(sl);
|
||||
#endif
|
||||
#if 0
|
||||
stlink_run(sl);
|
||||
stlink_status(sl);
|
||||
|
||||
stlink_force_debug(sl);
|
||||
stlink_status(sl);
|
||||
#endif
|
||||
#if 1 /* read the system bootloader */
|
||||
fputs("\n++++++++++ reading bootloader ++++++++++++++++\n\n", stderr);
|
||||
stlink_fread(sl, "/tmp/barfoo", sl->sys_base, sl->sys_size);
|
||||
#endif
|
||||
#if 0 /* read the flash memory */
|
||||
fputs("\n+++++++ read flash memory\n\n", stderr);
|
||||
/* mark_buf(sl); */
|
||||
stlink_read_mem32(sl, 0x08000000, 4);
|
||||
#endif
|
||||
#if 0 /* flash programming */
|
||||
fputs("\n+++++++ program flash memory\n\n", stderr);
|
||||
stlink_fwrite_flash(sl, "/tmp/foobar", 0x08000000);
|
||||
#endif
|
||||
#if 0 /* check file contents */
|
||||
fputs("\n+++++++ check flash memory\n\n", stderr);
|
||||
{
|
||||
const int res = stlink_fcheck_flash(sl, "/tmp/foobar", 0x08000000);
|
||||
printf("_____ stlink_fcheck_flash() == %d\n", res);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
fputs("\n+++++++ sram write and execute\n\n", stderr);
|
||||
stlink_fwrite_sram(sl, "/tmp/foobar", sl->sram_base);
|
||||
stlink_run_at(sl, sl->sram_base);
|
||||
#endif
|
||||
|
||||
stlink_run(sl);
|
||||
stlink_status(sl);
|
||||
//----------------------------------------------------------------------
|
||||
// back to mass mode, just in case ...
|
||||
stlink_exit_debug_mode(sl);
|
||||
stlink_current_mode(sl);
|
||||
stlink_close(sl);
|
||||
|
||||
//fflush(stderr); fflush(stdout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,62 @@
|
|||
#include <stdio.h>
|
||||
#include "stlink-common.h"
|
||||
|
||||
|
||||
int main(int ac, char** av) {
|
||||
stlink_t* sl;
|
||||
|
||||
sl = stlink_open_usb(NULL, 10);
|
||||
if (sl != NULL) {
|
||||
printf("-- version\n");
|
||||
stlink_version(sl);
|
||||
|
||||
if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
|
||||
printf("-- exit_dfu_mode\n");
|
||||
stlink_exit_dfu_mode(sl);
|
||||
}
|
||||
|
||||
printf("-- enter_swd_mode\n");
|
||||
stlink_enter_swd_mode(sl);
|
||||
|
||||
printf("-- current_mode\n");
|
||||
stlink_current_mode(sl);
|
||||
|
||||
/* printf("-- core_id\n"); */
|
||||
/* stlink_core_id(sl); */
|
||||
|
||||
printf("-- read_sram\n");
|
||||
static const uint32_t sram_base = 0x8000000;
|
||||
uint32_t off;
|
||||
for (off = 0; off < 16; off += 4)
|
||||
stlink_read_mem32(sl, sram_base + off, 4);
|
||||
|
||||
printf("-- read_mem, cpuid\n");
|
||||
stlink_read_mem32(sl, 0xe000e008, 4);
|
||||
/* stlink_read_mem32(sl, 0xe000ed90, 4); */
|
||||
/* stlink_read_mem32(sl, 0xe000edf0, 4); */
|
||||
/* stlink_read_mem32(sl, 0x4001100c, 4); */
|
||||
|
||||
printf("-- status\n");
|
||||
stlink_status(sl);
|
||||
|
||||
printf("-- reset\n");
|
||||
stlink_reset(sl);
|
||||
|
||||
printf("-- status\n");
|
||||
stlink_status(sl);
|
||||
|
||||
printf("-- step\n");
|
||||
stlink_step(sl);
|
||||
getchar();
|
||||
|
||||
printf("-- run\n");
|
||||
stlink_run(sl);
|
||||
|
||||
printf("-- exit_debug_mode\n");
|
||||
stlink_exit_debug_mode(sl);
|
||||
|
||||
stlink_close(sl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Ładowanie…
Reference in New Issue