Execute a custom adapter-specific command. The @var{command} string is
passed as is to the underlying adapter layout handler.
@end deffn
-
-@deffn {Config Command} {trace} source_clock_hz [output_file_path]
-Enable SWO tracing (if supported). The source clock rate for the
-trace port must be specified, this is typically the CPU clock rate. If
-the optional output file is specified then raw trace data is appended
-to the file, and the file is created if it does not exist.
-@end deffn
@end deffn
@deffn {Interface Driver} {opendous}
else
LOG_ERROR("transport is not selected");
}
+
+int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq)
+{
+ if (jtag->config_trace)
+ return jtag->config_trace(enabled, pin_protocol, port_size,
+ trace_freq);
+ else if (enabled) {
+ LOG_ERROR("The selected interface does not support tracing");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+int adapter_poll_trace(uint8_t *buf, size_t *size)
+{
+ if (jtag->poll_trace)
+ return jtag->poll_trace(buf, size);
+
+ return ERROR_FAIL;
+}
struct {
/** whether SWO tracing is enabled or not */
bool enabled;
- /** trace data destination file */
- FILE *output_f;
- /** trace module source clock (for prescaler) */
+ /** trace module source clock */
uint32_t source_hz;
- /** trace module clock prescaler */
- uint32_t prescale;
} trace;
/** reconnect is needed next time we try to query the
* status */
}
/** */
-static void stlink_usb_trace_read(void *handle)
+static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
{
struct stlink_usb_handle_s *h = handle;
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 = le_to_h_u16(h->databuf);
-
- if (size > 0) {
- size = size < sizeof(buf) ? size : sizeof(buf) - 1;
-
- res = stlink_usb_read_trace(handle, buf, size);
- if (res == ERROR_OK) {
- if (h->trace.output_f) {
- /* Log retrieved trace output */
- if (fwrite(buf, 1, size, h->trace.output_f) > 0)
- fflush(h->trace.output_f);
- }
- }
- }
+ if (res != ERROR_OK)
+ return res;
+
+ size_t bytes_avail = le_to_h_u16(h->databuf);
+ *size = bytes_avail < *size ? bytes_avail : *size - 1;
+
+ if (*size > 0) {
+ res = stlink_usb_read_trace(handle, buf, *size);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
}
}
-}
-
-static int stlink_usb_trace_read_callback(void *handle)
-{
- stlink_usb_trace_read(handle);
+ *size = 0;
return ERROR_OK;
}
else if (status & S_RESET_ST)
return TARGET_RESET;
- stlink_usb_trace_read(handle);
-
return TARGET_RUNNING;
}
return TARGET_UNKNOWN;
}
-/** */
-static int stlink_usb_reset(void *handle)
-{
- struct stlink_usb_handle_s *h = handle;
-
- assert(handle != NULL);
-
- stlink_usb_init_buffer(handle, h->rx_ep, 2);
-
- h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
-
- if (h->jtag_api == STLINK_JTAG_API_V1)
- h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS;
- else
- h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS;
-
- return stlink_cmd_allow_retry(handle, h->databuf, 2);
-}
-
static int stlink_usb_assert_srst(void *handle, int srst)
{
struct stlink_usb_handle_s *h = handle;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
-/** */
-static int stlink_configure_target_trace_port(void *handle)
-{
- int res;
- uint32_t reg;
- struct stlink_usb_handle_s *h = handle;
-
- assert(handle != NULL);
-
- /* configure the TPI */
-
- /* enable the trace subsystem */
- res = stlink_usb_v2_read_debug_reg(handle, DCB_DEMCR, ®);
- if (res != ERROR_OK)
- goto out;
- res = stlink_usb_write_debug_reg(handle, DCB_DEMCR, TRCENA|reg);
- if (res != ERROR_OK)
- goto out;
- /* set the TPI clock prescaler */
- res = stlink_usb_write_debug_reg(handle, TPIU_ACPR, h->trace.prescale);
- if (res != ERROR_OK)
- goto out;
- /* select the pin protocol. The STLinkv2 only supports asynchronous
- * UART emulation (NRZ) mode, so that's what we pick. */
- res = stlink_usb_write_debug_reg(handle, TPIU_SPPR, 0x02);
- if (res != ERROR_OK)
- goto out;
- /* disable continuous formatting */
- res = stlink_usb_write_debug_reg(handle, TPIU_FFCR, (1<<8));
- if (res != ERROR_OK)
- goto out;
-
- /* configure the ITM */
-
- /* unlock access to the ITM registers */
- res = stlink_usb_write_debug_reg(handle, ITM_LAR, 0xC5ACCE55);
- if (res != ERROR_OK)
- goto out;
- /* enable trace with ATB ID 1 */
- res = stlink_usb_write_debug_reg(handle, ITM_TCR, (1<<16)|(1<<0)|(1<<2));
- if (res != ERROR_OK)
- goto out;
- /* trace privilege */
- res = stlink_usb_write_debug_reg(handle, ITM_TPR, 1);
- if (res != ERROR_OK)
- goto out;
- /* trace port enable (port 0) */
- res = stlink_usb_write_debug_reg(handle, ITM_TER0, (1<<0));
- if (res != ERROR_OK)
- goto out;
-
- res = ERROR_OK;
-out:
- return res;
-}
-
/** */
static void stlink_usb_trace_disable(void *handle)
{
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX;
res = stlink_usb_xfer(handle, h->databuf, 2);
- if (res == ERROR_OK) {
+ if (res == ERROR_OK)
h->trace.enabled = false;
- target_unregister_timer_callback(stlink_usb_trace_read_callback, handle);
- }
}
assert(handle != NULL);
if (h->version.jtag >= STLINK_TRACE_MIN_VERSION) {
- uint32_t trace_hz;
-
- res = stlink_configure_target_trace_port(handle);
- if (res != ERROR_OK)
- LOG_ERROR("Unable to configure tracing on target");
-
- trace_hz = h->trace.prescale > 0 ?
- h->trace.source_hz / (h->trace.prescale + 1) :
- h->trace.source_hz;
-
stlink_usb_init_buffer(handle, h->rx_ep, 10);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_START_TRACE_RX;
h_u16_to_le(h->cmdbuf+h->cmdidx, (uint16_t)STLINK_TRACE_SIZE);
h->cmdidx += 2;
- h_u32_to_le(h->cmdbuf+h->cmdidx, trace_hz);
+ h_u32_to_le(h->cmdbuf+h->cmdidx, h->trace.source_hz);
h->cmdidx += 4;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res == ERROR_OK) {
h->trace.enabled = true;
- LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", trace_hz);
- /* We need the trace read function to be called at a
- * high-enough frequency to ensure reasonable
- * "timeliness" in processing ITM/DWT data.
- * TODO: An alternative could be using the asynchronous
- * features of the libusb-1.0 API to queue up one or more
- * reads in advance and requeue them once they are
- * completed. */
- target_register_timer_callback(stlink_usb_trace_read_callback, 1, 1, handle);
+ LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", h->trace.source_hz);
}
} else {
LOG_ERROR("Tracing is not supported by this version.");
return res;
}
+/** */
+static int stlink_usb_reset(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int retval;
+
+ assert(handle != NULL);
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 2);
+
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+
+ if (h->jtag_api == STLINK_JTAG_API_V1)
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS;
+ else
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS;
+
+ retval = stlink_cmd_allow_retry(handle, h->databuf, 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (h->trace.enabled) {
+ stlink_usb_trace_disable(h);
+ return stlink_usb_trace_enable(h);
+ }
+
+ return ERROR_OK;
+}
+
/** */
static int stlink_usb_run(void *handle)
{
if (h->jtag_api == STLINK_JTAG_API_V2) {
res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
- /* Try to start tracing, if requested */
- if (res == ERROR_OK && h->trace.source_hz && !h->trace.enabled) {
- if (stlink_usb_trace_enable(handle) == ERROR_OK)
- LOG_DEBUG("Tracing: enabled");
- else
- LOG_ERROR("Tracing: enable failed");
- }
-
return res;
}
if (h->jtag_api == STLINK_JTAG_API_V2) {
res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
- if (res == ERROR_OK && h->trace.enabled)
- stlink_usb_trace_disable(handle);
-
return res;
}
/* set the used jtag api, this will default to the newest supported version */
h->jtag_api = api;
- if (h->jtag_api >= 2 && param->trace_source_hz > 0) {
- uint32_t prescale;
-
- prescale = param->trace_source_hz > STLINK_TRACE_MAX_HZ ?
- (param->trace_source_hz / STLINK_TRACE_MAX_HZ) - 1 : 0;
-
- h->trace.output_f = param->trace_f;
- h->trace.source_hz = param->trace_source_hz;
- h->trace.prescale = prescale;
- }
-
/* initialize the debug hardware */
err = stlink_usb_init_mode(h, param->connect_under_reset);
return ERROR_FAIL;
}
+int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) {
+ LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
+ return ERROR_FAIL;
+ }
+
+ if (!enabled) {
+ stlink_usb_trace_disable(h);
+ return ERROR_OK;
+ }
+
+ if (*trace_freq > STLINK_TRACE_MAX_HZ) {
+ LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
+ STLINK_TRACE_MAX_HZ);
+ return ERROR_FAIL;
+ }
+
+ stlink_usb_trace_disable(h);
+
+ if (!*trace_freq)
+ *trace_freq = STLINK_TRACE_MAX_HZ;
+ h->trace.source_hz = *trace_freq;
+
+ return stlink_usb_trace_enable(h);
+}
+
/** */
struct hl_layout_api_s stlink_usb_layout_api = {
/** */
.override_target = stlink_usb_override_target,
/** */
.speed = stlink_speed,
+ /** */
+ .config_trace = stlink_config_trace,
+ /** */
+ .poll_trace = stlink_usb_trace_read,
};
#include <target/target.h>
-static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, NULL, 0, -1}, 0, 0 };
+static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 };
int hl_interface_open(enum hl_transports tr)
{
{
LOG_DEBUG("hl_interface_quit");
- if (hl_if.param.trace_f) {
- fclose(hl_if.param.trace_f);
- hl_if.param.trace_f = NULL;
- }
- hl_if.param.trace_source_hz = 0;
-
if (hl_if.layout->api->close)
hl_if.layout->api->close(hl_if.handle);
return ERROR_FAIL;
}
+int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq)
+{
+ if (hl_if.layout->api->config_trace)
+ return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol,
+ port_size, trace_freq);
+ else if (enabled) {
+ LOG_ERROR("The selected interface does not support tracing");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+int hl_interface_poll_trace(uint8_t *buf, size_t *size)
+{
+ if (hl_if.layout->api->poll_trace)
+ return hl_if.layout->api->poll_trace(hl_if.handle, buf, size);
+
+ return ERROR_FAIL;
+}
+
COMMAND_HANDLER(hl_interface_handle_device_desc_command)
{
LOG_DEBUG("hl_interface_handle_device_desc_command");
return ERROR_OK;
}
-COMMAND_HANDLER(interface_handle_trace_command)
-{
- FILE *f = NULL;
- unsigned source_hz;
-
- if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], source_hz);
- if (source_hz == 0) {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- if (CMD_ARGC == 2) {
- f = fopen(CMD_ARGV[1], "a");
- if (!f)
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- hl_if.param.trace_f = f;
- hl_if.param.trace_source_hz = source_hz;
-
- return ERROR_OK;
-}
-
COMMAND_HANDLER(interface_handle_hla_command)
{
if (CMD_ARGC != 1)
.usage = "(vid pid)* ",
},
{
- .name = "trace",
- .handler = &interface_handle_trace_command,
- .mode = COMMAND_CONFIG,
- .help = "configure trace reception",
- .usage = "source_lock_hz [destination_path]",
- },
- {
.name = "hla_command",
.handler = &interface_handle_hla_command,
.mode = COMMAND_EXEC,
.speed = &hl_interface_speed,
.khz = &hl_interface_khz,
.speed_div = &hl_interface_speed_div,
+ .config_trace = &hl_interface_config_trace,
+ .poll_trace = &hl_interface_poll_trace,
};
enum hl_transports transport;
/** */
bool connect_under_reset;
- /** Output file for trace data (if any) */
- FILE *trace_f;
- /** Trace module source clock rate */
- uint32_t trace_source_hz;
/** Initial interface clock clock speed */
int initial_interface_speed;
};
#ifndef _HL_LAYOUT_H
#define _HL_LAYOUT_H
+#include <target/armv7m_trace.h>
+
/** */
struct hl_interface_s;
struct hl_interface_param_s;
int (*custom_command) (void *handle, const char *command);
/** */
int (*speed)(void *handle, int khz, bool query);
+ /**
+ * Configure trace parameters for the adapter
+ *
+ * @param handle A handle to adapter
+ * @param enabled Whether to enable trace
+ * @param pin_protocol Configured pin protocol
+ * @param port_size Trace port width for sync mode
+ * @param trace_freq A pointer to the configured trace
+ * frequency; if it points to 0, the adapter driver must write
+ * its maximum supported rate there
+ * @returns ERROR_OK on success, an error code on failure.
+ */
+ int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq);
+ /**
+ * Poll for new trace data
+ *
+ * @param handle A handle to adapter
+ * @param buf A pointer to buffer to store received data
+ * @param size A pointer to buffer size; must be filled with
+ * the actual amount of bytes written
+ *
+ * @returns ERROR_OK on success, an error code on failure.
+ */
+ int (*poll_trace)(void *handle, uint8_t *buf, size_t *size);
/** */
enum target_state (*state) (void *fd);
};
#define OPENOCD_JTAG_INTERFACE_H
#include <jtag/jtag.h>
+#include <target/armv7m_trace.h>
/* @file
* The "Cable Helper API" is what the cable drivers can use to help
* @returns ERROR_OK on success, or an error code on failure.
*/
int (*srst_asserted)(int *srst_asserted);
+
+ /**
+ * Configure trace parameters for the adapter
+ *
+ * @param enabled Whether to enable trace
+ * @param pin_protocol Configured pin protocol
+ * @param port_size Trace port width for sync mode
+ * @param trace_freq A pointer to the configured trace
+ * frequency; if it points to 0, the adapter driver must write
+ * its maximum supported rate there
+ * @returns ERROR_OK on success, an error code on failure.
+ */
+ int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq);
+
+ /**
+ * Poll for new trace data
+ *
+ * @param buf A pointer to buffer to store received data
+ * @param size A pointer to buffer size; must be filled with
+ * the actual amount of bytes written
+ *
+ * @returns ERROR_OK on success, an error code on failure.
+ */
+ int (*poll_trace)(uint8_t *buf, size_t *size);
};
extern const char * const jtag_only[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
+int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq);
+int adapter_poll_trace(uint8_t *buf, size_t *size);
#endif /* OPENOCD_JTAG_INTERFACE_H */
#include <target/armv7m.h>
#include <target/cortex_m.h>
#include <target/armv7m_trace.h>
+#include <jtag/interface.h>
+
+#define TRACE_BUF_SIZE 4096
+
+static int armv7m_poll_trace(void *target)
+{
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+ uint8_t buf[TRACE_BUF_SIZE];
+ size_t size = sizeof(buf);
+ int retval;
+
+ retval = adapter_poll_trace(buf, &size);
+ if (retval != ERROR_OK || !size)
+ return retval;
+
+ if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
+ fflush(armv7m->trace_config.trace_file);
+ else {
+ LOG_ERROR("Error writing to the trace destination file");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
int armv7m_trace_tpiu_config(struct target *target)
{
int prescaler;
int retval;
+ target_unregister_timer_callback(armv7m_poll_trace, target);
+
+
+ retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ trace_config->pin_protocol,
+ trace_config->port_size,
+ &trace_config->trace_freq);
+ if (retval != ERROR_OK)
+ return retval;
+
if (!trace_config->trace_freq) {
LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
return ERROR_FAIL;
}
+ prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
+
if (trace_config->traceclkin_freq % trace_config->trace_freq) {
- LOG_ERROR("Can not calculate an integer divisor to get %u trace port frequency from %u TRACECLKIN frequency",
- trace_config->trace_freq, trace_config->traceclkin_freq);
- return ERROR_FAIL;
+ prescaler++;
+ int trace_freq = trace_config->traceclkin_freq / prescaler;
+ LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead",
+ trace_config->trace_freq, trace_config->traceclkin_freq,
+ trace_freq);
+ trace_config->trace_freq = trace_freq;
+ retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ trace_config->pin_protocol,
+ trace_config->port_size,
+ &trace_config->trace_freq);
+ if (retval != ERROR_OK)
+ return retval;
}
- prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
-
retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
if (retval != ERROR_OK)
return retval;
if (retval != ERROR_OK)
return retval;
+ if (trace_config->config_type == INTERNAL)
+ target_register_timer_callback(armv7m_poll_trace, 1, 1, target);
+
target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
return ERROR_OK;
#ifndef ARMV7M_TRACE_H
#define ARMV7M_TRACE_H
+#include <target/target.h>
#include <command.h>
/**