Boundary scan using FT2232HL - Page 1
Forum section: electronics / projects

author: abelynux
author_rank: Newbie
timestamp: October 24, 2024, 04:31:02 am
content: Hello everyone, first time posting, please be gentle. Im looking some wisdom to implement boundary scan on a board using a FT2232HL based board by progamatically using LabView to control and read individual pins of an FPGA on the board. A lot of the IO of the FPGA is connected to the outside world through different connectors. We want to control and read FPGA through JTAG with the mentioned device and read and write on the connectors where the FPGA signals are connected. As a reference of the concept, I have used a software called TopJTAG Probe that allows to visuliza the JTAG chain and control and read the IOs of the devices on it, so tehoretically this seems feasible. We want to increase test coverage on the board, we know about jtag off the shelf solutions which are expensive, but we think a basic solution (not sure how difficult can turn out the coding to provide such functionality) should be right for what we are looking without going crazy on cost... we will probably expand to several other boards so the effort may be worth... additionally as information, this boards are low production volume... Open to comments and ideas. Regards.

author: Postal2
author_rank: Frequent Contributor
timestamp: October 24, 2024, 10:53:54 pm
content: I do not recommend using FT2232HL, it is a very buggy chip and will not work as you expect. Consider using FT232H, it works almost perfectly. Especially if you want to use bit-bang, it will be a headache with FT2232H. Safe packet size for FT232H = 45056, for FT2232H = 500.

author: langwadt
author_rank: Super Contributor
timestamp: October 25, 2024, 12:53:04 am
content: Quote from: Postal2 on October 24, 2024, 10:53:54 pmFT2232H is used for jtag all over the place

author: Postal2
author_rank: Frequent Contributor
timestamp: October 25, 2024, 02:40:13 am
content: Quote from: langwadt on October 25, 2024, 12:53:04 amYou can use a car tire instead of toilet paper. I'm talking about what I know for sure.A person begins to develop his own program; he is interested in experience, not the opinion of a schoolchild.Using FT2232H only makes sense if your program supports FT2232D. Starting to design specifically for this chip is stupid.

author: abelynux
author_rank: Newbie
timestamp: October 26, 2024, 03:57:25 pm
content: Hi, Thanks to both of you!Looking at the BSDL file of the EP3C16Q240 (the target device) the boundary length is 1080, so if the packet size of the FT2232H = 500, does that mean that I won't be able to write and read to the device? On the other hand, assuming I'm interpreting the DLL functions correctly, in order to write and read from a device, I need to send or read the specified boundary length by specifying the corresponding bits of the "packet" that belong to the BSCs (boundar scan cells) for the desired IOs?I found some examples on the FTDI page for labview, they are basic examples, none of them account for the BSDL file... it seems a good starting point... I will start digging a bit more.Thanks a lot!

author: Postal2
author_rank: Frequent Contributor
timestamp: October 26, 2024, 04:52:05 pm
content: If you start programming with the intention of using FTDI, then use FT232H. If you need 2 channels - use 2 pieces. If you choose FT2232H - you will get the result, but you will struggle with numerous unexpected glitches that are not mentioned in the documentation. Bad usb detection, jitter signals due to hanging of the chip. The packet size is probably related to the size of the internal chip buffer. Of course, you will get the required size by successive requests. Each command will be passed with a spread in time.

author: hugo
author_rank: Regular Contributor
timestamp: October 26, 2024, 10:21:39 pm
content: QuoteDo you have a JTAG schematic with a FT232H?Thanks

author: ejeffrey
author_rank: Super Contributor
timestamp: October 26, 2024, 11:02:32 pm
content: The ftdi data sheets should have them.Are you writing your own software or expecting to use this with third party tools? If the latter you should check their compatibility list and also if they require specific programming of the FTDI chips in order to be recognized. For instance xilinx FPGA dev kits and programming cables use FTDI JTAG chips. But they need specific programming to be detected.

author: Postal2
author_rank: Frequent Contributor
timestamp: October 27, 2024, 03:41:04 am
content: From the program side, 2 FT232H chips look like one FT2232H. The PCB on the FT2232H chip costs 3 times more than the PCB on the FT232H. All the functions that could work on the FT2232H will do the same on the FT232H, but not vice versa. Now you ask, why program for the FT232H if the result will not work on the FT2232H? Very simple, you will choose the FT2232H chip, working with FTDI for the first time, and nothing will work for you. You will spend a lot of time searching for an error, while the FT232H will work with your code from the first time.Quote from: hugo on October 26, 2024, 10:21:39 pmThe JTAG to DBUS connection diagram is the same for all FTDI chips.Quote from: ejeffrey on October 26, 2024, 11:02:32 pmBarring this issue, the chips are controlled identically via FTDI's own DLL.

author: djacobow
author_rank: Super Contributor
timestamp: October 27, 2024, 04:06:05 am
content: My company has been using the FT4232 for years for this purpose. Generally, we use one channel for JTAG or SWD, one or two for uarts, and one for SPI or I2C.Mostly we control it all with python using pyftdi. This has been phenomenally successful for us. I can't think of the last time I used a "real" jtag adapter.One annoyance with the 4232 is that its gpio is 3v3 only, so we need translation for 1v9 or 0v9.

author: Postal2
author_rank: Frequent Contributor
timestamp: October 27, 2024, 04:28:46 am
content: Quote from: djacobow on October 27, 2024, 04:06:05 amPost here the source code you wrote for exchanging packets with FT4232H. I'll post mine now.My packet exchange is tied to global variables and is hard to read, so I posted the initialization function. A person who can only press buttons in someone else's program will certainly not have any source code of his own.Code:void myFtdiDeviceOpen(){//now erase possible mask for BB (must be reset)memset(myFtdiBBangRWbuf, 0, 65536);//reset mask for use later//now reset some vars for extreme safetymyFtdiBBangRWbufCurPointer = 0;myFtdiCurFlushRcvBytes = 0;myFtdiRcvFlushBufCurPointer = 0;//check library ... (handle only)if(myFtdiDllModule == NULL)//enumerate only once{myFtdiReLoad(true);if(myFtdiDllModule == NULL) return;//because final error//assume loaded. check devices connected ...//anyway check connected devices by count ...CString strTemp = _T("");DWORDdwNumDevices = 0;//set num device only at first program start!int errAnswer = myFT_ListDevices(&dwNumDevices, NULL, 0x80000000);if(FT_OK == errAnswer){if(dwNumDevices != 0){strTemp.Format( _T("Count of USB-devices = %d"), dwNumDevices );myMesShow(strTemp);if((dwNumDevices & 0xFF) > 1)//max 256 devices, >=2{myFtdiDeviceNum = dwNumDevices - 1;//OR -2???if(myFtdiPrevDevNum2232){ myFtdiDeviceNum = dwNumDevices - 2; myMesShow(_T("Selected number max-1."));}else myMesShow(_T("Selected number set to max."));}strTemp.Format( _T("Num of device to use = %d"), myFtdiDeviceNum );//default=0myMesShow(strTemp);}else{myMesShow(_T("Error: NULL devices, connect some ..."));return;}}else{strTemp.Format( _T("- Cannot enumerate, err=0x%.2X"), errAnswer );myMesShow(strTemp);return;}//assume number is valid, opening ...}//end load and enumerateif(myFtdiHandle == INVALID_HANDLE_VALUE)//open only if closed{// Set read write timeouts//mySI_SetTimeouts(5000, 2500);// Open device handleif(FT_OK != myFT_Open((DWORD)myFtdiDeviceNum, &myFtdiHandle)){myMesShow(_T("- Error Device Open !"));return;}}//end if invalid handle//configure for MPSSE... (MAY BE MORE MODES???)// SELECT BIT-BANG OR MPSSE BY MODE...//reset device...if(FT_OK != myFT_ResetDevice(myFtdiHandle)) myMesShow(_T("Error: Failed to reset device."));//check buffer not empty...DWORDdwRxBytes = 0;if(FT_OK != myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes)) myMesShow(_T("Error: GetQueueStatus."));//purge receive buffer by read tail...if(dwRxBytes > 65536) {myMesShow(_T("Error: dwRxBytes > 65536.")); return;}BYTE tmpBuffer;DWORD dwBytesReturned = 0;if(dwRxBytes > 0) myFT_Read(myFtdiHandle,tmpBuffer,dwRxBytes,&dwBytesReturned);//set usb transfer size (it will reset buffer) //old default is 4096//old2=16384//49152if(FT_OK != myFT_SetUSBParameters(myFtdiHandle,49152,49152)) myMesShow(_T("Error set USB transfer size."));//if(FT_OK != myFT_SetUSBParameters(myFtdiHandle,256,256)) myMesShow(_T("Error set USB transfer size."));if(FT_OK != myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes)) myMesShow(_T("Error: GetQueueStatus."));//second purge receive buffer by read tail...if(dwRxBytes > 65536) {myMesShow(_T("Err2: dwRxBytes > 65536.")); return;}if(dwRxBytes > 0) myFT_Read(myFtdiHandle,tmpBuffer,dwRxBytes,&dwBytesReturned);//here may be jump for bit-bang...if(myFtdiModeMPSSE){//disable event and error charsif(FT_OK != myFT_SetChars(myFtdiHandle,0,0,0,0)) myMesShow(_T("Error set event chars."));//set timeoutsif(FT_OK != myFT_SetTimeouts(myFtdiHandle,1000, 1000)) myMesShow(_T("Error: Failed to set timeouts."));//set latency to 1if(FT_OK != myFT_SetLatencyTimer(myFtdiHandle,1)) myMesShow(_T("Error: Failed to set latency."));//set (or reset??) flow control...if(FT_OK != myFT_SetFlowControl(myFtdiHandle,FT_FLOW_RTS_CTS,0,0)) myMesShow(_T("Error: Failed to set flow."));//if(FT_OK != myFT_SetFlowControl)(myFtdiHandle,FT_FLOW_NONE,0,0)) myMesShow(_T("Error: Failed to set flow."));//reset mpsseif(FT_OK != myFT_SetBitMode(myFtdiHandle,0,0)){myMesShow(_T("Error: Failed to reset mpsse.")); return;}//enable mpsse (bitmask??)if(FT_OK != myFT_SetBitMode(myFtdiHandle,0,2)){myMesShow(_T("Error: Failed to set mpsse.\r\n- try Bit-Bang instead.")); return;}//now set divisor x5...DWORD dwBytesWritten = 0;UINT bytesToReceive = 2;UINT r_Counter = 0;if(myFtdiDivisorX5disable){//first on/off divisor x5...BYTE setDivDis = {0x8A,0xAA,0x87};int ftStatus = myFT_Write(myFtdiHandle,setDivDis,3,&dwBytesWritten);if(ftStatus != FT_OK) {myMesShow(_T("Error: FT_Write2")); return;}//check answerwhile(r_Counter++ < 250000)//old max=1000000{ftStatus = myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes);if(ftStatus != FT_OK) {myMesShow(_T("Error: GetQueueStatus2")); return;}if(bytesToReceive <= dwRxBytes) break;}if(r_Counter >= 250000) {myMesShow(_T("GetQueue timeout\r\n- try Bit-Bang instead.")); return;}//assume Queue ready.ftStatus = myFT_Read(myFtdiHandle,tmpBuffer,bytesToReceive,&dwBytesReturned);if(ftStatus != FT_OK) {myMesShow(_T("Error: FT_Read1")); return;}if(tmpBuffer != 0xAA) myMesShow(_T("Error divisor X5"));//clear Queue for nextif(FT_OK != myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes)) myMesShow(_T("Error: GetQueueStatus3."));//purge receive buffer by read tail...if(dwRxBytes > 16384) {myMesShow(_T("Error: dwRxBytes > 16384.")); return;}if(dwRxBytes > 0) myFT_Read(myFtdiHandle,tmpBuffer,dwRxBytes,&dwBytesReturned);}//end if(myFtdiDivisorX5disable)//now set speed...BYTE setSpeed = {0x86,(BYTE)myFtdiCurMpsseSpeed,(BYTE)(myFtdiCurMpsseSpeed>>8),0xAB,0x87};int ftStatus = myFT_Write(myFtdiHandle,setSpeed,5,&dwBytesWritten);if(ftStatus != FT_OK) {myMesShow(_T("Error: FT_Write3")); return;}//check answerr_Counter = 0;while(r_Counter++ < 250000)//old max=1000000{ftStatus = myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes);if(ftStatus != FT_OK) {myMesShow(_T("Error: GetQueueStatus4")); return;}if(bytesToReceive <= dwRxBytes) break;}if(r_Counter >= 250000) {myMesShow(_T("GetQueue timeout2\r\n- try Bit-Bang instead.")); return;}//assume Queue ready.ftStatus = myFT_Read(myFtdiHandle,tmpBuffer,bytesToReceive,&dwBytesReturned);if(ftStatus != FT_OK) {myMesShow(_T("Error: FT_Read2")); return;}if(tmpBuffer != 0xAB) myMesShow(_T("Error mpsse speed"));//clear Queue for nextif(FT_OK != myFT_GetQueueStatus(myFtdiHandle,&dwRxBytes)) myMesShow(_T("Error: GetQueueStatus3."));//purge receive buffer by read tail...if(dwRxBytes > 16384) {myMesShow(_T("Error: dwRxBytes > 16384.")); return;}if(dwRxBytes > 0) myFT_Read(myFtdiHandle,tmpBuffer,dwRxBytes,&dwBytesReturned);}else//init for bit-bang...//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//open as bit-bang (sync){//ULONG myFtdiBaudRate = 62500;// X16 = 1M VALUE - USE GLOBAL VALUE!!!//ULONG myFtdiBaudRate = 31250;// X16 = 500k VALUE//disable event and error charsif(FT_OK != myFT_SetChars(myFtdiHandle,0,0,0,0)) myMesShow(_T("Error set event chars."));//set timeoutsif(FT_OK != myFT_SetTimeouts(myFtdiHandle,1000, 1000)) myMesShow(_T("Error: Failed to set timeouts."));//set latency to 1if(FT_OK != myFT_SetLatencyTimer(myFtdiHandle,1)) myMesShow(_T("Error: Failed to set latency."));//set (or reset??) flow control...if(FT_OK != myFT_SetFlowControl(myFtdiHandle,FT_FLOW_NONE,0x11,0x13)) myMesShow(_T("Error: Failed to set flow."));//set pulse speed by baudrate (x16)if(FT_OK != myFT_SetBaudRate(myFtdiHandle,myFtdiBaudRate)) myMesShow(_T("Error set baudrate."));//enable bit-bang (bitmask 0=all input??)if(FT_OK != myFT_SetBitMode(myFtdiHandle,0,4)) myMesShow(_T("Error set bit-bang."));//write default data to pins???//- need setup passive levels by mode}//end init for bit-bang//assume success//set line control/*wLineControl—A WORD variable that contains the desired line control settings. Possible inputsettings are as follows:Bits 0–3 Number of Stop bits0: 1 stop bit;1: 1.5 stop bits;2: 2 stop bitsBits 4–7 Parity0: None1: Odd2: Even3: Mark4: SpaceBits 8–15 Number of bits per word5, 6, 7, or 88n1=0x0800 WORDif(FT_OK != mySI_SetLineControl(mySilabsHandle, 0x0800)) myMesShow(_T("Error: Failed to set line 8N1."));//set flow-controlint myFlowSetResult = 0;switch (myFlowControl){case 1: myFlowSetResult = mySI_SetFlowControl(mySilabsHandle,1,2,2,1,0,0);//hardware flow-controlbreak;case 2: myFlowSetResult = mySI_SetFlowControl(mySilabsHandle,0,1,1,0,0,1);//Xon/Xoff flowbreak;default: myFlowSetResult = mySI_SetFlowControl(mySilabsHandle,0,1,1,0,0,0);//disable, as=0,dtr=rts=upbreak;}//end of flow-control switchif(FT_OK != myFlowSetResult) myMesShow(_T("Error: Failed to set flow-control."));// Clear the CP210x device's buffersif(FT_OK != mySI_FlushBuffers(mySilabsHandle, 1, 1)) myMesShow(_T("Error: Failed to purge device."));*/}//end myFtdiDeviceOpen

author: ejeffrey
author_rank: Super Contributor
timestamp: October 27, 2024, 02:29:27 pm
content: Quote from: djacobow on October 27, 2024, 04:06:05 amSame. For us, we haven't written our own JTAG code but used primarily the xilinx tools. But the FT4232 has worked flawlessly with the xilinx tools for loading a bitstream, booting a zynq processor, and using the in circuit logic analyzer. It's clearly possible to use these chips successfully.

author: Postal2
author_rank: Frequent Contributor
timestamp: October 27, 2024, 03:13:35 pm
content: Quote from: ejeffrey on October 27, 2024, 02:29:27 pmYou give advice on usage without having any idea about creating code for this chip.To work with the FT2232H (which is very similar to the FT4232H), you need to write fault-tolerant code, which was most likely ordered from FTDI, which has extensive internal documentation.On the contrary, FT232H works well and right away, so it is better to debug your program using it first, and then modify it for different junk.

author: djacobow
author_rank: Super Contributor
timestamp: October 27, 2024, 07:00:11 pm
content: Why would I write code for a debug tool of I don't have to? Believe it or not, I'd rather spend my time working on my target, not the debug environment.As I said, we use pyftdi. We also use openocd which has no problem with any of these chips.

author: abelynux
author_rank: Newbie
timestamp: October 27, 2024, 08:17:51 pm
content: Hello djacobow,Not trying to develop a debug tool, this is for quality testing of production boards that are already validated by design... not sure if it is any tool that can accomplish what we are looking without going beyond X times NRE of internal investment... if such tool is there of course we will give it a consideration. We want to integrate with labview so we can develop test sequences... practically we want to "convert" the UUT board into a DAQ controlled by the JTAG and measure/write through the connectors of the board... most of the signals of the JTAG devices on the board goes to the outside world, very few of them are connected to some ADCs or DACs on the board...It may be a crazy idea, we don't want to reinvent the wheel neither, but want to reduce cost... at this point we are under the impression that of the shelf solutions are off compared to internal investment... I may be underestimating the effort to develop such functionality, and if so, I'm open to new information that proves this not feasible, technically or financially.Just adding, python has been banned by our IT group, so python tools are out of our reach... IT group so paranoic...Thanks!

author: Postal2
author_rank: Frequent Contributor
timestamp: October 28, 2024, 06:20:39 am
content: Quote from: abelynux on October 27, 2024, 08:17:51 pmThen everything is much simpler. You pay for LabVIEW+ Suite, pay for the necessary modules, pay for support and calmly do everything you need without lifting a finger.

author: abelynux
author_rank: Newbie
timestamp: October 28, 2024, 08:27:07 am
content: It is not about doing notthing, it is about what can be justified and what makes more sense (at least on a manufacturing company, custom solutions are usually avoided due several factors, but not discarded, $$$), we either find an of the shelf solution with a good price that does what we are looking for or invest on developing the functions we need (using obviously the DLLs and API from FTDI)... at this point no decision has been made, and Im here to listen (read) from those that may have already gone through a similar path... if at the end such of the shelf solution is not there, we will take the route of developing what we need, which at this point it is still the way to go, unitl anyone suggest something better.

author: Postal2
author_rank: Frequent Contributor
timestamp: October 28, 2024, 09:01:03 am
content: Quote from: abelynux on October 28, 2024, 08:27:07 amYour solution for JTAG is very simple, more complex ones include downloading executable code for the target platform. I tried to find a free solution and could not. But going through the paid solutions, I saw how support is expanded. They will give you a tool for writing code ("plugin"), and when you write everything - they just steal it and include it in their program. Very convenient.