This is an automated email from Gerrit. Andrey Yurovsky ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/1515
-- gerrit commit 5f4ef7de9e94a7157f8d9353a61ca39ae882f6d8 Author: Andrey Yurovsky <[email protected]> Date: Wed Jul 17 13:21:53 2013 -0700 [RFC] stlink: add SWO tracing support Enable reading the SWO trace output via STLinkv2 dongles that support it. This adds an optional initialization parameter "stlink_swo_trace" with which the user specifies a destination file where SWO trace output is appended as it comes in and (optionally) a sampling rate (in Hz) for the data (2MHz, STLink's highest rate, is used if the rate is not specified). For example: stlink_swo_trace swo.log If stlink_swo_trace is specified with a usable file path, the stlink_usb driver will attempt to read SWO trace data as follows: - on _run(), the STLinkv2 will be told to enable tracing. - on _v2_get_status(), the trace data (if any) is fetched from the STLink after the target status is checked, if the target is running. - on _halt(), the STLink is told to disable tracing. When fetching trace data, the entire trace frame (excluding start/stop designators) is written to the output file and that data is flushed. Change-Id: I0b550bf2088fd71ac1268362c247efbaf14c6b8e Signed-off-by: Andrey Yurovsky <[email protected]> diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index a88f559..f702ae8 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -45,11 +45,15 @@ #define STLINK_NULL_EP 0 #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) +#define STLINK_TRACE_EP (3|ENDPOINT_IN) #define STLINK_SG_SIZE (31) #define STLINK_DATA_SIZE (4*128) #define STLINK_CMD_SIZE_V2 (16) #define STLINK_CMD_SIZE_V1 (10) +#define STLINK_TRACE_HZ (2000000) +#define STLINK_TRACE_SIZE (1024) + enum stlink_jtag_api_version { STLINK_JTAG_API_V1 = 1, STLINK_JTAG_API_V2, @@ -91,6 +95,12 @@ struct stlink_usb_handle_s { uint16_t pid; /** this is the currently used jtag api */ enum stlink_jtag_api_version jtag_api; + /** destination for SWO trace output */ + FILE *trace_f; + /** trace clock rate */ + uint32_t trace_hz; + /** whether we're logging SWO trace data */ + bool trace_enabled; }; #define STLINK_DEBUG_ERR_OK 0x80 @@ -161,6 +171,10 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 +#define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40 +#define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41 +#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 + /** */ enum stlink_mode { STLINK_MODE_UNKNOWN = 0, @@ -272,6 +286,26 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) } /** */ +static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h; + + assert(handle != NULL); + + h = (struct stlink_usb_handle_s *)handle; + + assert(h->version.stlink >= 2); + + if (jtag_libusb_bulk_read(h->fd, STLINK_TRACE_EP, (char *)buf, + size, 1000) != size) { + LOG_DEBUG("bulk trace read failed"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** */ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; @@ -713,6 +747,56 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } +static int stlink_usb_trace_read(void *handle) +{ + int res = ERROR_OK; + struct stlink_usb_handle_s *h; + + assert(handle != NULL); + + h = (struct stlink_usb_handle_s *)handle; + + if (h->trace_enabled) { + if (h->version.jtag >= 13) { + stlink_usb_init_buffer(handle, STLINK_RX_EP, 10); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GET_TRACE_NB; + + res = stlink_usb_xfer(handle, h->databuf, 2); + if (res == ERROR_OK) { + uint8_t buf[STLINK_TRACE_SIZE]; + size_t size = (h->databuf[1]<<8) | h->databuf[0]; + + if (size > 0) { + size = size < sizeof(buf) ? size : sizeof(buf) - 1; + + res = stlink_usb_read_trace(handle, buf, size); + if (res == ERROR_OK) { + size_t i; + + /* Log retrieved trace output but ignore the start/stop + * designators. */ + for (i = 0; i < size; i++) { + if (buf[i] != 0x01 && buf[i] != 0x80) + fputc(buf[i], h->trace_f); + } + + /* Write out the trace data */ + fflush(h->trace_f); + } + } + } else { + LOG_ERROR("Trace data read failed.\n"); + } + } else { + res = ERROR_FAIL; + } + } + + return res; +} + static enum target_state stlink_usb_v2_get_status(void *handle) { int result; @@ -727,6 +811,8 @@ static enum target_state stlink_usb_v2_get_status(void *handle) else if (status & S_RESET_ST) return TARGET_RESET; + stlink_usb_trace_read(handle); + return TARGET_RUNNING; } @@ -821,6 +907,75 @@ static int stlink_usb_assert_srst(void *handle, int srst) } /** */ +static int stlink_usb_trace_enable(void *handle) +{ + int res = ERROR_OK; + struct stlink_usb_handle_s *h; + + assert(handle != NULL); + + h = (struct stlink_usb_handle_s *)handle; + + if (!h->trace_enabled) { + if (h->version.jtag >= 13) { + stlink_usb_init_buffer(handle, STLINK_RX_EP, 10); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_START_TRACE_RX; + h->cmdbuf[h->cmdidx++] = (uint8_t)(STLINK_TRACE_SIZE); + h->cmdbuf[h->cmdidx++] = (uint8_t)(STLINK_TRACE_SIZE>>8); + h->cmdbuf[h->cmdidx++] = (uint8_t)(h->trace_hz>>0); + h->cmdbuf[h->cmdidx++] = (uint8_t)(h->trace_hz>>8); + h->cmdbuf[h->cmdidx++] = (uint8_t)(h->trace_hz>>16); + h->cmdbuf[h->cmdidx++] = (uint8_t)(h->trace_hz>>24); + + res = stlink_usb_xfer(handle, h->databuf, 2); + + if (res == ERROR_OK) { + h->trace_enabled = true; + LOG_INFO("Tracing: enabled (%uHz)\n", h->trace_hz); + } + } else { + LOG_ERROR("Tracing is not supported by this version."); + res = ERROR_FAIL; + } + } + + return res; +} + +static int stlink_usb_trace_disable(void *handle) +{ + int res = ERROR_OK; + struct stlink_usb_handle_s *h; + + assert(handle != NULL); + + h = (struct stlink_usb_handle_s *)handle; + + if (h->trace_enabled) { + if (h->version.jtag >= 13) { + if (h->trace_enabled) { + LOG_DEBUG("Tracing: disable\n"); + + stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX; + res = stlink_usb_xfer(handle, h->databuf, 2); + + if (res == ERROR_OK) + h->trace_enabled = false; + } + } else { + LOG_ERROR("Tracing is not supported by this version."); + res = ERROR_FAIL; + } + } + + return res; +} + +/** */ static int stlink_usb_run(void *handle) { int res; @@ -830,8 +985,14 @@ static int stlink_usb_run(void *handle) h = (struct stlink_usb_handle_s *)handle; - if (h->jtag_api == STLINK_JTAG_API_V2) - return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); + if (h->jtag_api == STLINK_JTAG_API_V2) { + res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); + + if (h->trace_f) + stlink_usb_trace_enable(handle); + + return res; + } stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); @@ -856,8 +1017,14 @@ static int stlink_usb_halt(void *handle) h = (struct stlink_usb_handle_s *)handle; - if (h->jtag_api == STLINK_JTAG_API_V2) - return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); + if (h->jtag_api == STLINK_JTAG_API_V2) { + res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); + + if (h->trace_enabled) + stlink_usb_trace_disable(handle); + + return res; + } stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); @@ -1241,6 +1408,12 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd) /* set the used jtag api, this will default to the newest supported version */ h->jtag_api = api; + /* the trace output file is already open if we will be logging SWO trace + * output */ + h->trace_enabled = false; + h->trace_f = param->trace_f; + h->trace_hz = param->trace_hz > 0 ? param->trace_hz : STLINK_TRACE_HZ; + /* initialize the debug hardware */ err = stlink_usb_init_mode(h); @@ -1259,6 +1432,16 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd) /** */ static int stlink_usb_close(void *fd) { + struct stlink_usb_handle_s *h; + + h = (struct stlink_usb_handle_s *)fd; + + if (h) { + fclose(h->trace_f); + h->trace_f = NULL; + h->trace_enabled = false; + } + return ERROR_OK; } diff --git a/src/jtag/stlink/stlink_interface.c b/src/jtag/stlink/stlink_interface.c index c06d86c..e7cdbd4 100644 --- a/src/jtag/stlink/stlink_interface.c +++ b/src/jtag/stlink/stlink_interface.c @@ -34,7 +34,7 @@ #include <target/target.h> -static struct stlink_interface_s stlink_if = { {0, 0, 0, 0, 0, 0}, 0, 0 }; +static struct stlink_interface_s stlink_if = { {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0 }; int stlink_interface_open(enum stlink_transports tr) { @@ -214,6 +214,23 @@ COMMAND_HANDLER(stlink_interface_handle_api_command) return ERROR_OK; } +COMMAND_HANDLER(stlink_interface_handle_swo_trace_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + stlink_if.param.trace_f = fopen(CMD_ARGV[0], "a"); + + if (stlink_if.param.trace_f) { + if (CMD_ARGC >= 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], stlink_if.param.trace_hz); + + return ERROR_OK; + } else { + return ERROR_COMMAND_ARGUMENT_INVALID; + } +} + static const struct command_registration stlink_interface_command_handlers[] = { { .name = "stlink_device_desc", @@ -250,6 +267,13 @@ static const struct command_registration stlink_interface_command_handlers[] = { .help = "set the desired stlink api level", .usage = "api version 1 or 2", }, + { + .name = "stlink_swo_trace", + .handler = &stlink_interface_handle_swo_trace_command, + .mode = COMMAND_ANY, + .help = "send SWO trace data to a file", + .usage = "file_path [trace_hz]", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/stlink/stlink_interface.h b/src/jtag/stlink/stlink_interface.h index ee2feff..0efea1e 100644 --- a/src/jtag/stlink/stlink_interface.h +++ b/src/jtag/stlink/stlink_interface.h @@ -40,6 +40,10 @@ struct stlink_interface_param_s { /** */ unsigned api; /** */ + FILE *trace_f; + /** */ + uint32_t trace_hz; + /** */ enum stlink_transports transport; }; -- ------------------------------------------------------------------------------ See everything from the browser to the database with AppDynamics Get end-to-end visibility with application monitoring from AppDynamics Isolate bottlenecks and diagnose root cause in seconds. Start your free trial of AppDynamics Pro today! http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
