#define OCD_FIRMWARE_UPGRADE \
"XDS110: upgrade to version 2.3.0.11+ for improved support"
+/* Firmware version that introduced improved TCK performance */
+#define FAST_TCK_FIRMWARE_VERSION 0x03000000
+
+/* Firmware version that introduced 10 MHz and 12 MHz TCK support */
+#define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003
+
/***************************************************************************
* USB Connection Buffer Definitions *
***************************************************************************/
/* TCK frequency limits */
#define XDS110_MIN_TCK_SPEED 100 /* kHz */
-#define XDS110_MAX_TCK_SPEED 2500 /* kHz */
-#define XDS110_TCK_PULSE_INCREMENT 66.0
+#define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */
+#define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */
+#define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */
+
+/* Fixed TCK delay values for "Fast" TCK frequencies */
+#define FAST_TCK_DELAY_14000_KHZ 0
+#define FAST_TCK_DELAY_10000_KHZ 0xfffffffd
+#define FAST_TCK_DELAY_12000_KHZ 0xfffffffe
+#define FAST_TCK_DELAY_8500_KHZ 1
+#define FAST_TCK_DELAY_5500_KHZ 2
+/* For TCK frequencies below 5500 kHz, use calculated delay */
/* Scan mode on connect */
#define MODE_JTAG 1
.is_cmapi_acquired = false,
.is_swd_mode = false,
.is_ap_dirty = false,
- .speed = XDS110_MAX_TCK_SPEED,
+ .speed = XDS110_DEFAULT_TCK_SPEED,
.delay_count = 0,
.serial = {0},
.voltage = 0,
xds110.txn_result_count = 0;
}
-static void xds110_execute_reset(struct jtag_command *cmd)
+static int xds110_reset(int trst, int srst)
{
- char trst;
- char srst;
+ uint8_t value;
+ bool success;
+ int retval = ERROR_OK;
- if (cmd->cmd.reset->trst != -1) {
- if (cmd->cmd.reset->trst == 0) {
+ if (trst != -1) {
+ if (trst == 0) {
/* Deassert nTRST (active low) */
- trst = 1;
+ value = 1;
} else {
/* Assert nTRST (active low) */
- trst = 0;
+ value = 0;
}
- (void)xds_set_trst(trst);
+ success = xds_set_trst(value);
+ if (!success)
+ retval = ERROR_FAIL;
}
- if (cmd->cmd.reset->srst != -1) {
- if (cmd->cmd.reset->srst == 0) {
+ if (srst != -1) {
+ if (srst == 0) {
/* Deassert nSRST (active low) */
- srst = 1;
+ value = 1;
} else {
/* Assert nSRST (active low) */
- srst = 0;
+ value = 0;
}
- (void)xds_set_srst(srst);
+ success = xds_set_srst(value);
+ if (!success)
+ retval = ERROR_FAIL;
/* Toggle TCK to trigger HIB on CC13x/CC26x devices */
- (void)xds_cycle_tck(60000);
+ if (success && !xds110.is_swd_mode) {
+ /* Toggle TCK for about 50 ms */
+ success = xds_cycle_tck(xds110.speed * 50);
+ }
+
+ if (!success)
+ retval = ERROR_FAIL;
}
+
+ return retval;
}
static void xds110_execute_sleep(struct jtag_command *cmd)
static void xds110_execute_command(struct jtag_command *cmd)
{
switch (cmd->type) {
- case JTAG_RESET:
- xds110_flush();
- xds110_execute_reset(cmd);
- break;
case JTAG_SLEEP:
xds110_flush();
xds110_execute_sleep(cmd);
static int xds110_speed(int speed)
{
+ double freq_to_use;
+ uint32_t delay_count;
bool success;
if (speed == 0) {
return ERROR_JTAG_NOT_IMPLEMENTED;
}
- if (speed > XDS110_MAX_TCK_SPEED) {
- LOG_INFO("XDS110: reduce speed request: %dkHz to %dkHz maximum",
- speed, XDS110_MAX_TCK_SPEED);
- speed = XDS110_MAX_TCK_SPEED;
- }
-
if (speed < XDS110_MIN_TCK_SPEED) {
- LOG_INFO("XDS110: increase speed request: %dkHz to %dkHz minimum",
+ LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum",
speed, XDS110_MIN_TCK_SPEED);
speed = XDS110_MIN_TCK_SPEED;
}
- /* The default is the maximum frequency the XDS110 can support */
- uint32_t freq_to_use = XDS110_MAX_TCK_SPEED * 1000; /* Hz */
- uint32_t delay_count = 0;
+ /* Older XDS110 firmware had inefficient scan routines and could only */
+ /* achieve a peak TCK frequency of about 2500 kHz */
+ if (xds110.firmware < FAST_TCK_FIRMWARE_VERSION) {
- if (XDS110_MAX_TCK_SPEED != speed) {
- freq_to_use = speed * 1000; /* Hz */
+ /* Check for request for top speed or higher */
+ if (speed >= XDS110_MAX_SLOW_TCK_SPEED) {
- /* Calculate the delay count value */
- double one_giga = 1000000000;
- /* Get the pulse duration for the maximum frequency supported in ns */
- double max_freq_pulse_duration = one_giga /
- (XDS110_MAX_TCK_SPEED * 1000);
+ /* Inform user that speed was adjusted down to max possible */
+ if (speed > XDS110_MAX_SLOW_TCK_SPEED) {
+ LOG_INFO(
+ "XDS110: reduce speed request: %d kHz to %d kHz maximum",
+ speed, XDS110_MAX_SLOW_TCK_SPEED);
+ speed = XDS110_MAX_SLOW_TCK_SPEED;
+ }
+ delay_count = 0;
- /* Convert frequency to pulse duration */
- double freq_to_pulse_width_in_ns = one_giga / freq_to_use;
+ } else {
- /*
- * Start with the pulse duration for the maximum frequency. Keep
- * decrementing the time added by each count value till the requested
- * frequency pulse is less than the calculated value.
- */
- double current_value = max_freq_pulse_duration;
+ const double XDS110_TCK_PULSE_INCREMENT = 66.0;
+ freq_to_use = speed * 1000; /* Hz */
+ delay_count = 0;
- while (current_value < freq_to_pulse_width_in_ns) {
- current_value += XDS110_TCK_PULSE_INCREMENT;
- ++delay_count;
+ /* Calculate the delay count value */
+ double one_giga = 1000000000;
+ /* Get the pulse duration for the max frequency supported in ns */
+ double max_freq_pulse_duration = one_giga /
+ (XDS110_MAX_SLOW_TCK_SPEED * 1000);
+
+ /* Convert frequency to pulse duration */
+ double freq_to_pulse_width_in_ns = one_giga / freq_to_use;
+
+ /*
+ * Start with the pulse duration for the maximum frequency. Keep
+ * decrementing time added by each count value till the requested
+ * frequency pulse is less than the calculated value.
+ */
+ double current_value = max_freq_pulse_duration;
+
+ while (current_value < freq_to_pulse_width_in_ns) {
+ current_value += XDS110_TCK_PULSE_INCREMENT;
+ ++delay_count;
+ }
+
+ /*
+ * Determine which delay count yields the best match.
+ * The one obtained above or one less.
+ */
+ if (delay_count) {
+ double diff_freq_1 = freq_to_use -
+ (one_giga / (max_freq_pulse_duration +
+ (XDS110_TCK_PULSE_INCREMENT * delay_count)));
+ double diff_freq_2 = (one_giga / (max_freq_pulse_duration +
+ (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) -
+ freq_to_use;
+
+ /* One less count value yields a better match */
+ if (diff_freq_1 > diff_freq_2)
+ --delay_count;
+ }
}
- /*
- * Determine which delay count yields the best match.
- * The one obtained above or one less.
- */
- if (delay_count) {
- double diff_freq_1 = freq_to_use -
- (one_giga / (max_freq_pulse_duration +
- (XDS110_TCK_PULSE_INCREMENT * delay_count)));
- double diff_freq_2 = (one_giga / (max_freq_pulse_duration +
- (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) -
- freq_to_use;
-
- /* One less count value yields a better match */
- if (diff_freq_1 > diff_freq_2)
- --delay_count;
+ /* Newer firmware has reworked TCK routines that are much more efficient */
+ /* and can now achieve a peak TCK frequency of 14000 kHz */
+ } else {
+
+ if (speed >= XDS110_MAX_FAST_TCK_SPEED) {
+ if (speed > XDS110_MAX_FAST_TCK_SPEED) {
+ LOG_INFO(
+ "XDS110: reduce speed request: %d kHz to %d kHz maximum",
+ speed, XDS110_MAX_FAST_TCK_SPEED);
+ speed = XDS110_MAX_FAST_TCK_SPEED;
+ }
+ delay_count = 0;
+ } else if (speed >= 12000 && xds110.firmware >=
+ FAST_TCK_PLUS_FIRMWARE_VERSION) {
+ delay_count = FAST_TCK_DELAY_12000_KHZ;
+ } else if (speed >= 10000 && xds110.firmware >=
+ FAST_TCK_PLUS_FIRMWARE_VERSION) {
+ delay_count = FAST_TCK_DELAY_10000_KHZ;
+ } else if (speed >= 8500) {
+ delay_count = FAST_TCK_DELAY_8500_KHZ;
+ } else if (speed >= 5500) {
+ delay_count = FAST_TCK_DELAY_5500_KHZ;
+ } else {
+ /* Calculate the delay count to set the frequency */
+ /* Formula determined by measuring the waveform on Saeleae logic */
+ /* analyzer using known values for delay count */
+ const double m = 17100000.0; /* slope */
+ const double b = -1.02; /* y-intercept */
+
+ freq_to_use = speed * 1000; /* Hz */
+ double period = 1.0/freq_to_use;
+ double delay = m * period + b;
+
+ if (delay < 1.0)
+ delay_count = 1;
+ else
+ delay_count = (uint32_t)delay;
}
}
return ERROR_OK;
}
-static int_least32_t xds110_swd_frequency(int_least32_t hz)
-{
- if (hz > 0)
- xds110_speed(hz / 1000);
- return hz;
-}
-
COMMAND_HANDLER(xds110_handle_info_command)
{
xds110_show_info();
xds110.serial[i] = (char)serial[i];
xds110.serial[len] = 0;
- } else {
- LOG_ERROR("XDS110: expected exactly one argument to xds110_serial "
- "<serial-number>");
- return ERROR_FAIL;
- }
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_OK;
}
return ERROR_FAIL;
}
xds110.voltage = voltage;
- } else {
- LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage "
- "<millivolts>");
- return ERROR_FAIL;
- }
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_OK;
}
.name = "info",
.handler = &xds110_handle_info_command,
.mode = COMMAND_EXEC,
- .usage = "",
.help = "show XDS110 info",
- },
- COMMAND_REGISTRATION_DONE
-};
-
-static const struct command_registration xds110_command_handlers[] = {
- {
- .name = "xds110",
- .mode = COMMAND_ANY,
- .help = "perform XDS110 management",
- .usage = "<cmd>",
- .chain = xds110_subcommand_handlers,
+ .usage = "",
},
{
- .name = "xds110_serial",
+ .name = "serial",
.handler = &xds110_handle_serial_command,
.mode = COMMAND_CONFIG,
.help = "set the XDS110 probe serial number",
.usage = "serial_string",
},
{
- .name = "xds110_supply_voltage",
+ .name = "supply",
.handler = &xds110_handle_supply_voltage_command,
.mode = COMMAND_CONFIG,
.help = "set the XDS110 probe supply voltage",
- .usage = "supply_voltage (millivolts)",
+ .usage = "voltage_in_millivolts",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration xds110_command_handlers[] = {
+ {
+ .name = "xds110",
+ .mode = COMMAND_ANY,
+ .help = "perform XDS110 management",
+ .usage = "",
+ .chain = xds110_subcommand_handlers,
},
COMMAND_REGISTRATION_DONE
};
static const struct swd_driver xds110_swd_driver = {
.init = xds110_swd_init,
- .frequency = xds110_swd_frequency,
.switch_seq = xds110_swd_switch_seq,
.read_reg = xds110_swd_read_reg,
.write_reg = xds110_swd_write_reg,
static const char * const xds110_transport[] = { "swd", "jtag", NULL };
-struct jtag_interface xds110_interface = {
+static struct jtag_interface xds110_interface = {
+ .execute_queue = xds110_execute_queue,
+};
+
+struct adapter_driver xds110_adapter_driver = {
.name = "xds110",
- .commands = xds110_command_handlers,
- .swd = &xds110_swd_driver,
.transports = xds110_transport,
+ .commands = xds110_command_handlers,
- .execute_queue = xds110_execute_queue,
- .speed = xds110_speed,
- .speed_div = xds110_speed_div,
- .khz = xds110_khz,
.init = xds110_init,
.quit = xds110_quit,
+ .reset = xds110_reset,
+ .speed = xds110_speed,
+ .khz = xds110_khz,
+ .speed_div = xds110_speed_div,
+
+ .jtag_ops = &xds110_interface,
+ .swd_ops = &xds110_swd_driver,
};