FT2232H MPSSE JTAG例程代碼分析
/*
AN_129_HS_JTAG_with_MPSSE.cpp : Defines the entry point for the console application.
*/
/*
@Desc:包含必要的頭檔案
*/
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "ftd2xx.h"
/*
@Desc:Main Function
*/
int _tmain(int argc, _TCHAR* argv[])
{
FT_HANDLE ftHandle; // Handle of the FTDI device
FT_STATUS ftStatus; // Result of each D2XX call
DWORD dwNumDevs; // The number of devices
unsigned int uiDevIndex = 0xF; // The device in the list that we'll use
BYTE byOutputBuffer[1024]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H
BYTE byInputBuffer[1024]; // Buffer to hold data read from the FT2232H
DWORD dwCount = 0; // General loop index
DWORD dwNumBytesToSend = 0; // Index to the output buffer
DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write
DWORD dwNumBytesToRead = 0; // Number of bytes available to read in the driver's input buffer
DWORD dwNumBytesRead = 0; // Count of actual bytes read - used with FT_Read
DWORD dwClockDivisor = 0x05DB; // Value of clock divisor, SCL Frequency = 60/((1+0x05DB)*2) (MHz) = 20khz
// Does an FTDI device exist?
printf("Checking for FTDI devices...\n");
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);
FT_HANDLE ftHandleTemp;
DWORD numDevs;
DWORD Flags;
DWORD ID;
DWORD Type;
DWORD LocId;
char SerialNumber[16];
char Description[64];
ftStatus = FT_GetDeviceInfoDetail(3, &Flags, &Type, &ID, &LocId, SerialNumber, Description, &ftHandleTemp);
*/
// Open the port - For this application note, we'll assume the first device is a FT2232H or FT4232H
// Further checks can be made against the device descriptions, locations, serial numbers, etc.
// before opening the port.
printf("\nAssume first device has the MPSSE and open it...\n");
ftStatus = FT_Open(0, &ftHandle);
if (ftStatus != FT_OK)
{
printf("Open Failed with error %d\n", ftStatus);
return 1; // Exit with error
}
// Configure port parameters
printf("\nConfiguring port for MPSSE use...\n");
ftStatus |= FT_ResetDevice(ftHandle);
//Reset USB device
//Purge USB receive buffer first by reading out all old data from FT2232H receive buffer
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
/*
// -----------------------------------------------------------
// At this point, the MPSSE is ready for commands
// -----------------------------------------------------------
*/
/*
// -----------------------------------------------------------
// 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
}
/*
// -----------------------------------------------------------
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
do
{
ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead);
// Get the number of bytes in the device input buffer
} while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK));
//or Timeout
ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);
//Read out the data from input buffer
printf("\n");
printf("TI SN74BCT8244A IR default value is 0x81\n");
printf("The value scanned by the FT2232H is 0x%x\n", byInputBuffer[dwNumBytesRead - 3]);
printf("\n");
printf("TI SN74BCT8244A DR bypass expected data is 00000010 = 0x2\n");
printf(" The value scanned by the FT2232H = 0x%x\n", (byInputBuffer[dwNumBytesRead-1] >> 5));
// Generate a clock while in Test-Logic-Reset
// This will not do anything with the TAP in the Test-Logic-Reset state,
// but will demonstrate generation of clocks without any data transfer
byOutputBuffer[dwNumBytesToSend++] = 0x8F;
// Generate clock pulses
byOutputBuffer[dwNumBytesToSend++] = 0x02;
// (0x0002 + 1) * 8 = 24 clocks
byOutputBuffer[dwNumBytesToSend++] = 0x00;
//
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
// Send off the clock commands
dwNumBytesToSend = 0; // Reset output buffer pointer
/*
// -----------------------------------------------------------
// Start closing everything down
// -----------------------------------------------------------
*/
printf("\nJTAG program executed successfully.\n");
printf("Press <Enter> to continue\n");
getchar(); // wait for a carriage return
FT_Close(ftHandle); // Close the port
return 0; // Exit with success
}