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;
}
#define MPSSE_TDI 2
#define MPSSE_TDO 4
#define MPSSE_TMS 8
#endif

View File

@ -1,7 +1,7 @@
/*
* 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>
*
* 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/>.
*/
/* Quick hack for bit-banging SW-DP interface over FT2232.
* Intended as proof of concept, not for production.
/* MPSSE bit-banging SW-DP interface over FTDI.
* Slow, but usable.
*/
#include <stdio.h>
@ -31,72 +31,97 @@
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 err;
assert(ftdic != NULL);
int err = ftdi_usb_purge_buffers(ftdic);
if (err != 0) {
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
}
/* 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",
err, ftdi_get_error_string(ftdic));
abort();
return -1;;
}
if((err = ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG)) != 0) {
/* Enable MPSSE controller. Pin directions are set later.*/
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
if (err != 0) {
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
return -1;;
}
assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2);
olddir = 0;
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
SET_BITS_HIGH, 0,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;
}
static void swdptap_turnaround(uint8_t dir)
{
platform_buffer_flush();
if (dir == olddir)
return;
olddir = dir;
uint8_t cmd[6];
int index = 0;
if(dir) /* SWDIO goes to input */
assert(ftdi_set_bitmode(ftdic, 0xA3, BITMODE_BITBANG) == 0);
if(dir) { /* SWDIO goes to input */
cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK;
}
/* One clock cycle */
ftdi_write_data(ftdic, (void *)"\xAB\xA8", 2);
if(!dir) /* SWDIO goes to output */
assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 0);
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
cmd[index++] = 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)
{
uint8_t ret;
swdptap_turnaround(1);
uint8_t cmd[4];
int index = 0;
ftdi_read_pins(ftdic, &ret);
ret &= 0x08;
ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2);
return ret;
cmd[index++] = MPSSE_TMS_IN_PORT;
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
cmd[index++] = 0;
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)
{
uint8_t buf[3] = "\xA0\xA1\xA0";
swdptap_turnaround(0);
uint8_t cmd[3];
if (val) {
for(int i = 0; i < 3; i++)
buf[i] |= 0x08;
}
platform_buffer_write(buf, 3);
cmd[0] = MPSSE_TMS_SHIFT;
cmd[1] = 0;
cmd[2] = (val)? 1 : 0;
platform_buffer_write(cmd, 3);
}