#define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40
#define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41
#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42
+#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43
#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00
#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01
#define REQUEST_SENSE 0x03
#define REQUEST_SENSE_LENGTH 18
+static const struct {
+ int speed;
+ int speed_divisor;
+} stlink_khz_to_speed_map[] = {
+ {4000, 0},
+ {1800, 1}, /* default */
+ {1200, 2},
+ {950, 3},
+ {480, 7},
+ {240, 15},
+ {125, 31},
+ {100, 40},
+ {50, 79},
+ {25, 158},
+ {15, 265},
+ {5, 798}
+};
+
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
/** */
return ERROR_OK;
}
+static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ /* only supported by stlink/v2 and for firmware >= 22 */
+ if (h->version.stlink == 1 || h->version.jtag < 22)
+ return ERROR_COMMAND_NOTFOUND;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 2);
+
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
+ h_u16_to_le(h->cmdbuf+h->cmdidx, clk_divisor);
+ h->cmdidx += 2;
+
+ int result = stlink_cmd_allow_retry(handle, h->databuf, 2);
+
+ if (result != ERROR_OK)
+ return result;
+
+ return ERROR_OK;
+}
+
/** */
static int stlink_usb_current_mode(void *handle, uint8_t *mode)
{
assert(h->version.jtag >= STLINK_TRACE_MIN_VERSION);
- LOG_DEBUG("Tracing: disable\n");
+ LOG_DEBUG("Tracing: disable");
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
res = stlink_configure_target_trace_port(handle);
if (res != ERROR_OK)
- LOG_ERROR("Unable to configure tracing on target\n");
+ LOG_ERROR("Unable to configure tracing on target");
trace_hz = h->trace.prescale > 0 ?
h->trace.source_hz / (h->trace.prescale + 1) :
if (res == ERROR_OK) {
h->trace.enabled = true;
- LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz\n", trace_hz);
+ 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.
/* 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\n");
+ LOG_DEBUG("Tracing: enabled");
else
- LOG_ERROR("Tracing: enable failed\n");
+ LOG_ERROR("Tracing: enable failed");
}
return res;
return !strcmp(targetname, "cortex_m");
}
+static int stlink_speed(void *handle, int khz, bool query)
+{
+ unsigned i;
+ int speed_index = -1;
+ int speed_diff = INT_MAX;
+ struct stlink_usb_handle_s *h = handle;
+
+ /* only supported by stlink/v2 and for firmware >= 22 */
+ if (h && (h->version.stlink == 1 || h->version.jtag < 22))
+ return khz;
+
+ for (i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++) {
+ if (khz == stlink_khz_to_speed_map[i].speed) {
+ speed_index = i;
+ break;
+ } else {
+ int current_diff = khz - stlink_khz_to_speed_map[i].speed;
+ /* get abs value for comparison */
+ current_diff = (current_diff > 0) ? current_diff : -current_diff;
+ if ((current_diff < speed_diff) && khz >= stlink_khz_to_speed_map[i].speed) {
+ speed_diff = current_diff;
+ speed_index = i;
+ }
+ }
+ }
+
+ bool match = true;
+
+ if (speed_index == -1) {
+ /* this will only be here if we cannot match the slow speed.
+ * use the slowest speed we support.*/
+ speed_index = ARRAY_SIZE(stlink_khz_to_speed_map) - 1;
+ match = false;
+ } else if (i == ARRAY_SIZE(stlink_khz_to_speed_map))
+ match = false;
+
+ if (!match && query) {
+ LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \
+ khz, stlink_khz_to_speed_map[speed_index].speed);
+ }
+
+ if (h && !query) {
+ int result = stlink_usb_set_swdclk(h, stlink_khz_to_speed_map[speed_index].speed_divisor);
+ if (result != ERROR_OK) {
+ LOG_ERROR("Unable to set adapter speed");
+ return khz;
+ }
+ }
+
+ return stlink_khz_to_speed_map[speed_index].speed;
+}
+
/** */
-static int stlink_usb_close(void *fd)
+static int stlink_usb_close(void *handle)
{
- struct stlink_usb_handle_s *h = fd;
+ struct stlink_usb_handle_s *h = handle;
- if (h->fd)
+ if (h && h->fd)
jtag_libusb_close(h->fd);
- free(fd);
+ free(h);
return ERROR_OK;
}
const uint16_t vids[] = { param->vid, 0 };
const uint16_t pids[] = { param->pid, 0 };
+ const char *serial = param->serial;
- LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
- param->vid, param->pid);
+ LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
+ param->transport, param->vid, param->pid,
+ param->serial ? param->serial : "");
/*
On certain host USB configurations(e.g. MacBook Air)
in order to become operational.
*/
do {
- if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) {
+ if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) {
LOG_ERROR("open failed");
goto error_open;
}
err = stlink_usb_init_mode(h, param->connect_under_reset);
if (err != ERROR_OK) {
- LOG_ERROR("init mode failed");
+ LOG_ERROR("init mode failed (unable to connect to the target)");
goto error_open;
}
+ /* clock speed only supported by stlink/v2 and for firmware >= 22 */
+ if (h->version.stlink >= 2 && h->version.jtag >= 22) {
+ LOG_DEBUG("Supported clock speeds are:");
+
+ for (unsigned i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++)
+ LOG_DEBUG("%d kHz", stlink_khz_to_speed_map[i].speed);
+
+ stlink_speed(h, param->initial_interface_speed, false);
+ }
+
/* get cpuid, so we can determine the max page size
* start with a safe default */
h->max_mem_packet = (1 << 10);
.write_debug_reg = stlink_usb_write_debug_reg,
/** */
.override_target = stlink_usb_override_target,
+ /** */
+ .speed = stlink_speed,
};