diff --git a/README.md b/README.md index f187c92..dbaddf4 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ __Supported cables:__ * anlogic JTAG adapter * [digilent_hs2](https://store.digilentinc.com/jtag-hs2-programming-cable/): jtag programmer cable from digilent * [DirtyJTAG](https://github.com/jeanthom/DirtyJTAG): JTAG probe firmware for STM32F1 + (Best to use release (1.4 or newer) or limit the --freq to 600000 with older releases. New version https://github.com/jeanthom/DirtyJTAG/tree/dirtyjtag2 is also supported) * Intel USB Blaster: jtag programmer cable from intel/altera * JTAG-HS3: jtag programmer cable from digilent * FT2232: generic programmer cable based on Ftdi FT2232 diff --git a/src/dirtyJtag.cpp b/src/dirtyJtag.cpp index d7512f4..b0a2e18 100644 --- a/src/dirtyJtag.cpp +++ b/src/dirtyJtag.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "dirtyJtag.hpp" #include "display.hpp" @@ -32,9 +33,11 @@ using namespace std; #define DIRTYJTAG_VID 0x1209 #define DIRTYJTAG_PID 0xC0CA +#define DIRTYJTAG_INTF 0 #define DIRTYJTAG_WRITE_EP 0x01 #define DIRTYJTAG_READ_EP 0x82 + enum dirtyJtagCmd { CMD_STOP = 0x00, CMD_INFO = 0x01, @@ -45,6 +48,21 @@ enum dirtyJtagCmd { CMD_CLK = 0x06 }; +//Modifiers applicable only to DirtyJTAG2 +enum CommandModifier { + EXTEND_LENGTH = 0x40, + NO_READ = 0x80 +}; + +struct version_specific +{ + uint8_t no_read; //command modifer for xfer no read + uint16_t max_bits; //max bit count that can be transferred +}; + +static version_specific v_options[4] ={{0, 240}, {0, 240}, {NO_READ, 496}, {NO_READ, 4000}}; + + enum dirtyJtagSig { SIG_TCK = (1 << 1), SIG_TDI = (1 << 2), @@ -71,14 +89,17 @@ DirtyJtag::DirtyJtag(uint32_t clkHZ, bool verbose): throw std::exception(); } - ret = libusb_claim_interface(dev_handle, 0); + ret = libusb_claim_interface(dev_handle, DIRTYJTAG_INTF); if (ret) { - cerr << "libusb error while claiming DirtyJTAG interface #0" << endl; + cerr << "libusb error while claiming DirtyJTAG interface" << endl; libusb_close(dev_handle); libusb_exit(usb_ctx); throw std::exception(); } + _version = 0; + getVersion(); + if (setClkFreq(clkHZ) < 0) { cerr << "Fail to set frequency" << endl; throw std::exception(); @@ -93,14 +114,49 @@ DirtyJtag::~DirtyJtag() libusb_exit(usb_ctx); } +void DirtyJtag::getVersion() +{ + int actual_length; + int ret; + uint8_t buf[] = {CMD_INFO, + CMD_STOP}; + uint8_t rx_buf[64]; + ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP, + buf, 2, &actual_length, 1000); + if (ret < 0) { + cerr << "getVersion: usb bulk write failed " << ret << endl; + return; + } + do { + ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, + rx_buf, 64, &actual_length, 1000); + if (ret < 0) { + cerr << "getVersion: read: usb bulk read failed " << ret << endl; + return; + } + } while (actual_length == 0); + if (!strncmp("DJTAG1\n", (char*)rx_buf, 7)) { + _version = 1; + } else if (!strncmp("DJTAG2\n", (char*)rx_buf, 7)) { + _version = 2; + } else if (!strncmp("DJTAG3\n", (char*)rx_buf, 7)) { + _version = 3; + } else { + cerr << "dirtyJtag version unknown" << endl; + _version = 0; + } +} + + + int DirtyJtag::setClkFreq(uint32_t clkHZ) { int actual_length; int ret, req_freq = clkHZ; - if (clkHZ > 600000) { - printWarn("DirtyJTAG probe limited to 600kHz"); - clkHZ = 600000; + if (clkHZ > 16000000) { + printWarn("DirtyJTAG probe limited to 16000kHz"); + clkHZ = 16000000; } printInfo("Jtag frequency : requested " + std::to_string(req_freq) + @@ -142,7 +198,7 @@ int DirtyJtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len) 0, CMD_STOP}; while (clk_len > 0) { - buf[2] = (clk_len > 100) ? 100 : (uint8_t)clk_len; + buf[2] = (clk_len > 64) ? 64 : (uint8_t)clk_len; int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP, buf, 4, &actual_length, 1000); @@ -168,7 +224,7 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) uint32_t real_byte_len = (len + 7) / 8; uint8_t tx_cpy[real_byte_len]; - uint8_t tx_buf[33], rx_buf[32]; + uint8_t tx_buf[512], rx_buf[512]; uint8_t *tx_ptr = tx, *rx_ptr = rx; if (tx) @@ -177,31 +233,51 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) memset(tx_cpy, 0, real_byte_len); tx_ptr = tx_cpy; - /* first send 30 x 8 bits */ - tx_buf[0] = CMD_XFER; + tx_buf[0] = CMD_XFER | (rx ? 0 : v_options[_version].no_read ); + uint16_t max_bit_transfer_length = v_options[_version].max_bits; + assert(max_bit_transfer_length %8 == 0);//need to cut the bits on byte size. while (real_bit_len != 0) { - uint8_t bit_to_send = (real_bit_len > 240) ? 240 : real_bit_len; - uint8_t byte_to_send = (bit_to_send + 7) / 8; - tx_buf[1] = bit_to_send; - memset(tx_buf + 2, 0, 30); + uint16_t bit_to_send = (real_bit_len > max_bit_transfer_length) ? max_bit_transfer_length : real_bit_len; + size_t byte_to_send = (bit_to_send + 7) / 8; + size_t header_offset = 0; + if (_version == 3) { + tx_buf[1] = (bit_to_send >> 8) & 0xFF; + tx_buf[2] = bit_to_send & 0xFF; + header_offset = 3; + } else if (bit_to_send > 255) { + tx_buf[0] |= EXTEND_LENGTH; + tx_buf[1] = bit_to_send - 256; + header_offset = 2; + }else { + tx_buf[0] &= ~EXTEND_LENGTH; + tx_buf[1] = bit_to_send; + header_offset = 2; + } + memset(tx_buf + header_offset, 0, byte_to_send); for (int i = 0; i < bit_to_send; i++) if (tx_ptr[i >> 3] & (1 << (i & 0x07))) - tx_buf[2 + (i >> 3)] |= (0x80 >> (i & 0x07)); - - tx_buf[2 + byte_to_send] = CMD_STOP; + tx_buf[header_offset + (i >> 3)] |= (0x80 >> (i & 0x07)); + actual_length = 0; int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP, - (unsigned char *)tx_buf, 33, &actual_length, 1000); - if (ret < 0) { - cerr << "writeTDI: fill: usb bulk write failed " << ret << endl; + (unsigned char *)tx_buf, (byte_to_send + header_offset), &actual_length, 1000); + if ((ret < 0) || (actual_length != (int)(byte_to_send + header_offset))) { + cerr << "writeTDI: fill: usb bulk write failed " << ret << "actual length: " << actual_length << endl; return EXIT_FAILURE; } + //cerr << actual_length << ", " << bit_to_send << endl; - ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, - rx_buf, 32, &actual_length, 1000); - if (ret < 0) { - cerr << "writeTDI: read: usb bulk write failed " << ret << endl; - return EXIT_FAILURE; + if (rx || (_version <= 1)) { + int transfer_length = (bit_to_send > 255) ? byte_to_send :32; + do { + ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, + rx_buf, transfer_length, &actual_length, 1000); + if (ret < 0) { + cerr << "writeTDI: read: usb bulk read failed " << ret << endl; + return EXIT_FAILURE; + } + } while (actual_length == 0); + assert((size_t)actual_length >= byte_to_send); } if (rx) { @@ -223,7 +299,7 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) (tx_cpy[pos >> 3] & (1 << (pos & 0x07))) ? SIG_TDI: 0; if (sendBitBang(SIG_TMS | SIG_TDI, - SIG_TMS | (last_bit), &sig, true) != 0) { + SIG_TMS | (last_bit), (rx ? &sig : 0), true) != 0) { cerr << "writeTDI: last bit error" << endl; return -EXIT_FAILURE; } @@ -264,11 +340,13 @@ int DirtyJtag::sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last) return -EXIT_FAILURE; } - if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, - read, 1, &actual_length, 1000) < 0) { - cerr << "sendBitBang: usb bulk write failed 4" << endl; - return -EXIT_FAILURE; - } + do { + if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, + read, 1, &actual_length, 1000) < 0) { + cerr << "sendBitBang: usb bulk read failed 4" << endl; + return -EXIT_FAILURE; + } + } while (actual_length == 0); } if (last) { diff --git a/src/dirtyJtag.hpp b/src/dirtyJtag.hpp index 515958f..3d5067c 100644 --- a/src/dirtyJtag.hpp +++ b/src/dirtyJtag.hpp @@ -58,10 +58,12 @@ class DirtyJtag : public JtagInterface { bool _verbose; int sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last); + void getVersion(); libusb_device_handle *dev_handle; libusb_context *usb_ctx; uint8_t _tdi; uint8_t _tms; + uint8_t _version; }; #endif // SRC_DIRTYJTAG_HPP_ diff --git a/src/ftdiJtagBitbang.cpp b/src/ftdiJtagBitbang.cpp index ee33c56..fd937d6 100644 --- a/src/ftdiJtagBitbang.cpp +++ b/src/ftdiJtagBitbang.cpp @@ -107,8 +107,12 @@ int FtdiJtagBitBang::setBitmode(uint8_t mode) _bitmode = mode; int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode); +#if (FTDI_VERSION < 105) ftdi_usb_purge_rx_buffer(_ftdi); ftdi_usb_purge_tx_buffer(_ftdi); +#else + ftdi_tcioflush(_ftdi); +#endif return ret; }