libftdi/swdptap.c: Use MPSSE Mode for bitbanging SWD.

This commit is contained in:
Uwe Bonnes 2018-05-29 19:33:43 +02:00
parent f3cacba219
commit 992ccf91a9
2 changed files with 67 additions and 38 deletions

View File

@ -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

View File

@ -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);
} }