adding ft232rl openocd based jtag

This commit is contained in:
David Welch
2012-07-09 02:17:28 -04:00
parent 259ad3212e
commit c40979d68b
6 changed files with 671 additions and 1 deletions

View File

@@ -56,3 +56,42 @@ all the same, going from one computer to another you might have a
problem. Also, real jtag boards have some electronics that protect
you from these differences as well as protect you from say using 3.3v
on 1.8v I/O lines or allow 5V systems to use 5Volts, etc.
UPDATE, I have a couple of lower cost solutions, first for generic
serial or serial to the msp430
http://jim.sh/ftx/
Looking at the documentation on that page I took the ftdi_sio kernel
sources and added the ftx part manually, was pretty easy, the built
the kernel image and used it. Basically my linux is not the latest
greatest-cutting edge ubuntu, so it doesnt have the ftdi mods. All you
are really doing when you modify the driver is adding yet another
ftdi part to the list of devices supported by that driver, many places
where it says if this ftdi part or that ftdi part, or that ftdi part,
you are just adding another to the list.
The possibly more interesting thing is that I have taken an ftdi ft232rl
board
http://www.sparkfun.com/products/718
And using the abitility to bit bang the pins on that device. It is no
longer a serial port, while being bitbanged, the ft232rl does not have
enough stuff in it to do both. So dont hook up the rxd and txd to
your raspi serial port, if you have a second one sure, but the jtag
one is only jtag.
Now it is not super fast, pretty slow in fact, but it is $15 plus some
wire.
Stay tuned, when I solder some pins on an ftx board I am going to try
to bit bang it and use it for jtag, resulting in a sub $10 jtag board.
Also I ordered a $18, supposedly jlink compatible board from china, it
may take a while to arrive.
Eventually you are going to want a faster and designed for jtag board
like the amontec boards or the flyswatter from tin can tools (do not
hook that serial port up to your raspberry pi you will fry the rasberry
pi) or others.

149
jtagproxy/ft232rl/README Normal file
View File

@@ -0,0 +1,149 @@
I have been wanting to do this for a long time and doing some googling
so have others.
Now ARM jtag on the raspberry pi, is not without risk. First some
soldering is required, not trivial soldering, not hard but not trivial.
Then you are connecting things between two boards, if you miscount the
pin numbers on either side you might short something like power to
ground and may melt one or both boards. Third, this jtag solution
does not provide level shifters, nor any isolation. You need to make
sure you have both the raspberry pi and the ftdi breakout board connected
to the same computer, or same usb hub, preferrably ports on the same
card or near each other to insure they use the same ground.
This example is based on this board:
http://www.sparkfun.com/products/718
In addition to being a serial port many of the ftdi usb devices have
a bitbang mode. This one has 8 pins that you can bit bang, ftdi has
an app note, or you can just use trial and error to figure out what bit
goes with what pin.
Now you will have to solder a wire on the raspberry pi to use the
ARM jtag anyway (see the armjtag directory) so you wont have a problem
soldering pins on this ftdi breakout board. The breakout board has
pins labelled, I am using these pins for JTAG.
#define BIT_TXD_TDI 0
#define BIT_DTR_TMS 4
#define BIT_RTS_TCK 2
#define BIT_RXD_TDO 1
TXD, DTR, RTS, RXD are the labels on the ftdi breakout board. TDI,
TMS, TCK, TDO are the JTAG signals provided by those pins. Map that
to the raspberry pi pins
ARM_TDI GPIO_GCLK P1-7 IN ( 4 ALT5)
ARM_TMS CAM_GPIO S5-11 OUT (27 ALT4)
ARM_TCK GPIO_GEN6 P1-22 OUT (25 ALT4)
ARM_TDO GPIO_GEN5 P1-18 OUT (24 ALT4)
P1 pin 7, 22, and 18 and S5 (ribbon connector) pin 11.
For generic ARM jtag you may want these as well which are supported
but I am not necessarily using them as I have other ftdi boards I am
going to try out which dont have more than 4 bitbang pins.
#define BIT_RI__TRST 7
#define BIT_DSR_SRST 5
The raspberry pi does need something tied to TRST for it to work.
ARM_TRST 22 GPIO_GEN3 P1-15 IN (22 ALT4)
TRST is asserted low so tie TRST to 3.3v on the ftdi breakout board.
So first get the openocd sources, in openocd/src/jtag/drivers/ backup
the original parport.c and replace it with the one you find here.
If you use git for the cutting edge openocd sources then the first
step is
./bootstrap
which basically creates the configure script, then
./configure --enable-parport
Now, I didnt take too much time to fix this the right way, you will
get a link error complaining about ftdi_something_something functions.
Dig in and find the Makefile (openocd/src/jtag/Makefile maybe or
openocd/src/jtag/drivers/Makefile, or openocd/src/Makefile, etc) and
change LIB from -ldl to -ldl -lftdi.
You will need the libftdi development files as well
apt-get install libftdi-dev
Keep trying to make
make
the project from the top openocd directory until you see this
openocd.texi:12: @include `version.texi': No such file or directory.
openocd.texi:37: warning: undefined flag: VERSION.
openocd.texi:38: warning: undefined flag: UPDATED.
openocd.texi:58: warning: undefined flag: VERSION.
openocd.texi:59: warning: undefined flag: UPDATED.
I have not figured what to do to make the docs build.
So the src directory will contain an openocd binary. You might want
to do a make install, but since this is a bit of a custom one I have
not I use the path to the binary.
As discussed in the armjtag directory it is much easier if you change
to the directory where you have the programs you want to load, that
way at the openocd prompt you dont need to specify a path it uses
the local directory (to the openocd SERVER). You need to use the
raspi.cfg from this directory when using this ftdi breakout board
(or some other ft232rl device)
cd raspberrypi/blinker01/
/path/to/openocd/src/openocd -f ../jtagproxy/ft232rl/raspi.cfg
If everything is wired up right and powered you should see this:
Info : clock speed 10000 kHz
Info : JTAG tap: raspi.arm tap/device found: 0x07b7617f (mfg: 0x0bf, part: 0x7b76, ver: 0x0)
Info : found ARM1176
In another terminal you can
telnet localhost 4444
and it should respond with something like this
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
>
If you get the > prompt then you can try this command, dont confuse
this prompt with your normal command line prompt, you dont want to be
halting your host computer
> halt
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x800001d3 pc: 0x00008144
Your cpsr and pc will vary.
Oh, right, of course you need to get the armjtag.bin file from the
armjtag directory and boot the raspberry pi using that file as your
kernel.img. The green led will blink if it is running that image.
When you halt the arm the blinking will stop either on or off depending
on when you halted the arm. So long as you have not done anything
to mess up the memory or program counter in openocd you can use
the resume command:
> resume
and it should allow the arm to resume and continue blinking.
See the armjtag directory for more info on loading programs, etc.

443
jtagproxy/ft232rl/parport.c Normal file
View File

@@ -0,0 +1,443 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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 "bitbang.h"
#include <ftdi.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <time.h>
static struct ftdi_context ftdi;
#define BIT_TXD_TDI 0
#define BIT_DTR_TMS 4
#define BIT_RTS_TCK 2
#define BIT_RXD_TDO 1
#define BIT_RI__TRST 7
#define BIT_DSR_SRST 5
/* parallel port cable description
*/
struct cable {
char *name;
uint8_t TDO_MASK; /* status port bit containing current TDO value */
uint8_t TRST_MASK; /* data port bit for TRST */
uint8_t TMS_MASK; /* data port bit for TMS */
uint8_t TCK_MASK; /* data port bit for TCK */
uint8_t TDI_MASK; /* data port bit for TDI */
uint8_t SRST_MASK; /* data port bit for SRST */
uint8_t OUTPUT_INVERT; /* data port bits that should be inverted */
uint8_t INPUT_INVERT; /* status port that should be inverted */
uint8_t PORT_INIT; /* initialize data port with this value */
uint8_t PORT_EXIT; /* de-initialize data port with this value */
uint8_t LED_MASK; /* data port bit for LED */
};
static struct cable cables[] = {
/* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
//{ "jtagproxy", 0x10, 0x01, 0x04, 0x08, 0x02, 0x20, 0x00, 0x00, 0x21, 0x21, 0x00 },
{
"jtagproxyftdi", //name
1<<BIT_RXD_TDO, //tdo
1<<BIT_RI__TRST, //trst
1<<BIT_DTR_TMS, //tms
1<<BIT_RTS_TCK, //tck
1<<BIT_TXD_TDI, //tdi
1<<BIT_DSR_SRST, //srst
0x00, //o_inv
0x00, //i_inv
(1<<BIT_RI__TRST)|(1<<BIT_DSR_SRST), //init
(1<<BIT_RI__TRST)|(1<<BIT_DSR_SRST), //exit
0x00 //led
},
{ "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
{ "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
{ "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
{ "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
{ "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 },
{ "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
{ "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 },
{ "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
{ "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 },
{ "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 },
/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows:
HARD TCK - Target TCK
HARD TMS - Target TMS
HARD TDI - Target TDI
HARD TDO - Target TDO
SOFT TCK - Target TRST
SOFT TDI - Target SRST
*/
{ "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 },
{ NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
/* configuration */
static char *parport_cable;
static uint16_t parport_port;
static bool parport_exit;
//static uint32_t parport_toggling_time_ns = 1000;
//static int wait_states;
/* interface variables
*/
static struct cable *cable;
static uint8_t dataport_value;
static int parport_read(void)
{
int data;
unsigned char x;
int ret;
x=0;
if(ftdi_read_pins(&ftdi,&x)<0)
{
LOG_ERROR("ftdi_read_pins failed");
}
data=x;
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
ret=1;
else
ret=0;
//printf("%u",ret); fflush(stdout);
return(ret);
}
static inline void parport_write_data(void)
{
uint8_t output;
output = dataport_value ^ cable->OUTPUT_INVERT;
if (ftdi_write_data(&ftdi, &output, 1) < 0)
{
LOG_ERROR("ftdi_write_data failed");
}
}
static void parport_write(int tck, int tms, int tdi)
{
//int i = wait_states + 1;
if (tck)
dataport_value |= cable->TCK_MASK;
else
dataport_value &= ~cable->TCK_MASK;
if (tms)
dataport_value |= cable->TMS_MASK;
else
dataport_value &= ~cable->TMS_MASK;
if (tdi)
dataport_value |= cable->TDI_MASK;
else
dataport_value &= ~cable->TDI_MASK;
//while (i-- > 0)
parport_write_data();
}
/* (1) assert or (0) deassert reset lines */
static void parport_reset(int trst, int srst)
{
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
if (trst == 0)
dataport_value |= cable->TRST_MASK;
else if (trst == 1)
dataport_value &= ~cable->TRST_MASK;
if (srst == 0)
dataport_value |= cable->SRST_MASK;
else if (srst == 1)
dataport_value &= ~cable->SRST_MASK;
parport_write_data();
}
/* turn LED on parport adapter on (1) or off (0) */
static void parport_led(int on)
{
if (on)
dataport_value |= cable->LED_MASK;
else
dataport_value &= ~cable->LED_MASK;
parport_write_data();
}
static int parport_speed(int speed)
{
//wait_states = speed;
return ERROR_OK;
}
static int parport_khz(int khz, int *jtag_speed)
{
//if (khz == 0) {
//LOG_DEBUG("RCLK not supported");
//return ERROR_FAIL;
//}
//*jtag_speed = 499999 / (khz * parport_toggling_time_ns);
*jtag_speed = khz;
return ERROR_OK;
}
static int parport_speed_div(int speed, int *khz)
{
//uint32_t denominator = (speed + 1) * parport_toggling_time_ns;
//*khz = (499999 + denominator) / denominator;
*khz = speed;
return ERROR_OK;
}
static struct bitbang_interface parport_bitbang = {
.read = &parport_read,
.write = &parport_write,
.reset = &parport_reset,
.blink = &parport_led,
};
static int parport_init(void)
{
struct cable *cur_cable;
cur_cable = cables;
/* Initialize and find device */
if (ftdi_init(&ftdi) < 0)
{
LOG_ERROR("ftdi_init failed");
return ERROR_JTAG_INIT_FAILED;
}
if (ftdi_usb_open(&ftdi, 0x0403, 0x6001) < 0)
{
LOG_ERROR("ftdi_usb_open failed");
return ERROR_JTAG_INIT_FAILED;
}
if (ftdi_set_bitmode(&ftdi,
(1<<BIT_TXD_TDI )|
(1<<BIT_DTR_TMS )|
(1<<BIT_RTS_TCK )|
(1<<BIT_RI__TRST)|
(1<<BIT_DSR_SRST)
,BITMODE_BITBANG) < 0)
{
LOG_ERROR("ftdi_set_bitmode failed\n");
return ERROR_JTAG_INIT_FAILED;
}
parport_cable = "jtagproxyftdi";
while (cur_cable->name) {
if (strcmp(cur_cable->name, parport_cable) == 0) {
cable = cur_cable;
break;
}
cur_cable++;
}
if (!cable) {
LOG_ERROR("No matching cable found for %s", parport_cable);
return ERROR_JTAG_INIT_FAILED;
}
dataport_value = cable->PORT_INIT;
parport_reset(0, 0);
parport_write(0, 0, 0);
parport_led(1);
bitbang_interface = &parport_bitbang;
return ERROR_OK;
}
static int parport_quit(void)
{
parport_led(0);
if (parport_exit) {
dataport_value = cable->PORT_EXIT;
parport_write_data();
}
if (parport_cable) {
free(parport_cable);
parport_cable = NULL;
}
if (ftdi_set_bitmode(&ftdi, 0xFF, BITMODE_RESET) < 0)
{
LOG_ERROR("ftdi_set_bitmode failed");
}
ftdi_usb_close(&ftdi);
ftdi_deinit(&ftdi);
return ERROR_OK;
}
COMMAND_HANDLER(parport_handle_parport_port_command)
{
if (CMD_ARGC == 1) {
/* only if the port wasn't overwritten by cmdline */
if (parport_port == 0)
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port);
else {
LOG_ERROR("The parport port was already configured!");
return ERROR_FAIL;
}
}
command_print(CMD_CTX, "parport port = 0x%" PRIx16 "", parport_port);
return ERROR_OK;
}
COMMAND_HANDLER(parport_handle_parport_cable_command)
{
if (CMD_ARGC == 0)
return ERROR_OK;
/* only if the cable name wasn't overwritten by cmdline */
if (parport_cable == 0) {
/* REVISIT first verify that it's listed in cables[] ... */
parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char));
strcpy(parport_cable, CMD_ARGV[0]);
}
/* REVISIT it's probably worth returning the current value ... */
return ERROR_OK;
}
COMMAND_HANDLER(parport_handle_write_on_exit_command)
{
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit);
return ERROR_OK;
}
COMMAND_HANDLER(parport_handle_parport_toggling_time_command)
{
//if (CMD_ARGC == 1) {
//uint32_t ns;
//int retval = parse_u32(CMD_ARGV[0], &ns);
//if (ERROR_OK != retval)
//return retval;
//if (ns == 0) {
//LOG_ERROR("0 ns is not a valid parport toggling time");
//return ERROR_FAIL;
//}
//parport_toggling_time_ns = ns;
//retval = jtag_get_speed(&wait_states);
//if (retval != ERROR_OK)
//return retval;
//}
//command_print(CMD_CTX, "parport toggling time = %" PRIu32 " ns",
//parport_toggling_time_ns);
return ERROR_OK;
}
static const struct command_registration parport_command_handlers[] = {
{
.name = "parport_port",
.handler = parport_handle_parport_port_command,
.mode = COMMAND_CONFIG,
.help = "Display the address of the I/O port (e.g. 0x378) "
"or the number of the '/dev/parport' device used. "
"If a parameter is provided, first change that port.",
.usage = "[port_number]",
},
{
.name = "parport_cable",
.handler = parport_handle_parport_cable_command,
.mode = COMMAND_CONFIG,
.help = "Set the layout of the parallel port cable "
"used to connect to the target.",
/* REVISIT there's no way to list layouts we know ... */
.usage = "[layout]",
},
{
.name = "parport_write_on_exit",
.handler = parport_handle_write_on_exit_command,
.mode = COMMAND_CONFIG,
.help = "Configure the parallel driver to write "
"a known value to the parallel interface on exit.",
.usage = "('on'|'off')",
},
{
.name = "parport_toggling_time",
.handler = parport_handle_parport_toggling_time_command,
.mode = COMMAND_CONFIG,
.help = "Displays or assigns how many nanoseconds it "
"takes for the hardware to toggle TCK.",
.usage = "[nanoseconds]",
},
COMMAND_REGISTRATION_DONE
};
struct jtag_interface parport_interface = {
.name = "parport",
.supported = DEBUG_CAP_TMS_SEQ,
.commands = parport_command_handlers,
.init = parport_init,
.quit = parport_quit,
.khz = parport_khz,
.speed_div = parport_speed_div,
.speed = parport_speed,
.execute_queue = bitbang_execute_queue,
};

View File

@@ -0,0 +1,32 @@
interface parport
# Broadcom 2835 on Raspberry Pi
telnet_port 4444
#gdb_port 0
#tcl_port 0
adapter_khz 10000
#jtag_nsrst_delay 400
#jtag_ntrst_delay 400
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME raspi
}
reset_config none
if { [info exists CPU_TAPID ] } {
set _CPU_TAPID $CPU_TAPID
} else {
set _CPU_TAPID 0x07b7617F
}
jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID
set _TARGETNAME $_CHIPNAME.arm
target create $_TARGETNAME arm11 -chain-position $_TARGETNAME

View File

@@ -21,7 +21,7 @@ the original parport.c and replace it with the one you find here.
The serial port itself is hardcoded so you might want to work around
that or at least remember to change it to match your computer/setup.
If you use git for the cutting edge openocde sources then the first
If you use git for the cutting edge openocd sources then the first
step is
./bootstrap

View File

@@ -15,6 +15,13 @@
# ARM_TMS 12/27 CAM_GPIO S5-11 OUT (27 ALT4)
# ARM_GND P1-25
# D2 PD1 PIN_TRST
# D3 PD0 PIN_TDI
# D4 PD4 PIN_TMS
# D5 PC6 PIN_TCK
# D6 PD7 PIN_TDO
# D7 PE6 PIN_SRST
interface parport
# Broadcom 2835 on Raspberry Pi