X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fbuspirate.c;h=aa0d8cc3f8c057540ec9b514205a113feda91b68;hp=a360d2304287bbff5fdf7786fbbe061c2bba3f1c;hb=cc2d4f015f72d7c30d613b50572eb9f31fac515a;hpb=5d987bca9cc24056e0e2529e2f6446e7b0e30a15
diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c
index a360d23042..aa0d8cc3f8 100644
--- a/src/jtag/drivers/buspirate.c
+++ b/src/jtag/drivers/buspirate.c
@@ -1,6 +1,7 @@
/***************************************************************************
* Copyright (C) 2010 by Michal Demin *
* based on usbprog.c and arm-jtag-ew.c *
+ * Several fixes by R. Diez in 2013. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -13,9 +14,7 @@
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * along with this program. If not, see . *
***************************************************************************/
#ifdef HAVE_CONFIG_H
@@ -32,8 +31,6 @@
#undef DEBUG_SERIAL
/*#define DEBUG_SERIAL */
static int buspirate_execute_queue(void);
-static int buspirate_speed(int speed);
-static int buspirate_khz(int khz, int *jtag_speed);
static int buspirate_init(void);
static int buspirate_quit(void);
@@ -43,7 +40,7 @@ static void buspirate_path_move(int num_states, tap_state_t *path);
static void buspirate_runtest(int num_cycles);
static void buspirate_scan(bool ir_scan, enum scan_type type,
uint8_t *buffer, int scan_size, struct scan_command *command);
-
+static void buspirate_stableclocks(int num_cycles);
#define CMD_UNKNOWN 0x00
#define CMD_PORT_MODE 0x01
@@ -84,6 +81,8 @@ enum {
SERIAL_FAST = 1
};
+static const cc_t SHORT_TIMEOUT = 1; /* Must be at least 1. */
+static const cc_t NORMAL_TIMEOUT = 10;
static int buspirate_fd = -1;
static int buspirate_pinmode = MODE_JTAG_OD;
@@ -92,6 +91,8 @@ static int buspirate_vreg;
static int buspirate_pullup;
static char *buspirate_port;
+static enum tap_state last_tap_state = TAP_RESET;
+
/* TAP interface */
static void buspirate_tap_init(void);
@@ -114,25 +115,12 @@ static void buspirate_jtag_get_adcs(int);
/* low level HW communication interface */
static int buspirate_serial_open(char *port);
-static int buspirate_serial_setspeed(int fd, char speed);
+static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout);
static int buspirate_serial_write(int fd, char *buf, int size);
static int buspirate_serial_read(int fd, char *buf, int size);
static void buspirate_serial_close(int fd);
static void buspirate_print_buffer(char *buf, int size);
-static int buspirate_speed(int speed)
-{
- /* TODO */
- LOG_INFO("Want to set speed to %dkHz, but not implemented yet", speed);
- return ERROR_OK;
-}
-
-static int buspirate_khz(int khz, int *jtag_speed)
-{
- *jtag_speed = khz;
- return ERROR_OK;
-}
-
static int buspirate_execute_queue(void)
{
/* currently processed command */
@@ -203,6 +191,10 @@ static int buspirate_execute_queue(void)
buspirate_tap_execute();
jtag_sleep(cmd->cmd.sleep->us);
break;
+ case JTAG_STABLECLOCKS:
+ DEBUG_JTAG_IO("stable clock %i cycles", cmd->cmd.stableclocks->num_cycles);
+ buspirate_stableclocks(cmd->cmd.stableclocks->num_cycles);
+ break;
default:
LOG_ERROR("BUG: unknown JTAG command type encountered");
exit(-1);
@@ -214,20 +206,94 @@ static int buspirate_execute_queue(void)
return buspirate_tap_execute();
}
+
+/* Returns true if successful, false if error. */
+
+static bool read_and_discard_all_data(const int fd)
+{
+ /* LOG_INFO("Discarding any stale data from a previous connection..."); */
+
+ bool was_msg_already_printed = false;
+
+ for ( ; ; ) {
+ char buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */
+
+ const ssize_t read_count = read(fd, buffer, sizeof(buffer));
+
+ if (read_count == 0) {
+ /* This is the "end of file" or "connection closed at the other end" condition. */
+ return true;
+ }
+
+ if (read_count > 0) {
+ if (!was_msg_already_printed) {
+ LOG_INFO("Some stale data from a previous connection was discarded.");
+ was_msg_already_printed = true;
+ }
+
+ continue;
+ }
+
+ assert(read_count == -1); /* According to the specification. */
+
+ const int errno_code = errno;
+
+ if (errno_code == EINTR)
+ continue;
+
+ if (errno_code == EAGAIN ||
+ errno_code == EWOULDBLOCK) {
+ /* We know that the file descriptor has been opened with O_NONBLOCK or O_NDELAY,
+ and these codes mean that there is no data to read at present. */
+ return true;
+ }
+
+ /* Some other error has occurred. */
+ return false;
+ }
+}
+
+
static int buspirate_init(void)
{
if (buspirate_port == NULL) {
- LOG_ERROR("You need to specify port !");
+ LOG_ERROR("You need to specify the serial port!");
return ERROR_JTAG_INIT_FAILED;
}
buspirate_fd = buspirate_serial_open(buspirate_port);
if (buspirate_fd == -1) {
- LOG_ERROR("Could not open serial port.");
+ LOG_ERROR("Could not open serial port");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* The Operating System or the device itself may deliver stale data from the last connection,
+ so discard all available bytes right after the new connection has been established.
+ After all, we are implementing here a master/slave protocol, so the slave should have nothing
+ to say until the master sends the first command.
+
+ In the past, there was a tcflush() call in buspirate_serial_setspeed(), but that
+ was not enough. I guess you must actively read from the serial port to trigger any
+ data collection from the device and/or lower USB layers. If you disable the serial port
+ read timeout (if you set SHORT_TIMEOUT to 0), then the discarding does not work any more.
+
+ Note that we are lowering the serial port timeout for this first read operation,
+ otherwise the normal initialisation would be delayed for too long. */
+
+ if (-1 == buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL, SHORT_TIMEOUT)) {
+ LOG_ERROR("Error configuring the serial port.");
return ERROR_JTAG_INIT_FAILED;
}
- buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL);
+ if (!read_and_discard_all_data(buspirate_fd)) {
+ LOG_ERROR("Error while attempting to discard any stale data right after establishing the connection.");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (-1 == buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL, NORMAL_TIMEOUT)) {
+ LOG_ERROR("Error configuring the serial port.");
+ return ERROR_JTAG_INIT_FAILED;
+ }
buspirate_jtag_enable(buspirate_fd);
@@ -249,7 +315,7 @@ static int buspirate_init(void)
static int buspirate_quit(void)
{
- LOG_INFO("Shuting down buspirate ");
+ LOG_INFO("Shutting down buspirate.");
buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ);
buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL);
@@ -279,10 +345,8 @@ COMMAND_HANDLER(buspirate_handle_adc_command)
COMMAND_HANDLER(buspirate_handle_vreg_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_vreg <1|0>");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (atoi(CMD_ARGV[0]) == 1)
buspirate_vreg = 1;
@@ -297,10 +361,8 @@ COMMAND_HANDLER(buspirate_handle_vreg_command)
COMMAND_HANDLER(buspirate_handle_pullup_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_pullup <1|0>");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (atoi(CMD_ARGV[0]) == 1)
buspirate_pullup = 1;
@@ -315,10 +377,8 @@ COMMAND_HANDLER(buspirate_handle_pullup_command)
COMMAND_HANDLER(buspirate_handle_led_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_led <1|0>");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (atoi(CMD_ARGV[0]) == 1) {
/* enable led */
@@ -338,10 +398,8 @@ COMMAND_HANDLER(buspirate_handle_led_command)
COMMAND_HANDLER(buspirate_handle_mode_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_mode ");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (CMD_ARGV[0][0] == 'n')
buspirate_pinmode = MODE_JTAG;
@@ -356,10 +414,8 @@ COMMAND_HANDLER(buspirate_handle_mode_command)
COMMAND_HANDLER(buspirate_handle_speed_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_speed ");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (CMD_ARGV[0][0] == 'n')
buspirate_baudrate = SERIAL_NORMAL;
@@ -374,10 +430,8 @@ COMMAND_HANDLER(buspirate_handle_speed_command)
COMMAND_HANDLER(buspirate_handle_port_command)
{
- if (CMD_ARGC < 1) {
- LOG_ERROR("usage: buspirate_port /dev/ttyUSB0");
- return ERROR_OK;
- }
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
if (buspirate_port == NULL)
buspirate_port = strdup(CMD_ARGV[0]);
@@ -395,36 +449,42 @@ static const struct command_registration buspirate_command_handlers[] = {
},
{
.name = "buspirate_vreg",
+ .usage = "<1|0>",
.handler = &buspirate_handle_vreg_command,
.mode = COMMAND_CONFIG,
.help = "changes the state of voltage regulators",
},
{
.name = "buspirate_pullup",
+ .usage = "<1|0>",
.handler = &buspirate_handle_pullup_command,
.mode = COMMAND_CONFIG,
.help = "changes the state of pullup",
},
{
.name = "buspirate_led",
+ .usage = "<1|0>",
.handler = &buspirate_handle_led_command,
.mode = COMMAND_EXEC,
.help = "changes the state of led",
},
{
.name = "buspirate_speed",
+ .usage = "",
.handler = &buspirate_handle_speed_command,
.mode = COMMAND_CONFIG,
.help = "speed of the interface",
},
{
.name = "buspirate_mode",
+ .usage = "",
.handler = &buspirate_handle_mode_command,
.mode = COMMAND_CONFIG,
.help = "pin mode of the interface",
},
{
.name = "buspirate_port",
+ .usage = "/dev/ttyUSB0",
.handler = &buspirate_handle_port_command,
.mode = COMMAND_CONFIG,
.help = "name of the serial port to open",
@@ -435,8 +495,6 @@ static const struct command_registration buspirate_command_handlers[] = {
struct jtag_interface buspirate_interface = {
.name = "buspirate",
.execute_queue = buspirate_execute_queue,
- .speed = buspirate_speed,
- .khz = buspirate_khz,
.commands = buspirate_command_handlers,
.init = buspirate_init,
.quit = buspirate_quit
@@ -529,7 +587,10 @@ static void buspirate_scan(bool ir_scan, enum scan_type type,
saved_end_state = tap_get_end_state();
buspirate_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
- buspirate_state_move();
+
+ /* Only move if we're not already there */
+ if (tap_get_state() != tap_get_end_state())
+ buspirate_state_move();
buspirate_tap_append_scan(scan_size, buffer, command);
@@ -544,11 +605,33 @@ static void buspirate_scan(bool ir_scan, enum scan_type type,
buspirate_state_move();
}
+static void buspirate_stableclocks(int num_cycles)
+{
+ int i;
+ int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
+
+ buspirate_tap_make_space(0, num_cycles);
+
+ for (i = 0; i < num_cycles; i++)
+ buspirate_tap_append(tms, 0);
+}
/************************* TAP related stuff **********/
+/* This buffer size matches the maximum CMD_TAP_SHIFT bit length in the Bus Pirate firmware,
+ look for constant 0x2000 in OpenOCD.c . */
#define BUSPIRATE_BUFFER_SIZE 1024
-#define BUSPIRATE_MAX_PENDING_SCANS 32
+
+/* The old value of 32 scans was not enough to achieve near 100% utilisation ratio
+ for the current BUSPIRATE_BUFFER_SIZE value of 1024.
+ With 128 scans I am getting full USB 2.0 high speed packets (512 bytes long) when
+ using the JtagDue firmware on the Arduino Due instead of the Bus Pirate, which
+ amounts approximately to a 10% overall speed gain. Bigger packets should also
+ benefit the Bus Pirate, but the speed difference is much smaller.
+ Unfortunately, each 512-byte packet is followed by a 329-byte one, which is not ideal.
+ However, increasing BUSPIRATE_BUFFER_SIZE for the benefit of the JtagDue would
+ make it incompatible with the Bus Pirate firmware. */
+#define BUSPIRATE_MAX_PENDING_SCANS 128
static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
@@ -574,6 +657,8 @@ static void buspirate_tap_init(void)
static int buspirate_tap_execute(void)
{
+ static const int CMD_TAP_SHIFT_HEADER_LEN = 3;
+
char tmp[4096];
uint8_t *in_buf;
int i;
@@ -587,13 +672,13 @@ static int buspirate_tap_execute(void)
LOG_DEBUG("executing tap num bits = %i scans = %i",
tap_chain_index, tap_pending_scans_num);
- bytes_to_send = (tap_chain_index+7) / 8;
+ bytes_to_send = DIV_ROUND_UP(tap_chain_index, 8);
tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */
tmp[1] = (char)(tap_chain_index >> 8); /* high */
tmp[2] = (char)(tap_chain_index); /* low */
- fill_index = 3;
+ fill_index = CMD_TAP_SHIFT_HEADER_LEN;
for (i = 0; i < bytes_to_send; i++) {
tmp[fill_index] = tdi_chain[i];
fill_index++;
@@ -601,14 +686,26 @@ static int buspirate_tap_execute(void)
fill_index++;
}
- ret = buspirate_serial_write(buspirate_fd, tmp, 3 + bytes_to_send*2);
- if (ret != bytes_to_send*2+3) {
+ /* jlink.c calls the routine below, which may be useful for debugging purposes.
+ For example, enabling this allows you to compare the log outputs from jlink.c
+ and from this module for JTAG development or troubleshooting purposes. */
+ if (false) {
+ last_tap_state = jtag_debug_state_machine(tms_chain, tdi_chain,
+ tap_chain_index, last_tap_state);
+ }
+
+ ret = buspirate_serial_write(buspirate_fd, tmp, CMD_TAP_SHIFT_HEADER_LEN + bytes_to_send*2);
+ if (ret != bytes_to_send*2+CMD_TAP_SHIFT_HEADER_LEN) {
LOG_ERROR("error writing :(");
return ERROR_JTAG_DEVICE_ERROR;
}
- ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + 3);
- in_buf = (uint8_t *)(&tmp[3]);
+ ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + CMD_TAP_SHIFT_HEADER_LEN);
+ if (ret != bytes_to_send + CMD_TAP_SHIFT_HEADER_LEN) {
+ LOG_ERROR("error reading");
+ return ERROR_FAIL;
+ }
+ in_buf = (uint8_t *)(&tmp[CMD_TAP_SHIFT_HEADER_LEN]);
/* parse the scans */
for (i = 0; i < tap_pending_scans_num; i++) {
@@ -628,8 +725,7 @@ static int buspirate_tap_execute(void)
free(buffer);
}
- tap_pending_scans_num = 0;
- tap_chain_index = 0;
+ buspirate_tap_init();
return ERROR_OK;
}
@@ -653,6 +749,19 @@ static void buspirate_tap_append(int tms, int tdi)
int bit_index = tap_chain_index % 8;
uint8_t bit = 1 << bit_index;
+ if (0 == bit_index) {
+ /* Let's say that the TAP shift operation wants to shift 9 bits,
+ so we will be sending to the Bus Pirate a bit count of 9 but still
+ full 16 bits (2 bytes) of shift data.
+ If we don't clear all bits at this point, the last 7 bits will contain
+ random data from the last buffer contents, which is not pleasant to the eye.
+ Besides, the Bus Pirate (or some clone) may want to assert in debug builds
+ that, after consuming all significant data bits, the rest of them are zero.
+ Therefore, for aesthetic and for assert purposes, we clear all bits below. */
+ tms_chain[chain_index] = 0;
+ tdi_chain[chain_index] = 0;
+ }
+
if (tms)
tms_chain[chain_index] |= bit;
else
@@ -664,9 +773,13 @@ static void buspirate_tap_append(int tms, int tdi)
tdi_chain[chain_index] &= ~bit;
tap_chain_index++;
- } else
- LOG_ERROR("tap_chain overflow, Bad things will happen");
-
+ } else {
+ LOG_ERROR("tap_chain overflow, bad things will happen");
+ /* Exit abruptly, like jlink.c does. After a buffer overflow we don't want
+ to carry on, as data will be corrupt. Another option would be to return
+ some error code at this point. */
+ exit(-1);
+ }
}
static void buspirate_tap_append_scan(int length, uint8_t *buffer,
@@ -724,30 +837,34 @@ static void buspirate_jtag_enable(int fd)
while (!done) {
ret = buspirate_serial_read(fd, tmp, 4);
if (ret != 4) {
- LOG_ERROR("Buspirate error. Is is binary/"
+ LOG_ERROR("Buspirate error. Is binary"
"/OpenOCD support enabled?");
exit(-1);
}
if (strncmp(tmp, "BBIO", 4) == 0) {
ret = buspirate_serial_read(fd, tmp, 1);
if (ret != 1) {
- LOG_ERROR("Buspirate did not correctly! "
+ LOG_ERROR("Buspirate did not answer correctly! "
"Do you have correct firmware?");
exit(-1);
}
if (tmp[0] != '1') {
- LOG_ERROR("Unsupported binary protocol ");
+ LOG_ERROR("Unsupported binary protocol");
exit(-1);
}
if (cmd_sent == 0) {
cmd_sent = 1;
tmp[0] = CMD_ENTER_OOCD;
ret = buspirate_serial_write(fd, tmp, 1);
+ if (ret != 1) {
+ LOG_ERROR("error reading");
+ exit(-1);
+ }
}
} else if (strncmp(tmp, "OCD1", 4) == 0)
done = 1;
else {
- LOG_ERROR("Buspirate did not correctly! "
+ LOG_ERROR("Buspirate did not answer correctly! "
"Do you have correct firmware?");
exit(-1);
}
@@ -757,13 +874,13 @@ static void buspirate_jtag_enable(int fd)
static void buspirate_jtag_reset(int fd)
{
- int ret;
char tmp[5];
tmp[0] = 0x00; /* exit OCD1 mode */
buspirate_serial_write(fd, tmp, 1);
usleep(10000);
- ret = buspirate_serial_read(fd, tmp, 5);
+ /* We ignore the return value here purposly, nothing we can do */
+ buspirate_serial_read(fd, tmp, 5);
if (strncmp(tmp, "BBIO1", 5) == 0) {
tmp[0] = 0x0F; /* reset BP */
buspirate_serial_write(fd, tmp, 1);
@@ -785,7 +902,10 @@ static void buspirate_jtag_set_speed(int fd, char speed)
buspirate_jtag_command(fd, tmp, 2);
/* here the adapter changes speed, we need follow */
- buspirate_serial_setspeed(fd, speed);
+ if (-1 == buspirate_serial_setspeed(fd, speed, NORMAL_TIMEOUT)) {
+ LOG_ERROR("Error configuring the serial port.");
+ exit(-1);
+ }
buspirate_serial_write(fd, ack, 2);
ret = buspirate_serial_read(fd, tmp, 2);
@@ -794,7 +914,7 @@ static void buspirate_jtag_set_speed(int fd, char speed)
exit(-1);
}
if ((tmp[0] != CMD_UART_SPEED) || (tmp[1] != speed)) {
- LOG_ERROR("Buspirate didn't reply as expected");
+ LOG_ERROR("Buspirate did not reply as expected to the speed change command");
exit(-1);
}
LOG_INFO("Buspirate switched to %s mode",
@@ -880,28 +1000,50 @@ static int buspirate_serial_open(char *port)
return fd;
}
-static int buspirate_serial_setspeed(int fd, char speed)
+
+/* Returns -1 on error. */
+
+static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout)
{
struct termios t_opt;
speed_t baud = (speed == SERIAL_FAST) ? B1000000 : B115200;
/* set the serial port parameters */
fcntl(fd, F_SETFL, 0);
- tcgetattr(fd, &t_opt);
- cfsetispeed(&t_opt, baud);
- cfsetospeed(&t_opt, baud);
+ if (0 != tcgetattr(fd, &t_opt))
+ return -1;
+
+ if (0 != cfsetispeed(&t_opt, baud))
+ return -1;
+
+ if (0 != cfsetospeed(&t_opt, baud))
+ return -1;
+
t_opt.c_cflag |= (CLOCAL | CREAD);
t_opt.c_cflag &= ~PARENB;
t_opt.c_cflag &= ~CSTOPB;
t_opt.c_cflag &= ~CSIZE;
t_opt.c_cflag |= CS8;
t_opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- t_opt.c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ /* The serial port may have been configured for human interaction with
+ the Bus Pirate console, but OpenOCD is going to use a binary protocol,
+ so make sure to turn off any CR/LF translation and the like. */
+ t_opt.c_iflag &= ~(IXON | IXOFF | IXANY | INLCR | ICRNL);
+
t_opt.c_oflag &= ~OPOST;
t_opt.c_cc[VMIN] = 0;
- t_opt.c_cc[VTIME] = 10;
- tcflush(fd, TCIFLUSH);
- tcsetattr(fd, TCSANOW, &t_opt);
+ t_opt.c_cc[VTIME] = timeout;
+
+ /* Note that, in the past, TCSANOW was used below instead of TCSADRAIN,
+ and CMD_UART_SPEED did not work properly then, at least with
+ the Bus Pirate v3.5 (USB). */
+ if (0 != tcsetattr(fd, TCSADRAIN, &t_opt)) {
+ /* According to the Linux documentation, this is actually not enough
+ to detect errors, you need to call tcgetattr() and check that
+ all changes have been performed successfully. */
+ return -1;
+ }
return 0;
}
@@ -979,8 +1121,6 @@ static void buspirate_print_buffer(char *buf, int size)
}
}
- if (line[0] != 0) {
+ if (line[0] != 0)
LOG_DEBUG("%s", line);
- }
}
-