}
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
- if (jtag->config_trace)
- return jtag->config_trace(enabled, pin_protocol, port_size,
- trace_freq);
- else if (enabled) {
+ if (jtag->config_trace) {
+ return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq,
+ traceclkin_freq, prescaler);
+ } else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
}
#include <jtag/swd.h>
#include <jtag/commands.h>
#include <jtag/drivers/jtag_usb_common.h>
+#include <target/cortex_m.h>
#include <libjaylink/libjaylink.h>
static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE;
+/* Maximum SWO frequency deviation. */
+#define SWO_MAX_FREQ_DEV 0.03
+
/* 256 byte non-volatile memory */
struct device_config {
uint8_t usb_address;
return tmp & 0xffffff00;
}
-static bool check_trace_freq(struct jaylink_swo_speed speed,
- uint32_t trace_freq)
+static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
+ uint32_t trace_freq, uint16_t *prescaler)
{
- double min;
+ unsigned int presc;
double deviation;
+
+ presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1;
+
+ if (presc > TPIU_ACPR_MAX_SWOSCALER)
+ return false;
+
+ deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq));
+
+ if (deviation > SWO_MAX_FREQ_DEV)
+ return false;
+
+ *prescaler = presc;
+
+ return true;
+}
+
+static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
+ unsigned int traceclkin_freq, uint32_t *trace_freq,
+ uint16_t *prescaler)
+{
uint32_t divider;
+ unsigned int presc;
+ double deviation;
+
+ for (divider = speed.min_div; divider <= speed.max_div; divider++) {
+ *trace_freq = speed.freq / divider;
+ presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1;
- min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div)));
+ if (presc > TPIU_ACPR_MAX_SWOSCALER)
+ break;
- for (divider = speed.min_div; divider < speed.max_div; divider++) {
- deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider)));
+ deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq));
- if (deviation < 0.03) {
- LOG_DEBUG("Found suitable frequency divider %u with deviation of "
- "%.02f %%.", divider, deviation);
+ if (deviation <= SWO_MAX_FREQ_DEV) {
+ *prescaler = presc;
return true;
}
-
- if (deviation < min)
- min = deviation;
}
- LOG_ERROR("Selected trace frequency is not supported by the device. "
- "Please choose a different trace frequency.");
- LOG_ERROR("Maximum permitted deviation is 3.00 %%, but only %.02f %% "
- "could be achieved.", min * 100);
-
return false;
}
static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
int ret;
uint32_t buffer_size;
struct jaylink_swo_speed speed;
+ uint32_t divider;
+ uint32_t min_freq;
+ uint32_t max_freq;
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) {
LOG_ERROR("Trace capturing is not supported by the device.");
return ERROR_FAIL;
}
- if (!*trace_freq)
- *trace_freq = speed.freq / speed.min_div;
+ if (*trace_freq > 0) {
+ divider = speed.freq / *trace_freq;
+ min_freq = speed.freq / speed.max_div;
+ max_freq = speed.freq / speed.min_div;
+
+ if (*trace_freq > max_freq) {
+ LOG_INFO("Given SWO frequency too high, using %u Hz instead.",
+ max_freq);
+ *trace_freq = max_freq;
+ } else if (*trace_freq < min_freq) {
+ LOG_INFO("Given SWO frequency too low, using %u Hz instead.",
+ min_freq);
+ *trace_freq = min_freq;
+ } else if (*trace_freq != speed.freq / divider) {
+ *trace_freq = speed.freq / divider;
+
+ LOG_INFO("Given SWO frequency is not supported by the device, "
+ "using %u Hz instead.", *trace_freq);
+ }
- if (!check_trace_freq(speed, *trace_freq))
- return ERROR_FAIL;
+ if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq,
+ prescaler)) {
+ LOG_ERROR("SWO frequency is not suitable. Please choose a "
+ "different frequency or use auto-detection.");
+ return ERROR_FAIL;
+ }
+ } else {
+ LOG_INFO("Trying to auto-detect SWO frequency.");
- LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
+ if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq,
+ prescaler)) {
+ LOG_ERROR("Maximum permitted frequency deviation of %.02f %% "
+ "could not be achieved.", SWO_MAX_FREQ_DEV);
+ LOG_ERROR("Auto-detection of SWO frequency failed.");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("Using SWO frequency of %u Hz.", *trace_freq);
+ }
ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq,
buffer_size);
return ERROR_FAIL;
}
+ LOG_DEBUG("Using %u bytes device memory for trace capturing.",
+ buffer_size);
+
/*
* Adjust the SWD transaction buffer size as starting SWO capturing
* allocates device internal memory.
return ERROR_FAIL;
}
-int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+int stlink_config_trace(void *handle, bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler)
{
struct stlink_usb_handle_s *h = handle;
+ uint16_t presc;
if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
if (!*trace_freq)
*trace_freq = STLINK_TRACE_MAX_HZ;
+
+ presc = traceclkin_freq / *trace_freq;
+
+ if (traceclkin_freq % *trace_freq > 0)
+ presc++;
+
+ if (presc > TPIU_ACPR_MAX_SWOSCALER) {
+ LOG_ERROR("SWO frequency is not suitable. Please choose a different "
+ "frequency.");
+ return ERROR_FAIL;
+ }
+
+ *prescaler = presc;
h->trace.source_hz = *trace_freq;
return stlink_usb_trace_enable(h);
}
int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq)
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler)
{
if (hl_if.layout->api->config_trace)
- return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol,
- port_size, trace_freq);
+ return hl_if.layout->api->config_trace(hl_if.handle, enabled,
+ pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler);
else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ int (*config_trace)(void *handle, bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler);
/**
* Poll for new trace data
*
* @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
+ * @param traceclkin_freq TRACECLKIN frequency provided to the TPIU in Hz
+ * @param prescaler Pointer to the SWO prescaler calculated by the
+ * adapter
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler);
/**
* Poll for new trace data
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
- uint32_t port_size, unsigned int *trace_freq);
+ uint32_t port_size, unsigned int *trace_freq,
+ unsigned int traceclkin_freq, uint16_t *prescaler);
int adapter_poll_trace(uint8_t *buf, size_t *size);
#endif /* OPENOCD_JTAG_INTERFACE_H */
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct armv7m_trace_config *trace_config = &armv7m->trace_config;
- int prescaler;
+ uint16_t prescaler;
int retval;
target_unregister_timer_callback(armv7m_poll_trace, target);
-
retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
- trace_config->pin_protocol,
- trace_config->port_size,
- &trace_config->trace_freq);
+ trace_config->pin_protocol, trace_config->port_size,
+ &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler);
+
if (retval != ERROR_OK)
return retval;
return ERROR_FAIL;
}
- prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
-
- if (trace_config->traceclkin_freq % trace_config->trace_freq) {
- 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 == TRACE_CONFIG_TYPE_INTERNAL,
- trace_config->pin_protocol,
- trace_config->port_size,
- &trace_config->trace_freq);
- if (retval != ERROR_OK)
- return retval;
- }
-
retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
if (retval != ERROR_OK)
return retval;
#define TPIU_FFCR 0xE0040304
#define TPIU_FSCR 0xE0040308
+/* Maximum SWO prescaler value. */
+#define TPIU_ACPR_MAX_SWOSCALER 0x1fff
+
/* DCB_DHCSR bit and field definitions */
#define DBGKEY (0xA05F << 16)
#define C_DEBUGEN (1 << 0)