eblot / pyftdi

FTDI device driver written in pure Python
Other
502 stars 211 forks source link

JTAG speed improvements? #202

Open markmelvin opened 4 years ago

markmelvin commented 4 years ago

I'm using it to drive a JTAG port and the speed of it is much slower that I expected. Is there any way to improve performance? It is running the JTAG clock at 3MHz, but the overall communications speed is somewhere around 8 Kbits/s. As a point of comparison, I can achieve 166 Kbits/s by bitbanging the protocol with Python. I can see the clock is generated at 3 MHz, but there are huge delays between bytes. I lowered the latency to 12 and it sped it up a little, but only by about 25%.

I overrode the minimum latency to allow down to 1ms and while this had a noticeable improvement, it is still slow. I think the only way to get this faster is to batch more data and avoid the latency roundtrip. This is difficult with the current JTAG driver if you want to read and write at the same time.

Maybe you could allow the user to at least set a minimum latency of 1 and expose that up through the JTAG API? The FTDI MPSSE samples do seem to encourage a latency of 1 for high speed operations.

eblot commented 4 years ago

I have not worked with JTAG module for many years, so it is likely it is possible to speed up transfers...

rwhitby commented 1 year ago

The main impediment to faster JTAG with PyFTDI is the sync() call at the end of write_tms().

At the moment, that sync() call is done everyt time write_tms() is called.

I put an "if should_read:" around the final sync() call in write_tms() and achieved a 100x speed-up of JTAG operations.

My application is using PyFTDI to blow an eFuse, which requires precisely controlling an external programming voltage while commanding the programming using JTAG operations.

Before (operation takes 3ms):

Screenshot 2022-11-09 at 9 40 07 am

After (operation takes 40us):

Screenshot 2022-11-09 at 9 39 36 am

The sync() is only required when you need to examine the shift data returned during the write_tms() operation. So during the shift_register() function, you don't need this additional round-trip on USB. During the shift_and_update_register() function, the returned data is examined, so you do need the extra sync() call.

The write_tms() function already has a should_read argument. This argument should be used to determine whether the final sync() call is needed, and then all places where write_tms() is used should set the should_read argument accordingly.

After reviewing all the open pull requests for overlap, I intend to submit a pull request with this JTAG speed improvement.