diff --git a/README.md b/README.md index 49f3c3c..6efef24 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ openFPGALoader -- a program to flash FPGA --bitstream arg bitstream -b, --board arg board name, may be used instead of cable -c, --cable arg jtag interface + --invert-read-edge JTAG mode / FTDI: read on negative edge instead + of positive --vid arg probe Vendor ID --pid arg probe Product ID --ftdi-serial arg FTDI chip serial number diff --git a/doc/guide/advanced.rst b/doc/guide/advanced.rst index a01b2ed..03c75ee 100644 --- a/doc/guide/advanced.rst +++ b/doc/guide/advanced.rst @@ -10,6 +10,15 @@ Resetting an FPGA openFPGALoader [options] -r +Using negative edge for TDO's sampling +==================================== + +If transaction are unstable you can try to change read edge by using + +.. code-block:: bash + + openFPGALoader [options] --invert-read-edge + Reading the bitstream from STDIN ================================ diff --git a/src/ftdiJtagMPSSE.cpp b/src/ftdiJtagMPSSE.cpp index dfd5fd7..e9a9c9c 100644 --- a/src/ftdiJtagMPSSE.cpp +++ b/src/ftdiJtagMPSSE.cpp @@ -29,10 +29,12 @@ using namespace std; #endif FtdiJtagMPSSE::FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, - string dev, const string &serial, uint32_t clkHZ, int8_t verbose): + string dev, const string &serial, uint32_t clkHZ, + bool invert_read_edge, int8_t verbose): FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _ch552WA(false), _write_mode(MPSSE_WRITE_NEG), // always write on neg edge - _read_mode(0) + _read_mode(0), + _invert_read_edge(invert_read_edge) // false: pos, true: neg { init_internal(cable); } @@ -88,10 +90,10 @@ void FtdiJtagMPSSE::config_edge() { /* at high (>15MHz) with digilent cable (arty) * opposite edges must be used. - * Not required with classic FT2232 + * Not required with classic FT2232 but user selectable */ - if (FTDIpp_MPSSE::getClkFreq() >= 15000000 && - !strncmp((const char *)_iproduct, "Digilent USB Device", 19)) { + if (_invert_read_edge || (FTDIpp_MPSSE::getClkFreq() >= 15000000 && + !strncmp((const char *)_iproduct, "Digilent USB Device", 19))) { _read_mode = MPSSE_READ_NEG; } else { _read_mode = 0; diff --git a/src/ftdiJtagMPSSE.hpp b/src/ftdiJtagMPSSE.hpp index f37d19a..d0f997d 100644 --- a/src/ftdiJtagMPSSE.hpp +++ b/src/ftdiJtagMPSSE.hpp @@ -23,7 +23,8 @@ class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE { public: FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, std::string dev, - const std::string &serial, uint32_t clkHZ, int8_t verbose = 0); + const std::string &serial, uint32_t clkHZ, bool invert_read_edge, + int8_t verbose = 0); virtual ~FtdiJtagMPSSE(); int setClkFreq(uint32_t clkHZ) override; @@ -58,5 +59,6 @@ class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE { bool _ch552WA; /* avoid errors with SiPeed tangNano */ uint8_t _write_mode; /**< write edge configuration */ uint8_t _read_mode; /**< read edge configuration */ + bool _invert_read_edge; /**< read edge selection (false: pos, true: neg) */ }; #endif diff --git a/src/jtag.cpp b/src/jtag.cpp index 0ac6813..1db3d38 100644 --- a/src/jtag.cpp +++ b/src/jtag.cpp @@ -63,13 +63,14 @@ using namespace std; Jtag::Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, string dev, const string &serial, uint32_t clkHZ, int8_t verbose, - const string &firmware_path): + const bool invert_read_edge, const string &firmware_path): _verbose(verbose), _state(RUN_TEST_IDLE), _tms_buffer_size(128), _num_tms(0), _board_name("nope"), device_index(0) { - init_internal(cable, dev, serial, pin_conf, clkHZ, firmware_path); + init_internal(cable, dev, serial, pin_conf, clkHZ, firmware_path, + invert_read_edge); detectChain(5); } @@ -80,7 +81,8 @@ Jtag::~Jtag() } void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial, - const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, const string &firmware_path) + const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, const string &firmware_path, + const bool invert_read_edge) { switch (cable.type) { case MODE_ANLOGICCABLE: @@ -92,7 +94,8 @@ void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial _jtag = new FtdiJtagBitBang(cable.config, pin_conf, dev, serial, clkHZ, _verbose); break; case MODE_FTDI_SERIAL: - _jtag = new FtdiJtagMPSSE(cable.config, dev, serial, clkHZ, _verbose); + _jtag = new FtdiJtagMPSSE(cable.config, dev, serial, clkHZ, + invert_read_edge, _verbose); break; case MODE_CH552_JTAG: _jtag = new CH552_jtag(cable.config, dev, serial, clkHZ, _verbose); diff --git a/src/jtag.hpp b/src/jtag.hpp index 8971b57..2f18b0d 100644 --- a/src/jtag.hpp +++ b/src/jtag.hpp @@ -19,6 +19,7 @@ class Jtag { public: Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, std::string dev, const std::string &serial, uint32_t clkHZ, int8_t verbose = 0, + const bool invert_read_edge = false, const std::string &firmware_path = ""); ~Jtag(); @@ -105,7 +106,8 @@ class Jtag { void init_internal(cable_t &cable, const std::string &dev, const std::string &serial, const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, - const std::string &firmware_path); + const std::string &firmware_path, + const bool invert_read_edge); /*! * \brief search in fpga_list and misc_dev_list for a device with idcode * if found insert idcode and irlength in _devices_list and diff --git a/src/main.cpp b/src/main.cpp index cf9033e..4713e71 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,7 @@ struct arguments { string ftdi_serial; int ftdi_channel; uint32_t freq; + bool invert_read_edge; string board; bool pin_config; bool list_cables; @@ -80,7 +81,7 @@ int main(int argc, char **argv) /* command line args. */ struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, - 0, "-", false, false, false, false, Device::PRG_NONE, false, + 0, false, "-", false, false, false, false, Device::PRG_NONE, false, false, false, "", "", "", -1, 0, false, -1, 0, 0, 0, false, ""}; /* parse arguments */ try { @@ -369,7 +370,8 @@ int main(int argc, char **argv) Jtag *jtag; try { jtag = new Jtag(cable, &pins_config, args.device, args.ftdi_serial, - args.freq, args.verbose, args.probe_firmware); + args.freq, args.verbose, args.invert_read_edge, + args.probe_firmware); } catch (std::exception &e) { printError("JTAG init failed with: " + string(e.what())); return EXIT_FAILURE; @@ -579,6 +581,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p ("b,board", "board name, may be used instead of cable", cxxopts::value(args->board)) ("c,cable", "jtag interface", cxxopts::value(args->cable)) + ("invert-read-edge", "JTAG mode / FTDI: read on negative edge instead of positive", + cxxopts::value(args->invert_read_edge)) ("vid", "probe Vendor ID", cxxopts::value(args->vid)) ("pid", "probe Product ID", cxxopts::value(args->pid))