libftdi/swdptap.c: Use MPSSE Mode for bitbanging SWD.
This commit is contained in:
parent
f3cacba219
commit
992ccf91a9
|
@ -67,5 +67,9 @@ static inline int platform_hwversion(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MPSSE_TDI 2
|
||||||
|
#define MPSSE_TDO 4
|
||||||
|
#define MPSSE_TMS 8
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
* Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,8 +18,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Quick hack for bit-banging SW-DP interface over FT2232.
|
/* MPSSE bit-banging SW-DP interface over FTDI.
|
||||||
* Intended as proof of concept, not for production.
|
* Slow, but usable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -31,72 +31,97 @@
|
||||||
|
|
||||||
static uint8_t olddir = 0;
|
static uint8_t olddir = 0;
|
||||||
|
|
||||||
|
#define MPSSE_MASK (MPSSE_TDI | MPSSE_TDO | MPSSE_TMS)
|
||||||
|
#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO)
|
||||||
|
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
|
||||||
|
MPSSE_BITMODE | MPSSE_WRITE_NEG)
|
||||||
|
|
||||||
|
#define MPSSE_TMS_IN_PORT GET_BITS_LOW
|
||||||
|
#define MPSSE_TMS_IN_PIN MPSSE_TMS
|
||||||
|
|
||||||
int swdptap_init(void)
|
int swdptap_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err = ftdi_usb_purge_buffers(ftdic);
|
||||||
|
if (err != 0) {
|
||||||
assert(ftdic != NULL);
|
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
||||||
|
err, ftdi_get_error_string(ftdic));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
/* Reset MPSSE controller. */
|
/* Reset MPSSE controller. */
|
||||||
if((err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET)) != 0) {
|
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||||
|
if (err != 0) {
|
||||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||||
err, ftdi_get_error_string(ftdic));
|
err, ftdi_get_error_string(ftdic));
|
||||||
abort();
|
return -1;;
|
||||||
}
|
}
|
||||||
|
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||||
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG)) != 0) {
|
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||||
|
if (err != 0) {
|
||||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||||
err, ftdi_get_error_string(ftdic));
|
err, ftdi_get_error_string(ftdic));
|
||||||
abort();
|
return -1;;
|
||||||
}
|
}
|
||||||
|
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
|
||||||
assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2);
|
SET_BITS_HIGH, 0,0};
|
||||||
olddir = 0;
|
ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK;
|
||||||
|
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||||
|
ftdi_init[7]= active_cable->cbus_data;
|
||||||
|
ftdi_init[8]= active_cable->cbus_ddr;
|
||||||
|
platform_buffer_write(ftdi_init, 9);
|
||||||
|
platform_buffer_flush();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swdptap_turnaround(uint8_t dir)
|
static void swdptap_turnaround(uint8_t dir)
|
||||||
{
|
{
|
||||||
platform_buffer_flush();
|
|
||||||
|
|
||||||
if (dir == olddir)
|
if (dir == olddir)
|
||||||
return;
|
return;
|
||||||
olddir = dir;
|
olddir = dir;
|
||||||
|
uint8_t cmd[6];
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
if(dir) /* SWDIO goes to input */
|
if(dir) { /* SWDIO goes to input */
|
||||||
assert(ftdi_set_bitmode(ftdic, 0xA3, BITMODE_BITBANG) == 0);
|
cmd[index++] = SET_BITS_LOW;
|
||||||
|
cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
|
||||||
|
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK;
|
||||||
|
}
|
||||||
/* One clock cycle */
|
/* One clock cycle */
|
||||||
ftdi_write_data(ftdic, (void *)"\xAB\xA8", 2);
|
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||||
|
cmd[index++] = 0;
|
||||||
if(!dir) /* SWDIO goes to output */
|
cmd[index++] = 0;
|
||||||
assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 0);
|
if (!dir) {
|
||||||
|
cmd[index++] = SET_BITS_LOW;
|
||||||
|
cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
|
||||||
|
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||||
|
}
|
||||||
|
platform_buffer_write(cmd, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool swdptap_bit_in(void)
|
bool swdptap_bit_in(void)
|
||||||
{
|
{
|
||||||
uint8_t ret;
|
|
||||||
|
|
||||||
swdptap_turnaround(1);
|
swdptap_turnaround(1);
|
||||||
|
uint8_t cmd[4];
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
ftdi_read_pins(ftdic, &ret);
|
cmd[index++] = MPSSE_TMS_IN_PORT;
|
||||||
ret &= 0x08;
|
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||||
ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2);
|
cmd[index++] = 0;
|
||||||
|
cmd[index++] = 0;
|
||||||
return ret;
|
platform_buffer_write(cmd, index);
|
||||||
|
uint8_t data[1];
|
||||||
|
platform_buffer_read(data, 1);
|
||||||
|
return (data[0] &= MPSSE_TMS_IN_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swdptap_bit_out(bool val)
|
void swdptap_bit_out(bool val)
|
||||||
{
|
{
|
||||||
uint8_t buf[3] = "\xA0\xA1\xA0";
|
|
||||||
|
|
||||||
swdptap_turnaround(0);
|
swdptap_turnaround(0);
|
||||||
|
uint8_t cmd[3];
|
||||||
|
|
||||||
if (val) {
|
cmd[0] = MPSSE_TMS_SHIFT;
|
||||||
for(int i = 0; i < 3; i++)
|
cmd[1] = 0;
|
||||||
buf[i] |= 0x08;
|
cmd[2] = (val)? 1 : 0;
|
||||||
}
|
platform_buffer_write(cmd, 3);
|
||||||
platform_buffer_write(buf, 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue