ftdi MPSSE / jtag: add option to use neg edge for TDO's sampling

This commit is contained in:
Gwenhael Goavec-Merou 2022-03-11 07:45:48 +01:00
parent 86b2e14dbd
commit 964c7d6659
7 changed files with 37 additions and 13 deletions

View File

@ -54,6 +54,8 @@ openFPGALoader -- a program to flash FPGA
--bitstream arg bitstream --bitstream arg bitstream
-b, --board arg board name, may be used instead of cable -b, --board arg board name, may be used instead of cable
-c, --cable arg jtag interface -c, --cable arg jtag interface
--invert-read-edge JTAG mode / FTDI: read on negative edge instead
of positive
--vid arg probe Vendor ID --vid arg probe Vendor ID
--pid arg probe Product ID --pid arg probe Product ID
--ftdi-serial arg FTDI chip serial number --ftdi-serial arg FTDI chip serial number

View File

@ -10,6 +10,15 @@ Resetting an FPGA
openFPGALoader [options] -r 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 Reading the bitstream from STDIN
================================ ================================

View File

@ -29,10 +29,12 @@ using namespace std;
#endif #endif
FtdiJtagMPSSE::FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, 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), FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _ch552WA(false),
_write_mode(MPSSE_WRITE_NEG), // always write on neg edge _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); init_internal(cable);
} }
@ -88,10 +90,10 @@ void FtdiJtagMPSSE::config_edge()
{ {
/* at high (>15MHz) with digilent cable (arty) /* at high (>15MHz) with digilent cable (arty)
* opposite edges must be used. * opposite edges must be used.
* Not required with classic FT2232 * Not required with classic FT2232 but user selectable
*/ */
if (FTDIpp_MPSSE::getClkFreq() >= 15000000 && if (_invert_read_edge || (FTDIpp_MPSSE::getClkFreq() >= 15000000 &&
!strncmp((const char *)_iproduct, "Digilent USB Device", 19)) { !strncmp((const char *)_iproduct, "Digilent USB Device", 19))) {
_read_mode = MPSSE_READ_NEG; _read_mode = MPSSE_READ_NEG;
} else { } else {
_read_mode = 0; _read_mode = 0;

View File

@ -23,7 +23,8 @@
class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE { class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE {
public: public:
FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, std::string dev, 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(); virtual ~FtdiJtagMPSSE();
int setClkFreq(uint32_t clkHZ) override; int setClkFreq(uint32_t clkHZ) override;
@ -58,5 +59,6 @@ class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE {
bool _ch552WA; /* avoid errors with SiPeed tangNano */ bool _ch552WA; /* avoid errors with SiPeed tangNano */
uint8_t _write_mode; /**< write edge configuration */ uint8_t _write_mode; /**< write edge configuration */
uint8_t _read_mode; /**< read edge configuration */ uint8_t _read_mode; /**< read edge configuration */
bool _invert_read_edge; /**< read edge selection (false: pos, true: neg) */
}; };
#endif #endif

View File

@ -63,13 +63,14 @@ using namespace std;
Jtag::Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, string dev, 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 &serial, uint32_t clkHZ, int8_t verbose,
const string &firmware_path): const bool invert_read_edge, const string &firmware_path):
_verbose(verbose), _verbose(verbose),
_state(RUN_TEST_IDLE), _state(RUN_TEST_IDLE),
_tms_buffer_size(128), _num_tms(0), _tms_buffer_size(128), _num_tms(0),
_board_name("nope"), device_index(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); detectChain(5);
} }
@ -80,7 +81,8 @@ Jtag::~Jtag()
} }
void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial, 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) { switch (cable.type) {
case MODE_ANLOGICCABLE: 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); _jtag = new FtdiJtagBitBang(cable.config, pin_conf, dev, serial, clkHZ, _verbose);
break; break;
case MODE_FTDI_SERIAL: 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; break;
case MODE_CH552_JTAG: case MODE_CH552_JTAG:
_jtag = new CH552_jtag(cable.config, dev, serial, clkHZ, _verbose); _jtag = new CH552_jtag(cable.config, dev, serial, clkHZ, _verbose);

View File

@ -19,6 +19,7 @@ class Jtag {
public: public:
Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, std::string dev, 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 std::string &serial, uint32_t clkHZ, int8_t verbose = 0,
const bool invert_read_edge = false,
const std::string &firmware_path = ""); const std::string &firmware_path = "");
~Jtag(); ~Jtag();
@ -105,7 +106,8 @@ class Jtag {
void init_internal(cable_t &cable, const std::string &dev, void init_internal(cable_t &cable, const std::string &dev,
const std::string &serial, const std::string &serial,
const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, 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 * \brief search in fpga_list and misc_dev_list for a device with idcode
* if found insert idcode and irlength in _devices_list and * if found insert idcode and irlength in _devices_list and

View File

@ -45,6 +45,7 @@ struct arguments {
string ftdi_serial; string ftdi_serial;
int ftdi_channel; int ftdi_channel;
uint32_t freq; uint32_t freq;
bool invert_read_edge;
string board; string board;
bool pin_config; bool pin_config;
bool list_cables; bool list_cables;
@ -80,7 +81,7 @@ int main(int argc, char **argv)
/* command line args. */ /* command line args. */
struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, 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, ""}; false, false, "", "", "", -1, 0, false, -1, 0, 0, 0, false, ""};
/* parse arguments */ /* parse arguments */
try { try {
@ -369,7 +370,8 @@ int main(int argc, char **argv)
Jtag *jtag; Jtag *jtag;
try { try {
jtag = new Jtag(cable, &pins_config, args.device, args.ftdi_serial, 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) { } catch (std::exception &e) {
printError("JTAG init failed with: " + string(e.what())); printError("JTAG init failed with: " + string(e.what()));
return EXIT_FAILURE; 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", ("b,board", "board name, may be used instead of cable",
cxxopts::value<string>(args->board)) cxxopts::value<string>(args->board))
("c,cable", "jtag interface", cxxopts::value<string>(args->cable)) ("c,cable", "jtag interface", cxxopts::value<string>(args->cable))
("invert-read-edge", "JTAG mode / FTDI: read on negative edge instead of positive",
cxxopts::value<bool>(args->invert_read_edge))
("vid", "probe Vendor ID", cxxopts::value<uint16_t>(args->vid)) ("vid", "probe Vendor ID", cxxopts::value<uint16_t>(args->vid))
("pid", "probe Product ID", cxxopts::value<uint16_t>(args->pid)) ("pid", "probe Product ID", cxxopts::value<uint16_t>(args->pid))