From 4b00cb1d688791abe509ea18abfe641422ef83c9 Mon Sep 17 00:00:00 2001 From: David Welch Date: Tue, 8 Mar 2011 21:43:16 -0500 Subject: [PATCH] Thanks to Martin Capitanio and the linux code at http://capitanio.org/mlink/index.html Was able to take my new stm32 value line discovery and load a simple program into sram and run it. So far all it does is blink the green and blue leds. --- Makefile | 32 + blinker.c | 34 + memmap | 11 + stlink-access-test-04.tgz | Bin 0 -> 11500 bytes stlink-access-test/AUTHORS | 3 + stlink-access-test/LICENSE | 27 + stlink-access-test/README | 5 + stlink-access-test/build/Makefile | 27 + stlink-access-test/src/stlink-access-test.c | 1205 +++++++++++++++++++ vectors.s | 54 + 10 files changed, 1398 insertions(+) create mode 100644 Makefile create mode 100644 blinker.c create mode 100644 memmap create mode 100644 stlink-access-test-04.tgz create mode 100644 stlink-access-test/AUTHORS create mode 100644 stlink-access-test/LICENSE create mode 100644 stlink-access-test/README create mode 100644 stlink-access-test/build/Makefile create mode 100644 stlink-access-test/src/stlink-access-test.c create mode 100644 vectors.s diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7a611da --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ + +ARMGNU = arm-none-linux-gnueabi + +ARCH = -mcpu=cortex-m3 +#ARCH = +AOPS = --warn --fatal-warnings -mthumb $(ARCH) +COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb $(ARCH) + + +all : blinker.bin + +clean : + rm -f *.o + rm -f *.elf + rm -f *.list + rm -f *.bin + +blinker.elf : blinker.o vectors.o memmap + $(ARMGNU)-ld -T memmap vectors.o blinker.o -o blinker.elf + $(ARMGNU)-objdump -D blinker.elf > blinker.list + +blinker.o : blinker.c + $(ARMGNU)-gcc $(COPS) -c blinker.c -o blinker.o + +vectors.o : vectors.s + $(ARMGNU)-as $(AOPS) vectors.s -o vectors.o + + +blinker.bin : blinker.elf + $(ARMGNU)-objcopy blinker.elf -O binary blinker.bin + + diff --git a/blinker.c b/blinker.c new file mode 100644 index 0000000..ad4baae --- /dev/null +++ b/blinker.c @@ -0,0 +1,34 @@ + +void PUT32 ( unsigned int, unsigned int ); +unsigned int GET32 ( unsigned int ); + +#define GPIOCBASE 0x40011000 + +int notmain ( void ) +{ + + volatile unsigned int ra; + unsigned int rb; + unsigned int rc; + + //Blue LED on PORT C bit 8 + //Green LED on PORT C bit 9 + + //output push-pull b0001 + ra=GET32(GPIOCBASE+0x04); + ra&=(~(0xF<<16)); + ra|=0x1<<16; + PUT32(GPIOCBASE+0x04,ra); + + rb=GET32(GPIOCBASE+0x0C); + rc=rb|(3<<8); + rb&=(~(3<<8)); + while(1) + { + PUT32(GPIOCBASE+0x0C,rb); + for(ra=0;ra<1000000;ra++) continue; + PUT32(GPIOCBASE+0x0C,rc); + for(ra=0;ra<1000000;ra++) continue; + } + return(0); +} diff --git a/memmap b/memmap new file mode 100644 index 0000000..9962e8b --- /dev/null +++ b/memmap @@ -0,0 +1,11 @@ + +MEMORY +{ + ram : ORIGIN = 0x20000000, LENGTH = 0x10000 +} + +SECTIONS +{ + .text : { *(.text*) } > ram +} + diff --git a/stlink-access-test-04.tgz b/stlink-access-test-04.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2300721037f7a4546489bdb1f5125efeecc05f8e GIT binary patch literal 11500 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 O*!2YN66hZg(0>5*-eKGT literal 0 HcmV?d00001 diff --git a/stlink-access-test/AUTHORS b/stlink-access-test/AUTHORS new file mode 100644 index 0000000..b069adf --- /dev/null +++ b/stlink-access-test/AUTHORS @@ -0,0 +1,3 @@ +Martin Capitanio +Spencer Oliver +Lementec Fabien diff --git a/stlink-access-test/LICENSE b/stlink-access-test/LICENSE new file mode 100644 index 0000000..37b124e --- /dev/null +++ b/stlink-access-test/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The "Capt'ns Missing Link" Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Martin Capitanio nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/stlink-access-test/README b/stlink-access-test/README new file mode 100644 index 0000000..9861697 --- /dev/null +++ b/stlink-access-test/README @@ -0,0 +1,5 @@ +cd build +make + +edit Makefile +make run diff --git a/stlink-access-test/build/Makefile b/stlink-access-test/build/Makefile new file mode 100644 index 0000000..34c25c6 --- /dev/null +++ b/stlink-access-test/build/Makefile @@ -0,0 +1,27 @@ +PRG := stlink-access-test +DEV := /dev/sg2 + +all: $(PRG) + +LIBS := \ + -lsgutils2 + +OBJS += \ + stlink-access-test.o + +$(PRG): $(OBJS) + @echo 'Invoking: GCC C Linker' + gcc -o$(PRG) $(OBJS) $(LIBS) + +%.o: ../src/%.c + @echo 'Building file: $<' + gcc -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu99 -MMD -MP \ + -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)"\ + -o"$@" "$<" + +clean: + @rm -vf *.d *.o $(PRG) + +run: all + cp $(PRG) /tmp/ + sudo /tmp/$(PRG) $(DEV) diff --git a/stlink-access-test/src/stlink-access-test.c b/stlink-access-test/src/stlink-access-test.c new file mode 100644 index 0000000..9442713 --- /dev/null +++ b/stlink-access-test/src/stlink-access-test.c @@ -0,0 +1,1205 @@ +/* + Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. + + A linux stlink access demo. The purpose of this file is to mitigate the usual + "reinventing the wheel" force by incompatible licenses and give you an idea, + how to access the stlink device. That doesn't mean you should be a free-loader + and not contribute your improvements to this code. + + Author: Martin Capitanio + The stlink related constants kindly provided by Oliver Spencer (OpenOCD) + for use in a GPL compatible license. + + Notes: + gcc -O0 -g3 -Wall -c -std=gnu99 -o stlink-access-test.o stlink-access-test.c + gcc -o stlink-access-test stlink-access-test.o -lsgutils2 + + Code format ~ TAB = 8, K&R, linux kernel source, golang oriented + Tested compatibility: linux, gcc >= 4.3.3 + + The communication is based on standard USB mass storage device + BOT (Bulk Only Transfer) + - Endpoint 1: BULK_IN, 64 bytes max + - Endpoint 2: BULK_OUT, 64 bytes max + + All CBW transfers are ordered with the LSB (byte 0) first (little endian). + Any command must be answered before sending the next command. + Each USB transfer must complete in less than 1s. + + SB Device Class Definition for Mass Storage Devices: + www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf + + dt - Data Transfer (IN/OUT) + CBW - Command Block Wrapper + CSW - Command Status Wrapper + RFU - Reserved for Future Use + scsi_pt - SCSI pass-through + sg - SCSI generic + + * usb-storage.quirks + http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt + Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product + ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding + to a common usb-storage quirk flag as follows: + + a = SANE_SENSE (collect more than 18 bytes of sense data); + b = BAD_SENSE (don't collect more than 18 bytes of sense data); + c = FIX_CAPACITY (decrease the reported device capacity by one sector); + h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd); + i = IGNORE_DEVICE (don't bind to this device); + l = NOT_LOCKABLE (don't try to lock and unlock ejectable media); + m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time); + o = CAPACITY_OK (accept the capacity reported by the device); + r = IGNORE_RESIDUE (the device reports bogus residue values); + s = SINGLE_LUN (the device has only one Logical Unit); + w = NO_WP_DETECT (don't test whether the medium is write-protected). + + Example: quirks=0419:aaf5:rl,0421:0433:rc + http://permalink.gmane.org/gmane.linux.usb.general/35053 + + modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:l + + Equivalently, you can add a line saying + + options usb-storage quirks=483:3744:l + + to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..." + part to an existing options line for usb-storage). + */ + +#define __USE_GNU +#include +#include +#include + +// sgutils2 (apt-get install libsgutils2-dev) +#include +#include + +// 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_RUNNINIG 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; + +struct stlink { + 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; +}; + +static void D(struct stlink *sl, char *txt) { + if (sl->verbose > 1) + fputs(txt, stderr); +} + +// Suspends execution of the calling process for +// (at least) ms milliseconds. +static void delay(int ms) { + fprintf(stderr, "*** wait %d ms\n", ms); + usleep(1000 * ms); +} + +// 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; +} + +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; +} + +static void clear_cdb(struct stlink *sl) { + for (int i = 0; i < sizeof(sl->cdb_cmd_blk); i++) + sl->cdb_cmd_blk[i] = 0; + // set default + sl->cdb_cmd_blk[0] = STLINK_DEBUG_COMMAND; + sl->q_data_dir = Q_DATA_IN; +} + +// E.g. make the valgrind happy. +static void clear_buf(struct stlink *sl) { + fprintf(stderr, "*** clear_buf ***\n"); + for (int i = 0; i < sizeof(sl->q_buf); i++) + sl->q_buf[i] = 0; + +} + +static struct stlink* stlink_open(const char *dev_name, const int verbose) { + fprintf(stderr, "\n*** stlink_open [%s] ***\n", dev_name); + int sg_fd = scsi_pt_open_device(dev_name, RDWR, verbose); + if (sg_fd < 0) { + fprintf(stderr, "error opening device: %s: %s\n", dev_name, + safe_strerror(-sg_fd)); + return NULL; + } + + struct stlink *sl = malloc(sizeof(struct stlink)); + if (sl == NULL) { + fprintf(stderr, "struct stlink: out of memory\n"); + return NULL; + } + + sl->sg_fd = sg_fd; + sl->verbose = verbose; + sl->core_stat = STLINK_CORE_STAT_UNKNOWN; + sl->core_id = 0; + sl->q_addr = 0; + clear_buf(sl); + return sl; +} + +// close the device, free the allocated memory +void stlink_close(struct stlink *sl) { + D(sl, "\n*** stlink_close ***\n"); + if (sl) { + scsi_pt_close_device(sl->sg_fd); + free(sl); + } +} + +//TODO rewrite/cleanup, save the error in sl +static void stlink_confirm_inq(struct stlink *sl, struct sg_pt_base *ptvp) { + const int e = sl->do_scsi_pt_err; + if (e < 0) { + fprintf(stderr, "scsi_pt error: pass through os error: %s\n", + safe_strerror(-e)); + return; + } else if (e == SCSI_PT_DO_BAD_PARAMS) { + fprintf(stderr, "scsi_pt error: bad pass through setup\n"); + return; + } else if (e == SCSI_PT_DO_TIMEOUT) { + fprintf(stderr, " pass through timeout\n"); + return; + } + const int duration = get_scsi_pt_duration_ms(ptvp); + if ((sl->verbose > 1) && (duration >= 0)) + fprintf(stderr, " duration=%d ms\n", duration); + + // XXX stlink fw sends broken residue, so ignore it and use the known q_len + // "usb-storage quirks=483:3744:r" + // forces residue to be ignored and calculated, but this causes aboard if + // data_len = 0 and by some other data_len values. + + const int resid = get_scsi_pt_resid(ptvp); + const int dsize = sl->q_len - resid; + + const int cat = get_scsi_pt_result_category(ptvp); + char buf[512]; + unsigned int slen; + + switch (cat) { + case SCSI_PT_RESULT_GOOD: + if (sl->verbose && (resid > 0)) + fprintf(stderr, " notice: requested %d bytes but " + "got %d bytes, ignore [broken] residue = %d\n", + sl->q_len, dsize, resid); + break; + case SCSI_PT_RESULT_STATUS: + if (sl->verbose) { + sg_get_scsi_status_str( + get_scsi_pt_status_response(ptvp), sizeof(buf), + buf); + fprintf(stderr, " scsi status: %s\n", buf); + } + return; + case SCSI_PT_RESULT_SENSE: + slen = get_scsi_pt_sense_len(ptvp); + if (sl->verbose) { + sg_get_sense_str("", sl->sense_buf, slen, (sl->verbose + > 1), sizeof(buf), buf); + fprintf(stderr, "%s", buf); + } + if (sl->verbose && (resid > 0)) { + if ((sl->verbose) || (sl->q_len > 0)) + fprintf(stderr, " requested %d bytes but " + "got %d bytes\n", sl->q_len, dsize); + } + return; + case SCSI_PT_RESULT_TRANSPORT_ERR: + if (sl->verbose) { + get_scsi_pt_transport_err_str(ptvp, sizeof(buf), buf); + // http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html + // These codes potentially come from the firmware on a host adapter + // or from one of several hosts that an adapter driver controls. + // The 'host_status' field has the following values: + // [0x07] Internal error detected in the host adapter. + // This may not be fatal (and the command may have succeeded). + fprintf(stderr, " transport: %s", buf); + } + return; + case SCSI_PT_RESULT_OS_ERR: + if (sl->verbose) { + get_scsi_pt_os_err_str(ptvp, sizeof(buf), buf); + fprintf(stderr, " os: %s", buf); + } + return; + default: + fprintf(stderr, " unknown pass through result " + "category (%d)\n", cat); + } +} + +static void stlink_q(struct stlink* sl) { + fputs("CDB[", stderr); + for (int i = 0; i < CDB_SL; i++) + fprintf(stderr, " 0x%02x", (unsigned int) sl->cdb_cmd_blk[i]); + fputs("]\n", stderr); + + // Get control command descriptor of scsi structure, + // (one object per command!!) + struct sg_pt_base *ptvp = construct_scsi_pt_obj(); + if (NULL == ptvp) { + fprintf(stderr, "construct_scsi_pt_obj: out of memory\n"); + return; + } + + set_scsi_pt_cdb(ptvp, sl->cdb_cmd_blk, sizeof(sl->cdb_cmd_blk)); + + // set buffer for sense (error information) data + set_scsi_pt_sense(ptvp, sl->sense_buf, sizeof(sl->sense_buf)); + + // Set a buffer to be used for data transferred from device + if (sl->q_data_dir == Q_DATA_IN) { + //clear_buf(sl); + set_scsi_pt_data_in(ptvp, sl->q_buf, sl->q_len); + } else { + set_scsi_pt_data_out(ptvp, sl->q_buf, sl->q_len); + } + // Executes SCSI command (or at least forwards it to lower layers). + sl->do_scsi_pt_err = do_scsi_pt(ptvp, sl->sg_fd, SG_TIMEOUT_SEC, + sl->verbose); + + // check for scsi errors + stlink_confirm_inq(sl, ptvp); + // TODO recycle: clear_scsi_pt_obj(struct sg_pt_base * objp); + destruct_scsi_pt_obj(ptvp); +} + +static void stlink_print_data(struct stlink *sl) { + if (sl->q_len <= 0 || sl->verbose < 2) + return; + if (sl->verbose > 2) + fprintf(stderr, "data_len = %d 0x%x\n", sl->q_len, sl->q_len); + + for (uint32_t i = 0; i < sl->q_len; i++) { + if (i % 16 == 0) { + if (sl->q_data_dir == Q_DATA_OUT) + fprintf(stderr, "\n<- 0x%08x ", sl->q_addr + i); + else + fprintf(stderr, "\n-> 0x%08x ", sl->q_addr + i); + } + fprintf(stderr, " %02x", (unsigned int) sl->q_buf[i]); + } + fputs("\n\n", stderr); +} + +// TODO thinking, cleanup +static void stlink_parse_version(struct stlink *sl) { + sl->st_vid = 0; + sl->stlink_pid = 0; + if (sl->q_len <= 0) { + fprintf(stderr, "Error: could not parse the stlink version"); + return; + } + stlink_print_data(sl); + 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 + + sl->stlink_v = (b0 & 0xf0) >> 4; + sl->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6); + sl->swim_v = b1 & 0x3f; + sl->st_vid = (b3 << 8) | b2; + sl->stlink_pid = (b5 << 8) | b4; + + if (sl->verbose < 2) + return; + + fprintf(stderr, "st vid = 0x%04x (expect 0x%04x)\n", + sl->st_vid, USB_ST_VID); + fprintf(stderr, "stlink pid = 0x%04x (expect 0x%04x)\n", + sl->stlink_pid, USB_STLINK_PID); + fprintf(stderr, "stlink version = 0x%x\n", sl->stlink_v); + fprintf(stderr, "jtag version = 0x%x\n", sl->jtag_v); + fprintf(stderr, "swim version = 0x%x\n", sl->swim_v); + if (sl->jtag_v == 0) + fprintf(stderr, + " notice: the firmware doesn't support a jtag/swd interface\n"); + if (sl->swim_v == 0) + fprintf(stderr, + " notice: the firmware doesn't support a swim interface\n"); + +} + +static int stlink_mode(struct stlink *sl) { + if (sl->q_len <= 0) + return STLINK_DEV_UNKNOWN_MODE; + + stlink_print_data(sl); + + switch (sl->q_buf[0]) { + case STLINK_DEV_DFU_MODE: + fprintf(stderr, "stlink mode: dfu\n"); + return STLINK_DEV_DFU_MODE; + case STLINK_DEV_DEBUG_MODE: + fprintf(stderr, "stlink mode: debug (jtag or swd)\n"); + return STLINK_DEV_DEBUG_MODE; + case STLINK_DEV_MASS_MODE: + fprintf(stderr, "stlink mode: mass\n"); + return STLINK_DEV_MASS_MODE; + } + return STLINK_DEV_UNKNOWN_MODE; +} + +static void stlink_stat(struct stlink *sl, char *txt) { + if (sl->q_len <= 0) + return; + + stlink_print_data(sl); + + switch (sl->q_buf[0]) { + case STLINK_OK: + fprintf(stderr, " %s: ok\n", txt); + return; + case STLINK_FALSE: + fprintf(stderr, " %s: false\n", txt); + return; + default: + fprintf(stderr, " %s: unknown\n", txt); + } +} + +static void stlink_core_stat(struct stlink *sl) { + if (sl->q_len <= 0) + return; + + stlink_print_data(sl); + + switch (sl->q_buf[0]) { + case STLINK_CORE_RUNNINIG: + sl->core_stat = STLINK_CORE_RUNNINIG; + fprintf(stderr, " core status: running\n"); + return; + case STLINK_CORE_HALTED: + sl->core_stat = STLINK_CORE_HALTED; + fprintf(stderr, " core status: halted\n"); + return; + default: + sl->core_stat = STLINK_CORE_STAT_UNKNOWN; + fprintf(stderr, " core status: unknown\n"); + } +} + +void stlink_version(struct stlink *sl) { + D(sl, "\n*** stlink_version ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[0] = STLINK_GET_VERSION; + sl->q_len = 6; + sl->q_addr = 0; + stlink_q(sl); + stlink_parse_version(sl); +} + +// Get stlink mode: +// STLINK_DEV_DFU_MODE || STLINK_DEV_MASS_MODE || STLINK_DEV_DEBUG_MODE +// usb dfu || usb mass || jtag or swd +int stlink_current_mode(struct stlink *sl) { + D(sl, "\n*** stlink_current_mode ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[0] = STLINK_GET_CURRENT_MODE; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + return stlink_mode(sl); +} + +// Exit the mass mode and enter the swd debug mode. +void stlink_enter_swd_mode(struct stlink *sl) { + D(sl, "\n*** stlink_enter_swd_mode ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_ENTER; + sl->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_SWD; + sl->q_len = 0; // >0 -> aboard + stlink_q(sl); +} + +// Exit the mass mode and enter the jtag debug mode. +// (jtag is disabled in the discovery's stlink firmware) +void stlink_enter_jtag_mode(struct stlink *sl) { + D(sl, "\n*** stlink_enter_jtag_mode ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_ENTER; + sl->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG; + sl->q_len = 0; + stlink_q(sl); +} + +// Exit the jtag or swd mode and enter the mass mode. +void stlink_exit_debug_mode(struct stlink *sl) { + D(sl, "\n*** stlink_exit_debug_mode ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_EXIT; + sl->q_len = 0; // >0 -> aboard + stlink_q(sl); +} + +// XXX kernel driver performs reset, the device temporally disappears +static void stlink_exit_dfu_mode(struct stlink *sl) { + D(sl, "\n*** stlink_exit_dfu_mode ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[0] = STLINK_DFU_COMMAND; + sl->cdb_cmd_blk[1] = STLINK_DFU_EXIT; + sl->q_len = 0; // ?? + stlink_q(sl); + /* + [135121.844564] sd 19:0:0:0: [sdb] Unhandled error code + [135121.844569] sd 19:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK + [135121.844574] sd 19:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 10 00 00 00 08 00 + [135121.844584] end_request: I/O error, dev sdb, sector 4096 + [135121.844590] Buffer I/O error on device sdb, logical block 512 + [135130.122567] usb 6-1: reset full speed USB device using uhci_hcd and address 7 + [135130.274551] usb 6-1: device firmware changed + [135130.274618] usb 6-1: USB disconnect, address 7 + [135130.275186] VFS: busy inodes on changed media or resized disk sdb + [135130.275424] VFS: busy inodes on changed media or resized disk sdb + [135130.286758] VFS: busy inodes on changed media or resized disk sdb + [135130.292796] VFS: busy inodes on changed media or resized disk sdb + [135130.301481] VFS: busy inodes on changed media or resized disk sdb + [135130.304316] VFS: busy inodes on changed media or resized disk sdb + [135130.431113] usb 6-1: new full speed USB device using uhci_hcd and address 8 + [135130.629444] usb-storage 6-1:1.0: Quirks match for vid 0483 pid 3744: 102a1 + [135130.629492] scsi20 : usb-storage 6-1:1.0 + [135131.625600] scsi 20:0:0:0: Direct-Access STM32 PQ: 0 ANSI: 0 + [135131.627010] sd 20:0:0:0: Attached scsi generic sg2 type 0 + [135131.633603] sd 20:0:0:0: [sdb] 64000 512-byte logical blocks: (32.7 MB/31.2 MiB) + [135131.633613] sd 20:0:0:0: [sdb] Assuming Write Enabled + [135131.633620] sd 20:0:0:0: [sdb] Assuming drive cache: write through + [135131.640584] sd 20:0:0:0: [sdb] Assuming Write Enabled + [135131.640592] sd 20:0:0:0: [sdb] Assuming drive cache: write through + [135131.640609] sdb: + [135131.652634] sd 20:0:0:0: [sdb] Assuming Write Enabled + [135131.652639] sd 20:0:0:0: [sdb] Assuming drive cache: write through + [135131.652645] sd 20:0:0:0: [sdb] Attached SCSI removable disk + [135131.671536] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE + [135131.671548] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current] + [135131.671553] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range + [135131.671560] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00 + [135131.671570] end_request: I/O error, dev sdb, sector 63872 + [135131.671575] Buffer I/O error on device sdb, logical block 7984 + [135131.678527] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE + [135131.678532] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current] + [135131.678537] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range + [135131.678542] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00 + [135131.678551] end_request: I/O error, dev sdb, sector 63872 + ... + [135131.853565] end_request: I/O error, dev sdb, sector 4096 + */ +} + +static void stlink_core_id(struct stlink *sl) { + D(sl, "\n*** stlink_core_id ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_READCOREID; + sl->q_len = 4; + sl->q_addr = 0; + stlink_q(sl); + sl->core_id = read_uint32(sl->q_buf, 0); + if (sl->verbose < 2) + return; + stlink_print_data(sl); + fprintf(stderr, "core_id = 0x%08x\n", sl->core_id); +} + +// Arm-core reset -> halted state. +void stlink_reset(struct stlink *sl) { + D(sl, "\n*** stlink_reset ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_RESETSYS; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_stat(sl, "core reset"); +} + +// Arm-core status: halted or running. +void stlink_status(struct stlink *sl) { + D(sl, "\n*** stlink_status ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_GETSTATUS; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_core_stat(sl); +} + +// Force the core into the debug mode -> halted state. +void stlink_force_debug(struct stlink *sl) { + D(sl, "\n*** stlink_force_debug ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_FORCEDEBUG; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_stat(sl, "force debug"); +} + +// Read all arm-core registers. +void stlink_read_all_regs(struct stlink *sl) { + D(sl, "\n*** stlink_read_all_regs ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_READALLREGS; + sl->q_len = 84; + sl->q_addr = 0; + stlink_q(sl); + stlink_print_data(sl); + + // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83 + // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 + for (int i = 0; i < 16; i++) { + sl->reg.r[i] = read_uint32(sl->q_buf, 4 * i); + if (sl->verbose > 1) + fprintf(stderr, "r%2d = 0x%08x\n", i, sl->reg.r[i]); + } + sl->reg.xpsr = read_uint32(sl->q_buf, 64); + sl->reg.main_sp = read_uint32(sl->q_buf, 68); + sl->reg.process_sp = read_uint32(sl->q_buf, 72); + sl->reg.rw = read_uint32(sl->q_buf, 76); + sl->reg.rw2 = read_uint32(sl->q_buf, 80); + if (sl->verbose < 2) + return; + + fprintf(stderr, "xpsr = 0x%08x\n", sl->reg.xpsr); + fprintf(stderr, "main_sp = 0x%08x\n", sl->reg.main_sp); + fprintf(stderr, "process_sp = 0x%08x\n", sl->reg.process_sp); + fprintf(stderr, "rw = 0x%08x\n", sl->reg.rw); + fprintf(stderr, "rw2 = 0x%08x\n", sl->reg.rw2); +} + +// Read an arm-core register, the index must be in the range 0..20. +// 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 +// r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 +void stlink_read_reg(struct stlink *sl, int r_idx) { + D(sl, "\n*** stlink_read_reg"); + fprintf(stderr, " (%d) ***\n", r_idx); + + if (r_idx > 20 || r_idx < 0) { + fprintf(stderr, "Error: register index must be in [0..20]\n"); + return; + } + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_READREG; + sl->cdb_cmd_blk[2] = r_idx; + sl->q_len = 4; + sl->q_addr = 0; + stlink_q(sl); + // 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 + // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83 + // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 + stlink_print_data(sl); + + uint32_t r = read_uint32(sl->q_buf, 0); + fprintf(stderr, "r_idx (%2d) = 0x%08x\n", r_idx, r); + + switch (r_idx) { + case 16: + sl->reg.xpsr = r; + break; + case 17: + sl->reg.main_sp = r; + break; + case 18: + sl->reg.process_sp = r; + break; + case 19: + sl->reg.rw = r; //XXX ?(primask, basemask etc.) + break; + case 20: + sl->reg.rw2 = r; //XXX ?(primask, basemask etc.) + break; + default: + sl->reg.r[r_idx] = r; + } +} + +// Write an arm-core register. Index: +// 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 +// r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 +void stlink_write_reg(struct stlink *sl, uint32_t reg, int idx) { + D(sl, "\n*** stlink_write_reg ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEREG; + // 2: reg index + // 3-6: reg content + sl->cdb_cmd_blk[2] = idx; + write_uint32(sl->cdb_cmd_blk + 3, reg); + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_stat(sl, "write reg"); +} + +// Write a register of the debug module of the core. +// XXX ?(atomic writes) +// TODO test +void stlink_write_dreg(struct stlink *sl, uint32_t reg, uint32_t addr) { + D(sl, "\n*** stlink_write_dreg ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEDEBUGREG; + // 2-5: address of reg of the debug module + // 6-9: reg content + write_uint32(sl->cdb_cmd_blk + 2, addr); + write_uint32(sl->cdb_cmd_blk + 6, reg); + sl->q_len = 2; + sl->q_addr = addr; + stlink_q(sl); + stlink_stat(sl, "write debug reg"); +} + +// Force the core exit the debug mode. +void stlink_run(struct stlink *sl) { + D(sl, "\n*** stlink_run ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_RUNCORE; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_stat(sl, "run core"); +} + +// Step the arm-core. +void stlink_step(struct stlink *sl) { + D(sl, "\n*** stlink_step ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_STEPCORE; + sl->q_len = 2; + sl->q_addr = 0; + stlink_q(sl); + stlink_stat(sl, "step core"); +} + +// TODO test +// see Cortex-M3 Technical Reference Manual +void stlink_set_hw_bp(struct stlink *sl, int fp_nr, uint32_t addr, int fp) { + D(sl, "\n*** stlink_set_hw_bp ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_SETFP; + // 2:The number of the flash patch used to set the breakpoint + // 3-6: Address of the breakpoint (LSB) + // 7: FP_ALL (0x02) / FP_UPPER (0x01) / FP_LOWER (0x00) + sl->q_buf[2] = fp_nr; + write_uint32(sl->q_buf, addr); + sl->q_buf[7] = fp; + + sl->q_len = 2; + stlink_q(sl); + stlink_stat(sl, "set flash breakpoint"); +} + +// TODO test +void stlink_clr_hw_bp(struct stlink *sl, int fp_nr) { + D(sl, "\n*** stlink_clr_hw_bp ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_CLEARFP; + sl->cdb_cmd_blk[2] = fp_nr; + + sl->q_len = 2; + stlink_q(sl); + stlink_stat(sl, "clear flash breakpoint"); +} + +// Read a "len" bytes to the sl->q_buf from the memory, max 6kB (6144 bytes) +void stlink_read_mem32(struct stlink *sl, uint32_t addr, uint16_t len) { + D(sl, "\n*** stlink_read_mem32 ***\n"); + if (len % 4 != 0) { // !!! never ever: fw gives just wrong values + fprintf( + stderr, + "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n", + len % 4); + return; + } + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_READMEM_32BIT; + // 2-5: addr + // 6-7: len + write_uint32(sl->cdb_cmd_blk + 2, addr); + write_uint16(sl->cdb_cmd_blk + 6, len); + + // data_in 0-0x40-len + // !!! len _and_ q_len must be max 6k, + // i.e. >1024 * 6 = 6144 -> aboard) + // !!! if len < q_len: 64*k, 1024*n, n=1..5 -> aboard + // (broken residue issue) + sl->q_len = len; + sl->q_addr = addr; + stlink_q(sl); + stlink_print_data(sl); +} + +// Write a "len" bytes from the sl->q_buf to the memory, max 64 Bytes. +void stlink_write_mem8(struct stlink *sl, uint32_t addr, uint16_t len) { + D(sl, "\n*** stlink_write_mem8 ***\n"); + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_8BIT; + // 2-5: addr + // 6-7: len (>0x40 (64) -> aboard) + write_uint32(sl->cdb_cmd_blk + 2, addr); + write_uint16(sl->cdb_cmd_blk + 6, len); + + // data_out 0-len + sl->q_len = len; + sl->q_addr = addr; + sl->q_data_dir = Q_DATA_OUT; + stlink_q(sl); + stlink_print_data(sl); +} + +// Write a "len" bytes from the sl->q_buf to the memory, max Q_BUF_LEN bytes. +void stlink_write_mem32(struct stlink *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; + } + clear_cdb(sl); + sl->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_32BIT; + // 2-5: addr + // 6-7: len "unlimited" + write_uint32(sl->cdb_cmd_blk + 2, addr); + write_uint16(sl->cdb_cmd_blk + 6, len); + + // data_out 0-0x40-...-len + sl->q_len = len; + sl->q_addr = addr; + sl->q_data_dir = Q_DATA_OUT; + stlink_q(sl); + stlink_print_data(sl); +} + +// 1) open a sg device, switch the stlink from dfu to mass mode +// 2) wait 5s until the kernel driver stops reseting the broken device +// 3) reopen the device +// 4) the device driver is now ready for a switch to jtag/swd mode +// TODO thinking, better error handling, wait until the kernel driver stops reseting the plugged-in device +struct stlink* stlink_force_open(const char *dev_name, const int verbose) { + struct stlink *sl = stlink_open(dev_name, verbose); + if (sl == NULL) { + fputs("Error: could not open stlink device\n", stderr); + return NULL; + } + stlink_version(sl); + if (sl->st_vid != USB_ST_VID || sl->stlink_pid != USB_STLINK_PID) { + fprintf(stderr, "Error: the device %s is not a stlink\n", + dev_name); + fprintf(stderr, " VID: got %04x expect %04x \n", + sl->st_vid, USB_ST_VID); + fprintf(stderr, " PID: got %04x expect %04x \n", + sl->stlink_pid, USB_STLINK_PID); + return NULL; + } + + D(sl, "\n*** stlink_force_open ***\n"); + switch (stlink_current_mode(sl)) { + case STLINK_DEV_MASS_MODE: + return sl; + case STLINK_DEV_DEBUG_MODE: + // TODO go to mass? + return sl; + } + fprintf(stderr, "\n*** switch the stlink to mass mode ***\n"); + stlink_exit_dfu_mode(sl); + // exit the dfu mode -> the device is gone + fprintf(stderr, "\n*** reopen the stlink device ***\n"); + stlink_close(sl); + delay(5000); + + sl = stlink_open(dev_name, verbose); + if (sl == NULL) { + fputs("Error: could not open stlink device\n", stderr); + return NULL; + } + // re-query device info + stlink_version(sl); + return sl; +} + +static void mark_buf(struct stlink *sl) { + clear_buf(sl); + sl->q_buf[0] = 0x12; + sl->q_buf[1] = 0x34; + sl->q_buf[2] = 0x56; + sl->q_buf[3] = 0x78; + sl->q_buf[4] = 0x90; + sl->q_buf[15] = 0x42; + sl->q_buf[16] = 0x43; + sl->q_buf[63] = 0x42; + sl->q_buf[64] = 0x43; + sl->q_buf[1024 * 6 - 1] = 0x42; //6kB + sl->q_buf[1024 * 8 - 1] = 0x42; //8kB +} + +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); + fprintf(stderr, "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); + fprintf(stderr, "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); + fprintf(stderr, "mpu type register: MPU_TYPER = got 0x%08x expect 0x0", read_uint32(sl->q_buf, 0)); + + stlink_read_mem32(sl, 0xe000edf0, 4); + fprintf(stderr, "DHCSR = 0x%08x", read_uint32(sl->q_buf, 0)); + + stlink_read_mem32(sl, 0x4001100c, 4); + fprintf(stderr, "GPIOC_ODR = 0x%08x", read_uint32(sl->q_buf, 0)); +#endif +#if 1 +{ + //added by dwelch to load a binary into sram and change the pc (r15) + + unsigned int ra; + unsigned int rb; + FILE *fpin; + + fpin=fopen("blinker.bin","rb"); + if(fpin==NULL) + { + printf("Error opening file blinker.bin\n"); + return(1); + } + ra=0x20000000; + while(1) + { + if(fread(&rb,1,4,fpin)==0) break; + write_uint32(sl->q_buf, rb); + stlink_write_mem32(sl, ra, 4); + ra+=4; + } + printf("0x%08X\n",ra); + + for(ra=0x20000000;ra<0x20000010;ra++) + { + stlink_read_mem32(sl, ra, 4); + rb = read_uint32(sl->q_buf, 0); + printf("0x%04X 0x%04X\n",ra,rb); + } + + stlink_write_reg(sl, 0x20000050, 15); + + //let it fall through and allow the processor to run again +} +#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); + fprintf(stderr, "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); + //fprintf(stderr, "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 + + 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; +} diff --git a/vectors.s b/vectors.s new file mode 100644 index 0000000..981ac93 --- /dev/null +++ b/vectors.s @@ -0,0 +1,54 @@ + +/* vectors.s */ +.cpu cortex-m3 +.thumb + +.word 0x20001000 /* stack top address */ +.word _start /* 1 Reset */ +.word hang /* 2 NMI */ +.word hang /* 3 HardFault */ +.word hang /* 4 MemManage */ +.word hang /* 5 BusFault */ +.word hang /* 6 UsageFault */ +.word hang /* 7 RESERVED */ +.word hang /* 8 RESERVED */ +.word hang /* 9 RESERVED*/ +.word hang /* 10 RESERVED */ +.word hang /* 11 SVCall */ +.word hang /* 12 Debug Monitor */ +.word hang /* 13 RESERVED */ +.word hang /* 14 PendSV */ +.word hang /* 15 SysTick */ +.word hang /* 16 External Interrupt(0) */ +.word hang /* 17 External Interrupt(1) */ +.word hang /* 18 External Interrupt(2) */ +.word hang /* 19 ... */ + +.thumb_func +.global _start +_start: + ldr r0,stacktop + mov sp,r0 /* in case the vector table is not used */ + bl notmain + b hang + +.thumb_func +hang: b . + +.align +stacktop: .word 0x20001000 + +;@----------------------- +.thumb_func +.globl PUT32 +PUT32: + str r1,[r0] + bx lr +;@----------------------- +.thumb_func +.globl GET32 +GET32: + ldr r0,[r0] + bx lr + +.end