FT2232H编程流程分析

前言

如何熟练操作FT2232H设备呢?这是一个问题。下面我们以Visual Studio环境下C++例程代码为例来逐步进行解析。

正菜

获取当前连接的FTDI设备

ftStatus = FT_CreateDeviceInfoList(&dwNumDevs);		// Get the number of FTDI devices

if (ftStatus != FT_OK)			// Did the command execute OK?
{
	printf("Error in getting the number of devices\n");
	return 1;					// Exit with error
}

if (dwNumDevs < 1)				// Exit if we don't see any
{
	printf("There are no FTDI devices installed\n");
	return 1;					// Exist with error
}

printf("%d FTDI devices found - the count includes individual ports on a single chip\n", dwNumDevs);

上述代码获取当前系统下的FTDI设备数,如果设备是FT232H,那么dwNumDevs等于1;如果设备是FT2232H,那么dwNumDevs等于2.

获取指定设备的详细信息

FT_HANDLE ftHandleTemp; 
DWORD numDevs; 
DWORD Flags;
DWORD ID; 
DWORD Type; 
DWORD LocId; 
char SerialNumber[16]; 
char Description[64];

ftStatus = FT_GetDeviceInfoDetail(1, &Flags, &Type, &ID, &LocId, SerialNumber, Description, &ftHandleTemp);
if (ftStatus != FT_OK)
{
	printf("Open Failed with error %d\n", ftStatus);
	return 1;					// Exit with error
}
printf("TYPE:%x\n", Type);
printf("ID:%x\n", ID);
printf("Flags:%x\n", Flags);
printf("SN:%x\n", SerialNumber);
printf("Description:%x\n", Description);

确认设备信息后,打开指定设备

ftStatus = FT_Open(1, &ftHandle);
if (ftStatus != FT_OK)
{
	printf("Open Failed with error %d\n", ftStatus);
	return 1;					// Exit with error
}	

上面代码中1表示设备号。

复位设备

ftStatus |= FT_ResetDevice(ftHandle); 	//Reset USB device

清空缓存

ftStatus |= FT_GetQueueStatus(ftHandle, &dwNumBytesToRead);   // Get the number of bytes in the FT2232H receive buffer
if ((ftStatus == FT_OK) && (dwNumBytesToRead > 0))
	FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);  	//Read out the data from FT2232H receive buffer

清空接收缓存和发送缓存.

配置设备

ftStatus |= FT_SetUSBParameters(ftHandle, 65536, 65535); 	//Set USB request transfer sizes to 64K
ftStatus |= FT_SetChars(ftHandle, false, 0, false, 0); 		//Disable event and error characters
ftStatus |= FT_SetTimeouts(ftHandle, 0, 5000); 	     		//Sets the read and write timeouts in milliseconds 
ftStatus |= FT_SetLatencyTimer(ftHandle, 16);   			//Set the latency timer (default is 16mS)
ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x00); 			//Reset controller
ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x02); 			//Enable MPSSE mode
if (ftStatus != FT_OK)
{
	printf("Error in initializing the MPSSE %d\n", ftStatus);
	FT_Close(ftHandle);
	return 1;					// Exit with error
}	
Sleep(50); // Wait for all the USB stuff to complete and work

主要配置:

  • 设置USB传输块大小
  • 禁止事件和错误字符
  • 按照毫秒单位设定读写timeout
  • 设置延迟定时器
  • 复位控制器
  • 使能MPSSE模式

同步MPSSE

/* 
// -----------------------------------------------------------
// Synchronize the MPSSE by sending a bogus opcode (0xAA), 
//		The MPSSE will respond with "Bad Command" (0xFA) followed by
//		the bogus opcode itself.
// -----------------------------------------------------------
*/
byOutputBuffer[dwNumBytesToSend++] = 0xAA;//'\xAA'; 	//Add bogus command 憍AA?to the queue
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);   // Send off the BAD commands
dwNumBytesToSend = 0;			// Reset output buffer pointer
do
{
	ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); 	// Get the number of bytes in the device input buffer
} while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK)); 	//or Timeout

bool bCommandEchod = false;
ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead); 	//Read out the data from input buffer
for (dwCount = 0; dwCount < dwNumBytesRead - 1; dwCount++)  	//Check if Bad command and echo command received
{
	if ((byInputBuffer[dwCount] == 0xFA) && (byInputBuffer[dwCount+1] == 0xAA))
	{
		bCommandEchod = true;
		break;
	}
}
if (bCommandEchod == false)
{
	printf("Error in synchronizing the MPSSE\n");
	FT_Close(ftHandle);
	return 1;					// Exit with error
}	

点灯测试代码

while (1) {
	//注释掉的代码是MPSSE I2C User Mannual中提到的GPIO操作函数
	/*FT_WriteGPIO(ftHandle, 0xff, 0xFF);
	Sleep(50);
	FT_WriteGPIO(ftHandle, 0xff, 0x00);
	Sleep(50);*/
	dwNumBytesToSend = 0;			// Start with a fresh index
	
	// Set up the Hi-Speed specific commands for the FTx232H
	byOutputBuffer[dwNumBytesToSend++] = 0x82;	// Use 60MHz master clock (disable divide by 5)
	byOutputBuffer[dwNumBytesToSend++] = 0xFF;	// Turn off adaptive clocking (may be needed for ARM)
	byOutputBuffer[dwNumBytesToSend++] = 0xFF;	// Disable three-phase clocking
	ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
	dwNumBytesToSend = 0;
	Sleep(50);
	byOutputBuffer[dwNumBytesToSend++] = 0x82;	// Use 60MHz master clock (disable divide by 5)
	byOutputBuffer[dwNumBytesToSend++] = 0x00;	// Turn off adaptive clocking (may be needed for ARM)
	byOutputBuffer[dwNumBytesToSend++] = 0xFF;	// Disable three-phase clocking
	ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
	dwNumBytesToSend = 0;
	Sleep(50);
}

配置MPSSE JTAG

/* 
// -----------------------------------------------------------
// Configure the MPSSE settings for JTAG
//		Multple commands can be sent to the MPSSE with one FT_Write
// -----------------------------------------------------------
*/
dwNumBytesToSend = 0;			// Start with a fresh index

// Set up the Hi-Speed specific commands for the FTx232H
byOutputBuffer[dwNumBytesToSend++] = 0x8A;		// Use 60MHz master clock (disable divide by 5)
byOutputBuffer[dwNumBytesToSend++] = 0x97;  	// Turn off adaptive clocking (may be needed for ARM)
byOutputBuffer[dwNumBytesToSend++] = 0x8D;		// Disable three-phase clocking
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 
									// Send off the HS-specific commands
dwNumBytesToSend = 0;			// Reset output buffer pointer
// Set initial states of the MPSSE interface - low byte, both pin directions and output values
//		Pin name	Signal	Direction	Config	Initial State	Config
//		ADBUS0		TCK		output		1		low				0
//		ADBUS1		TDI		output		1		low				0
//		ADBUS2		TDO		input		0						0
//		ADBUS3		TMS		output		1		high			1
//		ADBUS4		GPIOL0	input		0						0
//		ADBUS5		GPIOL1	input		0						0
//		ADBUS6		GPIOL2	input		0						0
//		ADBUS7		GPIOL3	input		0						0
		
byOutputBuffer[dwNumBytesToSend++] = 0x80;  // Set data bits low-byte of MPSSE port
byOutputBuffer[dwNumBytesToSend++] = 0x08;	// Initial state config above
byOutputBuffer[dwNumBytesToSend++] = 0x0B;	// Direction config above
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);  // Send off the low GPIO config commands
dwNumBytesToSend = 0;			// Reset output buffer pointer

配置GPIO

dwNumBytesToSend = 0;			// Start with a fresh index
// Set initial states of the MPSSE interface - high byte, both pin directions and output values
//		Pin name	Signal	Direction	Config	Initial State	Config
//		ACBUS0		GPIOH0	input		0						0
//		ACBUS1		GPIOH1	input		0						0
//		ACBUS2		GPIOH2	input		0						0
//		ACBUS3		GPIOH3	input		0						0
//		ACBUS4		GPIOH4	input		0						0
//		ACBUS5		GPIOH5	input		0						0
//		ACBUS6		GPIOH6	input		0						0
//		ACBUS7		GPIOH7	input		0						0

byOutputBuffer[dwNumBytesToSend++] = 0x82;	// Set data bits low-byte of MPSSE port
byOutputBuffer[dwNumBytesToSend++] = 0x00;	// Initial state config above
byOutputBuffer[dwNumBytesToSend++] = 0x00;	// Direction config above

ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);  // Send off the high GPIO config commands

dwNumBytesToSend = 0;			// Reset output buffer pointer

设置TCK时钟

// Set TCK frequency 
// TCK = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2)
byOutputBuffer[dwNumBytesToSend++] = '\x86'; //Command to set clock divisor
byOutputBuffer[dwNumBytesToSend++] = dwClockDivisor & 0xFF; 	//Set 0xValueL of clock divisor
byOutputBuffer[dwNumBytesToSend++] = (dwClockDivisor >> 8) & 0xFF; 	//Set 0xValueH of clock divisor
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); // Send off the clock divisor commands
dwNumBytesToSend = 0;			// Reset output buffer pointer

0xValueH表示高8位,0xValueL表示低8位. dwClockDivisor设定为0x05DB(即1499),TCK时钟频率设定为20KHz。

禁用Loopback

dwNumBytesToSend = 0;			// Reset output buffer pointer
// Disable internal loop-back
byOutputBuffer[dwNumBytesToSend++] = 0x85;	// Disable loopback
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);  // Send off the loopback command
dwNumBytesToSend = 0;	// Reset output buffer pointer

JTAG状态转换(Test-Logic-Reset -> Run-Test-Idle -> Select-DR-Scan -> Select-IR-Scan->Capture IR->Shift IR

// Navigage TMS through Test-Logic-Reset -> Run-Test-Idle -> Select-DR-Scan -> Select-IR-Scan
// TMS=1   TMS=0   TMS=1     TMS=1
byOutputBuffer[dwNumBytesToSend++] = 0x4B;	// Don't read data in Test-Logic-Reset, Run-Test-Idle, Select-DR-Scan, Select-IR-Scan
byOutputBuffer[dwNumBytesToSend++] = 0x05;	// Number of clock pulses = Length + 1 (6 clocks here)
byOutputBuffer[dwNumBytesToSend++] = 0x0D;	// Data is shifted LSB first, so the TMS pattern is 101100
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 	// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

JTAG状态机转换(Shift-IR

// TMS is currently low.  State machine is in Shift-IR, so now use the TDI/TDO command to shift 1's out TDI/DO while reading TDO/DI
// Although 8 bits need shifted in, only 7 are clocked here.  The 8th will be in conjunciton with a TMS command, coming next

byOutputBuffer[dwNumBytesToSend++] = 0x3B;		// Clock data out throuth states Capture-IR, Shift-IR and Exit-IR, read back result
byOutputBuffer[dwNumBytesToSend++] = 0x06;		// Number of clock pulses = Length + 1 (7 clocks here)
byOutputBuffer[dwNumBytesToSend++] = 0xFF;		// Shift out 1111111 (ignore last bit)
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 				// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

JTAG状态机转换(Exit 1-IR

// Here is the TMS command for one clock.  Data is also shifted in.
byOutputBuffer[dwNumBytesToSend++] = 0x6B;			// Clock out TMS, Read one bit.
byOutputBuffer[dwNumBytesToSend++] = 0x00;			// Number of clock pulses = Length + 0 (1 clock here)
byOutputBuffer[dwNumBytesToSend++] = 0x83;			// Data is shifted LSB first, so TMS becomes 1.  Also, bit 7 is shifted into TDI/DO, also a 1
	                						        // The 1 in bit 1 will leave TMS high for the next commands.
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 	// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

JTAG状态机转换(Update-IR->Select-DR-Scan->Capture DR->Shift-DR

// Navigage TMS from Exit-IR through Update-IR -> Select-DR-Scan -> Capture-DR
//					                 TMS=1        TMS=1             TMS=0

byOutputBuffer[dwNumBytesToSend++] = 0x4B;	// Don't read data in Update-IR -> Select-DR-Scan -> Capture-DR
byOutputBuffer[dwNumBytesToSend++] = 0x03;	// Number of clock pulses = Length + 1 (4 clocks here)
byOutputBuffer[dwNumBytesToSend++] = 0x83;	// Data is shifted LSB first, so the TMS pattern is 110
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);  // Send off the TMS command
dwNumBytesToSend = 0;	// Reset output buffer pointer

JTAG状态机转换(Shift-DR

// TMS is currently low.  State machine is in Shift-DR, so now use the TDI/TDO command to shift 101 out TDI/DO while reading TDO/DI
// Although 3 bits need shifted in, only 2 are clocked here.  The 3rd will be in conjunciton with a TMS command, coming next
byOutputBuffer[dwNumBytesToSend++] = 0x3B;	// Clock data out throuth states Shift-DR and Exit-DR.
byOutputBuffer[dwNumBytesToSend++] = 0x01;	// Number of clock pulses = Length + 1 (2 clocks here)
byOutputBuffer[dwNumBytesToSend++] = 0x01;	// Shift out 101 (ignore last bit)
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 	// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

JTAG状态机转换(Exit 1-DR

// Here is the TMS command for one clock.  Data is also shifted in.
byOutputBuffer[dwNumBytesToSend++] = 0x6B;	// Clock out TMS, Read one bit.
byOutputBuffer[dwNumBytesToSend++] = 0x00;	// Number of clock pulses = Length + 0 (1 clock here)
byOutputBuffer[dwNumBytesToSend++] = 0x83;		// Data is shifted LSB first, so TMS becomes 1.  Also, bit 7 is shifted into TDI/DO, also a 1
									            // The 1 in bit 1 will leave TMS high for the next commands.
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 	// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

JTAG状态机转换(Exit 1-DR->Update-DR->Select-DR-Scan -> Select-IR-Scan -> Test Logic Reset

// Navigage TMS through Update-DR -> Select-DR-Scan -> Select-IR-Scan -> Test Logic Reset
// TMS=1        TMS=1             TMS=1             TMS=1

byOutputBuffer[dwNumBytesToSend++] = 0x4B;		// Don't read data in Update-DR -> Select-DR-Scan -> Select-IR-Scan -> Test Logic Reset
byOutputBuffer[dwNumBytesToSend++] = 0x03;  	// Number of clock pulses = Length + 1 (4 clocks here)
byOutputBuffer[dwNumBytesToSend++] = 0xFF;		// Data is shifted LSB first, so the TMS pattern is 101100
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); 	// Send off the TMS command
dwNumBytesToSend = 0;			// Reset output buffer pointer

直至JTAG的状态机转换基本就结束了,大家可以将代码片段有序组合,按照要求嵌入到GUI应用程序。

洗锅刷碗

关于FT2232H的Visual Studio环境下C++编程基本就是看完了,大家可以在FTDI官网下载到AN-129的应用笔记以及HS_JTAG_MPSEE_Source的工程源代码。建议亲自实操测试,最好可以使用Demo板卡和示波器亲自调试。

  • 9
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值