Adds initial support for Buspirate as Jtag interface --- configure.in | 11 + doc/openocd.texi | 3 + src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/buspirate.c | 981 ++++++++++++++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/interface/buspirate.cfg | 16 + 6 files changed, 1020 insertions(+), 0 deletions(-) create mode 100644 src/jtag/drivers/buspirate.c create mode 100644 tcl/interface/buspirate.cfg
diff --git a/configure.in b/configure.in index 3b0a06d..d93b21a 100644 --- a/configure.in +++ b/configure.in @@ -474,6 +474,10 @@ AC_ARG_ENABLE(arm-jtag-ew, AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]), [build_armjtagew=$enableval], [build_armjtagew=no]) +AC_ARG_ENABLE(buspirate, + AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]), + [build_buspirate=$enableval], [build_buspirate=no]) + AC_ARG_ENABLE(minidriver_dummy, AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]), [build_minidriver_dummy=$enableval], [build_minidriver_dummy=no]) @@ -741,6 +745,12 @@ else AC_DEFINE(BUILD_ARMJTAGEW, 0, [0 if you don't want the ARM-JTAG-EW JTAG driver.]) fi +if test $build_buspirate = yes; then + AC_DEFINE(BUILD_BUSPIRATE, 1, [1 if you want the Buspirate JTAG driver.]) +else + AC_DEFINE(BUILD_BUSPIRATE, 0, [0 if you don't want the Buspirate JTAG driver.]) +fi + #-- Deal with MingW/Cygwin FTD2XX issues if test $is_win32 = yes; then @@ -1035,6 +1045,7 @@ AM_CONDITIONAL(JLINK, test $build_jlink = yes) AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes) AM_CONDITIONAL(RLINK, test $build_rlink = yes) AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes) +AM_CONDITIONAL(BUSPIRATE, test $build_buspirate = yes) AM_CONDITIONAL(USB, test $build_usb = yes) AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes) AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes) diff --git a/doc/openocd.texi b/doc/openocd.texi index 61e39b2..bcf06e7 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -386,6 +386,9 @@ Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form o @item @b{ARM-JTAG-EW} @* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html} + +...@item @b{Buspirate} +...@* Link: @url{http://dangerousprototypes.com} @end itemize @section IBM PC Parallel Printer Port Based diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index d6113c6..0588126 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -64,6 +64,9 @@ endif if ARMJTAGEW DRIVERFILES += arm-jtag-ew.c endif +if BUSPIRATE +DRIVERFILES += buspirate.c +endif noinst_HEADERS = \ bitbang.h \ diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c new file mode 100644 index 0000000..9b7d67e --- /dev/null +++ b/src/jtag/drivers/buspirate.c @@ -0,0 +1,981 @@ +/*************************************************************************** + * Copyright (C) 2010 by Michal Demin * + * based on usbprog.c and arm-jtag-ew.c * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * 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. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/interface.h> +#include <jtag/commands.h> + +#include <termios.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#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); + +static void buspirate_end_state(tap_state_t state); +static void buspirate_state_move(void); +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); + + +#define CMD_UNKOWN 0x00 +#define CMD_PORT_MODE 0x01 +#define CMD_FEATURE 0x02 +#define CMD_READ_ADCS 0x03 +//#define CMD_TAP_SHIFT 0x04 // old protocol +#define CMD_TAP_SHIFT 0x05 +#define CMD_ENTER_OOCD 0x06 +#define CMD_UART_SPEED 0x07 +#define CMD_JTAG_SPEED 0x08 + +enum { + MODE_HIZ=0, + MODE_JTAG=1, // push-pull outputs + MODE_JTAG_OD=2, // open-drain outputs +}; + +enum { + FEATURE_LED=0x01, + FEATURE_VREG=0x02, + FEATURE_TRST=0x04, + FEATURE_SRST=0x08, + FEATURE_PULLUP=0x10 +}; + +enum { + ACTION_DISABLE=0, + ACTION_ENABLE=1 +}; + +enum { + SERIAL_NORMAL=0, + SERIAL_FAST=1 +}; + + +static int buspirate_fd = -1; +static int buspirate_pinmode = MODE_JTAG_OD; +static int buspirate_baudrate = SERIAL_NORMAL; +static int buspirate_vreg = 0; +static int buspirate_pullup = 0; +static char* buspirate_port = NULL; + + +/* TAP interface */ +static void buspirate_tap_init(void); +static int buspirate_tap_execute(void); +static void buspirate_tap_append(int tms, int tdi); +static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); +static void buspirate_tap_make_space(int scan, int bits); + +static void buspirate_reset(int trst, int srst); + +/* low level interface */ +static void buspirate_jtag_reset(int); +static void buspirate_jtag_enable(int); +static unsigned char buspirate_jtag_command(int, char *, int); +static void buspirate_jtag_set_speed(int, char); +static void buspirate_jtag_set_mode(int, char); +static void buspirate_jtag_set_feature(int, char, char); +static void buspirate_jtag_get_adcs(int); + +/* low level HW communication interface */ +static int buspirate_serial_setspeed(int fd, speed_t speed); +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_print_buffer(char* buf, int size); + +static int buspirate_speed(int speed) +{ + // TODO + LOG_INFO("Want to set speed to %dkHz, but not implemented :(", 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) +{ + struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + int scan_size; + enum scan_type type; + uint8_t *buffer; + + while (cmd) + { + switch (cmd->type) + { + case JTAG_RUNTEST: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); +#endif + buspirate_end_state(cmd->cmd.runtest->end_state); + buspirate_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_STATEMOVE: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); +#endif + buspirate_end_state(cmd->cmd.statemove->end_state); + buspirate_state_move(); + break; + case JTAG_PATHMOVE: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); +#endif + buspirate_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); + break; + case JTAG_SCAN: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("scan end in %s", tap_state_name(cmd->cmd.scan->end_state)); +#endif + + buspirate_end_state(cmd->cmd.scan->end_state); + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + buspirate_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); + + break; + case JTAG_RESET: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); +#endif + // flush buffers, so we can reset + buspirate_tap_execute(); + + if (cmd->cmd.reset->trst == 1) + { + tap_set_state(TAP_RESET); + } + buspirate_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_SLEEP: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("sleep %i", cmd->cmd.sleep->us); +#endif + buspirate_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + + cmd = cmd->next; + } + + return buspirate_tap_execute(); +} + +static int buspirate_init(void) +{ + buspirate_print_buffer("", 0); + + if (buspirate_port == NULL) { + buspirate_port = "/dev/ttyUSB0"; + } + + + buspirate_fd = open(buspirate_port, O_RDWR | O_NOCTTY); + if (buspirate_fd == -1) + { + LOG_ERROR("Could not open serial port."); + return ERROR_JTAG_INIT_FAILED; + } + + buspirate_serial_setspeed(buspirate_fd, B115200); + + buspirate_jtag_enable(buspirate_fd); + + if (buspirate_baudrate != SERIAL_NORMAL) { + buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST); + } + + LOG_INFO("Buspirate Interface ready!"); + + buspirate_tap_init(); + buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode); + buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG, (buspirate_vreg==1)?ACTION_ENABLE:ACTION_DISABLE); + buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP, (buspirate_pullup==1)?ACTION_ENABLE:ACTION_DISABLE); + buspirate_reset(0, 0); + + return ERROR_OK; +} + +static int buspirate_quit(void) +{ + LOG_INFO("Shuting down buspirate "); + buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ); + + buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL); + buspirate_jtag_reset(buspirate_fd); + if (buspirate_port) { + free(buspirate_port); + buspirate_port = NULL; + } + return ERROR_OK; +} + +/* openocd command interface */ +COMMAND_HANDLER(buspirate_handle_adc_command) { + if (CMD_ARGC != 0) + { + LOG_ERROR("usage: buspirate_adc"); + return ERROR_OK; + } + + if (buspirate_fd == -1) { + return ERROR_OK; + } + + // send the command + buspirate_jtag_get_adcs(buspirate_fd); + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_vreg_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_vreg <1|0>"); + return ERROR_OK; + } + + if (atoi(CMD_ARGV[0]) == 1) { + buspirate_vreg = 1; + } else { + buspirate_vreg = 0; + } + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_pullup_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_pullup <1|0>"); + return ERROR_OK; + } + + if (atoi(CMD_ARGV[0]) == 1) { + buspirate_pullup = 1; + } else { + buspirate_pullup = 0; + } + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_led_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_led <1|0>"); + return ERROR_OK; + } + + if (atoi(CMD_ARGV[0]) == 1) { + // enable led + buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, ACTION_ENABLE); + } else { + // disable led + buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, ACTION_DISABLE); + } + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_mode_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_mode <normal|open-drain>"); + return ERROR_OK; + } + + if (CMD_ARGV[0][0] == 'n') { + buspirate_pinmode = MODE_JTAG; + } else if (CMD_ARGV[0][0] == 'o') { + buspirate_pinmode = MODE_JTAG_OD; + } else { + LOG_ERROR("usage: buspirate_mode <normal|open-drain>"); + } + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_speed_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_speed <normal|fast>"); + return ERROR_OK; + } + + if (CMD_ARGV[0][0] == 'n') { + buspirate_baudrate = SERIAL_NORMAL; + } else if (CMD_ARGV[0][0] == 'f') { + buspirate_baudrate = SERIAL_FAST; + } else { + LOG_ERROR("usage: buspirate_speed <normal|fast>"); + } + + return ERROR_OK; + +} + +COMMAND_HANDLER(buspirate_handle_port_command) { + if (CMD_ARGC != 1) + { + LOG_ERROR("usage: buspirate_port /dev/ttyUSB0"); + return ERROR_OK; + } + + if (buspirate_port == 0) { + buspirate_port = strdup(CMD_ARGV[0]); + } + + return ERROR_OK; + +} + +static const struct command_registration buspirate_command_handlers[] = { + { + .name = "buspirate_adc", + .handler = &buspirate_handle_adc_command, + .mode = COMMAND_EXEC, + .help = "reads voltages on adc pins", + }, + { + .name = "buspirate_vreg", + .handler = &buspirate_handle_vreg_command, + .mode = COMMAND_CONFIG, + .help = "changes the state of voltage regulators", + }, + { + .name = "buspirate_pullup", + .handler = &buspirate_handle_pullup_command, + .mode = COMMAND_CONFIG, + .help = "changes the state of pullup", + }, + { + .name = "buspirate_led", + .handler = &buspirate_handle_led_command, + .mode = COMMAND_EXEC, + .help = "changes the state of led", + }, + { + .name = "buspirate_speed", + .handler = &buspirate_handle_speed_command, + .mode = COMMAND_CONFIG, + .help = "speed of the interface", + }, + { + .name = "buspirate_mode", + .handler = &buspirate_handle_mode_command, + .mode = COMMAND_CONFIG, + .help = "pin mode of the interface", + }, + { + .name = "buspirate_port", + .handler = &buspirate_handle_port_command, + .mode = COMMAND_CONFIG, + .help = "name of the serial port to open", + }, + COMMAND_REGISTRATION_DONE +}; + +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 +}; + +/*************** jtag execute commands **********************/ +static void buspirate_end_state(tap_state_t state) +{ + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else + { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +static void buspirate_state_move(void) +{ + int i = 0, tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + for (i = 0; i < tms_count; i++) + { + tms = (tms_scan >> i) & 1; + buspirate_tap_append(tms, 0); + } + + tap_set_state(tap_get_end_state()); +} + +static void buspirate_path_move(int num_states, tap_state_t *path) +{ + int i; + + for (i = 0; i< num_states; i++) + { + if (tap_state_transition(tap_get_state(), false) == path[i]) + { + /* LOG_INFO("1"); */ + buspirate_tap_append(0, 0); + } + else if (tap_state_transition(tap_get_state(), true) == path[i]) + { + /* LOG_INFO("2"); */ + buspirate_tap_append(1, 0); + } + else + { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); + exit(-1); + } + + tap_set_state(path[i]); + } + + tap_set_end_state(tap_get_state()); +} + +static void buspirate_runtest(int num_cycles) +{ + int i; + + tap_state_t saved_end_state = tap_get_end_state(); + + /* only do a state_move when we're not already in IDLE */ + if (tap_get_state() != TAP_IDLE) + { + buspirate_end_state(TAP_IDLE); + buspirate_state_move(); + } + + for (i = 0; i < num_cycles; i++) + { + buspirate_tap_append(0, 0); + } + +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("runtest: cur_state %s end_state %s", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state())); +#endif + + /* finish in end_state */ + buspirate_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + { + buspirate_state_move(); + } +} + +static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) +{ + tap_state_t saved_end_state; + + buspirate_tap_make_space(1, scan_size+8); // is 8 correct ? (2 moves = 16) + + saved_end_state = tap_get_end_state(); + + buspirate_end_state(ir_scan?TAP_IRSHIFT:TAP_DRSHIFT); + buspirate_state_move(); + + + /* The adapter does the transition to PAUSE internally */ + if (ir_scan) + tap_set_state(TAP_IRPAUSE); + else + tap_set_state(TAP_DRPAUSE); + + buspirate_tap_append_scan(scan_size, buffer, command); + + /* move to PAUSE */ + buspirate_tap_append(0, 0); + + /* restore the saved state */ + buspirate_end_state(saved_end_state); + tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + + if (tap_get_state() != tap_get_end_state()) + buspirate_state_move(); +} + + +/************************* TAP related stuff **********/ + +#define BUSPIRATE_BUFFER_SIZE 1024 +#define BUSPIRATE_MAX_PENDING_SCANS 32 + +static char tms_chain[BUSPIRATE_BUFFER_SIZE]; // send +static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; // send +//static char tdo_chain[BUSPIRATE_BUFFER_SIZE]; // recv +static int tap_chain_index; + +typedef struct // this was stolen from arm-jtag-ew +{ + int first; /* First bit position in tdo_buffer to read */ + int length; /* Number of bits to read */ + struct scan_command *command; /* Corresponding scan command */ + uint8_t *buffer; +} pending_scan_result_t; + +static pending_scan_result_t tap_pending_scans[BUSPIRATE_MAX_PENDING_SCANS]; +static int tap_pending_scans_num; + +static void buspirate_tap_init(void) { + tap_chain_index = 0; + tap_pending_scans_num = 0; +} + +static int buspirate_tap_execute(void) +{ + char tmp[4096]; + uint8_t *in_buf; + int i; + int fill_index = 0; + int ret; + int bytes_to_send; + + if (tap_chain_index <= 0) + return ERROR_OK; + LOG_DEBUG("executing tap num bits = %i scans = %i", tap_chain_index, tap_pending_scans_num); + + bytes_to_send = (tap_chain_index+7) / 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; + for (i=0; i<bytes_to_send; i++) { + tmp[fill_index] = tdi_chain[i]; + fill_index++; + tmp[fill_index] = tms_chain[i]; + fill_index++; + } + + ret = buspirate_serial_write(buspirate_fd, tmp, 3 + bytes_to_send*2); + if (ret != bytes_to_send*2+3) + { + LOG_ERROR("error writing :("); + return ERROR_JTAG_DEVICE_ERROR; + } +#ifdef DEBUG_SERIAL +fprintf(stderr,"bytes writen %i:\n", ret); +buspirate_print_buffer(tmp, bytes_to_send*2+3); +#endif + + ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + 3); +#ifdef DEBUG_SERIAL +fprintf(stderr,"bytes read %i should have read %i:\n", ret, bytes_to_send + 3); +buspirate_print_buffer(tmp, bytes_to_send+3); +#endif + in_buf = (uint8_t*)(&tmp[3]); + /* parse the scans */ + for (i = 0; i < tap_pending_scans_num; i++) { + uint8_t *buffer = tap_pending_scans[i].buffer; + int length = tap_pending_scans[i].length; + int first = tap_pending_scans[i].first; + struct scan_command *command = tap_pending_scans[i].command; +//LOG_INFO("Parsing scan result [%i] len = %i first = %i bytes:", i, length, first); + + /* copy bits from buffer */ + buf_set_buf(in_buf, first, buffer, 0, length); +//buspirate_print_buffer((char*)buffer, (length+7)/8); + + /* return buffer to higher level */ + if (jtag_read_buffer(buffer, command) != ERROR_OK) + { + buspirate_tap_init(); + return ERROR_JTAG_QUEUE_FAILED; + } + + if (buffer) { + free(buffer); + } + } + tap_pending_scans_num = 0; + tap_chain_index = 0; + return ERROR_OK; +} + +static void buspirate_tap_make_space(int scans, int bits) +{ + int have_scans = BUSPIRATE_MAX_PENDING_SCANS - tap_pending_scans_num; + int have_bits = BUSPIRATE_BUFFER_SIZE * 8 - tap_chain_index; + + if ((have_scans < scans) || (have_bits < bits)) + { + buspirate_tap_execute(); + } +} + +static void buspirate_tap_append(int tms, int tdi) +{ + int index = tap_chain_index / 8; + + if (index < BUSPIRATE_BUFFER_SIZE) + { + int bit_index = tap_chain_index % 8; + uint8_t bit = 1 << bit_index; + + if (tms) + tms_chain[index] |= bit; + else + tms_chain[index] &= ~bit; + + if (tdi) + tdi_chain[index] |= bit; + else + tdi_chain[index] &= ~bit; + + tap_chain_index++; + } + else + { + LOG_ERROR("tap_chain overflow, Bad things will happen"); + } + +} + +static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) +{ + int i; + tap_pending_scans[tap_pending_scans_num].length = length; + tap_pending_scans[tap_pending_scans_num].buffer = buffer; + tap_pending_scans[tap_pending_scans_num].command = command; + tap_pending_scans[tap_pending_scans_num].first = tap_chain_index; +//fprintf(stderr,"adding scan\n"); + for (i = 0; i<length; i++) { + int tms = (i < length-1 ? 0 : 1); + int tdi = (buffer[i/8] >> (i%8)) & 1; + buspirate_tap_append(tms, tdi); + } + tap_pending_scans_num++; +} + +/*************** jtag wrapper functions *********************/ + +/* (1) assert or (0) deassert reset lines */ +static void buspirate_reset(int trst, int srst) +{ + LOG_DEBUG("trst: %i, srst: %i", trst, srst); + + if (trst) + buspirate_jtag_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE); + else + buspirate_jtag_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE); + + if (srst) + buspirate_jtag_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); + else + buspirate_jtag_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); +} + +/*************** jtag lowlevel functions ********************/ +static void buspirate_jtag_enable(int fd) +{ + int ret; + char tmp[21] = { [0 ... 20] = 0x00 }; + int done = 0; + int cmd_sent = 0; + + buspirate_serial_write(fd, tmp, 20); + usleep(10000); + + // reads 1 to x "BBIO1" and one "OCD1" + while (!done) + { + ret = buspirate_serial_read(fd, tmp, 4); +#ifdef DEBUG_SERIAL +fprintf(stderr,"bytes read %i:\n", ret); +buspirate_print_buffer(tmp, ret); +#endif + if (ret != 4) + { + LOG_ERROR("Buspirate did not respond :(( restart everything"); + exit(-1); + } + if (strncmp(tmp, "BBIO", 4)==0) + { + ret = buspirate_serial_read(fd, tmp, 1); +#ifdef DEBUG_SERIAL +fprintf(stderr,"bytes read %i:\n", ret); +buspirate_print_buffer(tmp, ret); +#endif + if (ret != 1) { + LOG_ERROR("Buspirate did not respond well :( restart everything"); + exit(-1); + } + if (tmp[0] != '1') + { + 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); +#ifdef DEBUG_SERIAL +fprintf(stderr,"bytes written %i:\n", ret); +#endif + } + } + else if (strncmp(tmp, "OCD1", 4) == 0) + { + done = 1; + } + else + { + LOG_ERROR("Buspirate did not respond :((( restart everything"); + exit(-1); + } + } + +} + +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); + if (strncmp(tmp, "BBIO1", 5)==0) + { + tmp[0] = 0x0F; // reset BP + buspirate_serial_write(fd, tmp, 1); + } + else + { + LOG_ERROR("Bad reply :( Please restart manually"); + } + +} + +static void buspirate_jtag_set_speed(int fd, char speed) +{ + int ret; + char tmp[2]; + char ack[2]; + speed_t baudrate = B115200; + + ack[0] = 0xAA; + ack[1] = 0x55; + + tmp[0] = CMD_UART_SPEED; + tmp[1] = speed; + buspirate_jtag_command(fd, tmp, 2); + + // here the adapter changes speed, we need follow + if (speed == SERIAL_FAST) { + baudrate = B1000000; + } + buspirate_serial_setspeed(fd, baudrate); + + buspirate_serial_write(fd, ack, 2); + ret = buspirate_serial_read(fd, tmp, 2); + if (ret != 2) { + LOG_ERROR("Buspirate did not respond :(( restart everything"); + exit(-1); + } + if ((tmp[0] != CMD_UART_SPEED) || (tmp[1] != speed)) { + LOG_ERROR("Buspirate didn't reply as expected :(( restart everything"); + exit(-1); + } + LOG_INFO("Buspirate switched to %s mode", (speed==SERIAL_NORMAL)?"normal":"FAST"); +} + + +static void buspirate_jtag_set_mode(int fd, char mode) +{ + char tmp[2]; + tmp[0] = CMD_PORT_MODE; + tmp[1] = mode; + buspirate_jtag_command(fd, tmp, 2); +} + +static void buspirate_jtag_set_feature(int fd, char feat, char action) +{ + char tmp[3]; + tmp[0] = CMD_FEATURE; + tmp[1] = feat; // what + tmp[2] = action; // action + buspirate_jtag_command(fd, tmp, 3); +} + +static void buspirate_jtag_get_adcs(int fd) +{ + uint8_t tmp[10]; + uint16_t a,b,c,d; + tmp[0] = CMD_READ_ADCS; + buspirate_jtag_command(fd, (char*)tmp, 1); + a = tmp[2] << 8 | tmp[3]; + b = tmp[4] << 8 | tmp[5]; + c = tmp[6] << 8 | tmp[7]; + d = tmp[8] << 8 | tmp[9]; + + LOG_INFO("ADC: ADC_Pin = %.02f VPullup = %.02f V33 = %.02f V50 = %.02f", + ((float)a)/155.1515, ((float)b)/155.1515, ((float)c)/155.1515, ((float)d)/155.1515); +} + +static unsigned char buspirate_jtag_command(int buspirate_fd, char *cmd, int cmdlen) +{ + int res; + int len = 0; + + res = buspirate_serial_write(buspirate_fd, cmd, cmdlen); +#ifdef DEBUG_SERIAL +//LOG_INFO("jtag_message %i",(int)cmd[0]); +LOG_INFO("write cmd = %i bytes %i", cmd[0], res); +buspirate_print_buffer(cmd, cmdlen); +#endif + if ((cmd[0] == CMD_UART_SPEED) || (cmd[0] == CMD_PORT_MODE) || (cmd[0] == CMD_FEATURE) || (cmd[0] == CMD_JTAG_SPEED)) + return 1; + + if (res == cmdlen) + { + // LOG_INFO("waiting jtag_message response %i",(int)msg[0]); + switch (cmd[0]) { + case CMD_READ_ADCS: + len = 10; // 2+2*4 + break; + case CMD_TAP_SHIFT: + len = cmdlen; + break; + default: + LOG_INFO("Wrong !"); + } + res = buspirate_serial_read(buspirate_fd, cmd, len); +#ifdef DEBUG_SERIAL +LOG_INFO("read bytes %i should have read %i", res, len); +buspirate_print_buffer(cmd, len); +#endif + if (res > 0) + return (unsigned char)cmd[1]; + else + return -1; + } + else + return -1; + return 0; +} + +/* low level serial port */ +static int buspirate_serial_setspeed(int fd, speed_t speed) { + struct termios t_opt; + + /* set the serial port parameters */ + fcntl(buspirate_fd, F_SETFL, 0); + tcgetattr(buspirate_fd, &t_opt); + cfsetispeed(&t_opt, speed); + cfsetospeed(&t_opt, speed); + 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); + t_opt.c_oflag &= ~OPOST; + t_opt.c_cc[VMIN] = 0; + t_opt.c_cc[VTIME] = 10; + tcflush(buspirate_fd, TCIFLUSH); + tcsetattr(buspirate_fd, TCSANOW, &t_opt); + + return 0; +} + +static int buspirate_serial_write(int fd, char *buf, int size) { + int ret = 0; + + ret = write(fd, buf, size); + + if (ret != size) { + LOG_ERROR("Error sending data"); + } + + return ret; +} + +static int buspirate_serial_read(int fd, char *buf, int size) { + int len = 0; + int ret = 0; + int timeout = 0; + + while (len < size) + { + ret = read(fd, buf+len, size-len); + if (ret == -1) + return -1; + + if (ret == 0) { + timeout ++; + + if (timeout >= 10) + return len; + + continue; + } + + len += ret; + } + + return len; +} + +static void buspirate_print_buffer(char* buf, int size) { + int i; + + for (i = 0 ; i < size; i++) { + fprintf(stderr, "%02X ", ((unsigned char)buf[i]) & 0xff); + } + fprintf(stderr, "\n"); +} diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index f6d8219..8d13a08 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -91,6 +91,9 @@ extern struct jtag_interface rlink_interface; #if BUILD_ARMJTAGEW == 1 extern struct jtag_interface armjtagew_interface; #endif +#if BUILD_BUSPIRATE == 1 +extern struct jtag_interface buspirate_interface; +#endif #endif // standard drivers /** @@ -151,6 +154,9 @@ struct jtag_interface *jtag_interfaces[] = { #if BUILD_ARMJTAGEW == 1 &armjtagew_interface, #endif +#if BUILD_BUSPIRATE == 1 + &buspirate_interface, +#endif #endif // standard drivers NULL, }; diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg new file mode 100644 index 0000000..6573c3d --- /dev/null +++ b/tcl/interface/buspirate.cfg @@ -0,0 +1,16 @@ +# +# Buspirate with OpenOCD support +# +# http://dangerousprototypes.com/category/bus-pirate/ +# + +interface buspirate +buspirate_port /dev/ttyUSB0 # adjust to your needs +buspirate_speed normal # or fast +#buspirate_vreg 0 # or 1 +#buspirate_mode normal # or open-drain +#buspirate_pullup 0 # or 1 + +# this depends on the cable, you are safe with this option +reset_config srst_only + -- 1.6.6.1 _______________________________________________ Openocd-development mailing list Openocd-development@lists.berlios.de https://lists.berlios.de/mailman/listinfo/openocd-development