FT232H eeprom programming 시리얼 넘버 변경 예제
이번 글은 ft232h의 eeprom에 저장된 데이터 중 시리얼 넘버를 수정하는 예제
소스를 싣고 있다.
FT232H에는 EEPROM이 들어있고, 이 EEPROM에는 USB 장치의 속성 정보들이 저장되어
있다. 우리가 윈도우에서 장치 관리자를 통해 USB 장치의 속성을 볼 때 나오는 그런
정보들이 들어있으며, EEPROM에 들어있는 정보는 "ftd2xx.h" 헤더 파일에는 아래와
같이 선언되어 있다.
//
// structure to hold program data for FT_EE_Program, FT_EE_ProgramEx,
FT_EE_Read
// and FT_EE_ReadEx functions
//
typedef struct ft_program_data {
DWORD Signature1;
// Header - must be 0x00000000
DWORD Signature2;
// Header - must be 0xffffffff
DWORD Version;
// Header - FT_PROGRAM_DATA version
//
0 = original
//
1 = FT2232 extensions
//
2 = FT232R extensions
//
3 = FT2232H extensions
//
4 = FT4232H extensions
//
5 = FT232H extensions
WORD VendorId;
// 0x0403
WORD ProductId;
// 0x6001
char *Manufacturer;
// "FTDI"
char *ManufacturerId;
// "FT"
char *Description;
// "USB HS Serial Converter"
char *SerialNumber;
// "FT000001" if fixed, or NULL
WORD MaxPower;
// 0 < MaxPower <= 500
WORD PnP;
// 0 = disabled, 1 = enabled
WORD SelfPowered;
// 0 = bus powered, 1 = self powered
WORD RemoteWakeup;
// 0 = not capable, 1 = capable
//
// Rev4 (FT232B) extensions
//
UCHAR Rev4;
// non-zero if Rev4 chip, zero otherwise
UCHAR IsoIn;
// non-zero if in endpoint is isochronous
UCHAR IsoOut;
// non-zero if out endpoint is isochronous
UCHAR PullDownEnable;
// non-zero if pull down enabled
UCHAR SerNumEnable;
// non-zero if serial number to be used
UCHAR USBVersionEnable;
// non-zero if chip uses USBVersion
WORD USBVersion;
// BCD (0x0200 => USB2)
//
// Rev 5 (FT2232) extensions
//
UCHAR Rev5;
// non-zero if Rev5 chip, zero otherwise
UCHAR IsoInA;
// non-zero if in endpoint is isochronous
UCHAR IsoInB;
// non-zero if in endpoint is isochronous
UCHAR IsoOutA;
// non-zero if out endpoint is isochronous
UCHAR IsoOutB;
// non-zero if out endpoint is isochronous
UCHAR PullDownEnable5;
// non-zero if pull down enabled
UCHAR SerNumEnable5;
// non-zero if serial number to be used
UCHAR USBVersionEnable5;
// non-zero if chip uses USBVersion
WORD USBVersion5;
// BCD (0x0200 => USB2)
UCHAR AIsHighCurrent;
// non-zero if interface is high current
UCHAR BIsHighCurrent;
// non-zero if interface is high current
UCHAR IFAIsFifo;
// non-zero if interface is 245 FIFO
UCHAR IFAIsFifoTar;
// non-zero if interface is 245 FIFO CPU target
UCHAR IFAIsFastSer;
// non-zero if interface is Fast serial
UCHAR AIsVCP;
// non-zero if interface is to use VCP drivers
UCHAR IFBIsFifo;
// non-zero if interface is 245 FIFO
UCHAR IFBIsFifoTar;
// non-zero if interface is 245 FIFO CPU target
UCHAR IFBIsFastSer;
// non-zero if interface is Fast serial
UCHAR BIsVCP;
// non-zero if interface is to use VCP drivers
//
// Rev 6 (FT232R) extensions
//
UCHAR UseExtOsc;
// Use External Oscillator
UCHAR HighDriveIOs;
// High Drive I/Os
UCHAR EndpointSize;
// Endpoint size
UCHAR PullDownEnableR;
// non-zero if pull down enabled
UCHAR SerNumEnableR;
// non-zero if serial number to be used
UCHAR InvertTXD;
// non-zero if invert TXD
UCHAR InvertRXD;
// non-zero if invert RXD
UCHAR InvertRTS;
// non-zero if invert RTS
UCHAR InvertCTS;
// non-zero if invert CTS
UCHAR InvertDTR;
// non-zero if invert DTR
UCHAR InvertDSR;
// non-zero if invert DSR
UCHAR InvertDCD;
// non-zero if invert DCD
UCHAR InvertRI;
// non-zero if invert RI
UCHAR Cbus0;
// Cbus Mux control
UCHAR Cbus1;
// Cbus Mux control
UCHAR Cbus2;
// Cbus Mux control
UCHAR Cbus3;
// Cbus Mux control
UCHAR Cbus4;
// Cbus Mux control
UCHAR RIsD2XX;
// non-zero if using D2XX driver
//
// Rev 7 (FT2232H) Extensions
//
UCHAR PullDownEnable7;
// non-zero if pull down enabled
UCHAR SerNumEnable7;
// non-zero if serial number to be used
UCHAR ALSlowSlew;
// non-zero if AL pins have slow slew
UCHAR ALSchmittInput;
// non-zero if AL pins are Schmitt input
UCHAR ALDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR AHSlowSlew;
// non-zero if AH pins have slow slew
UCHAR AHSchmittInput;
// non-zero if AH pins are Schmitt input
UCHAR AHDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR BLSlowSlew;
// non-zero if BL pins have slow slew
UCHAR BLSchmittInput;
// non-zero if BL pins are Schmitt input
UCHAR BLDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR BHSlowSlew;
// non-zero if BH pins have slow slew
UCHAR BHSchmittInput;
// non-zero if BH pins are Schmitt input
UCHAR BHDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR IFAIsFifo7;
// non-zero if interface is 245 FIFO
UCHAR IFAIsFifoTar7;
// non-zero if interface is 245 FIFO CPU target
UCHAR IFAIsFastSer7;
// non-zero if interface is Fast serial
UCHAR AIsVCP7;
// non-zero if interface is to use VCP drivers
UCHAR IFBIsFifo7;
// non-zero if interface is 245 FIFO
UCHAR IFBIsFifoTar7;
// non-zero if interface is 245 FIFO CPU target
UCHAR IFBIsFastSer7;
// non-zero if interface is Fast serial
UCHAR BIsVCP7;
// non-zero if interface is to use VCP drivers
UCHAR PowerSaveEnable;
// non-zero if using BCBUS7 to save power for self-powered designs
//
// Rev 8 (FT4232H) Extensions
//
UCHAR PullDownEnable8;
// non-zero if pull down enabled
UCHAR SerNumEnable8;
// non-zero if serial number to be used
UCHAR ASlowSlew;
// non-zero if A pins have slow slew
UCHAR ASchmittInput;
// non-zero if A pins are Schmitt input
UCHAR ADriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR BSlowSlew;
// non-zero if B pins have slow slew
UCHAR BSchmittInput;
// non-zero if B pins are Schmitt input
UCHAR BDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR CSlowSlew;
// non-zero if C pins have slow slew
UCHAR CSchmittInput;
// non-zero if C pins are Schmitt input
UCHAR CDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR DSlowSlew;
// non-zero if D pins have slow slew
UCHAR DSchmittInput;
// non-zero if D pins are Schmitt input
UCHAR DDriveCurrent;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR ARIIsTXDEN;
// non-zero if port A uses RI as RS485 TXDEN
UCHAR BRIIsTXDEN;
// non-zero if port B uses RI as RS485 TXDEN
UCHAR CRIIsTXDEN;
// non-zero if port C uses RI as RS485 TXDEN
UCHAR DRIIsTXDEN;
// non-zero if port D uses RI as RS485 TXDEN
UCHAR AIsVCP8;
// non-zero if interface is to use VCP drivers
UCHAR BIsVCP8;
// non-zero if interface is to use VCP drivers
UCHAR CIsVCP8;
// non-zero if interface is to use VCP drivers
UCHAR DIsVCP8;
// non-zero if interface is to use VCP drivers
//
// Rev 9 (FT232H) Extensions
//
UCHAR PullDownEnableH;
// non-zero if pull down enabled
UCHAR SerNumEnableH;
// non-zero if serial number to be used
UCHAR ACSlowSlewH;
// non-zero if AC pins have slow slew
UCHAR ACSchmittInputH;
// non-zero if AC pins are Schmitt input
UCHAR ACDriveCurrentH;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR ADSlowSlewH;
// non-zero if AD pins have slow slew
UCHAR ADSchmittInputH;
// non-zero if AD pins are Schmitt input
UCHAR ADDriveCurrentH;
// valid values are 4mA, 8mA, 12mA, 16mA
UCHAR Cbus0H;
// Cbus Mux control
UCHAR Cbus1H;
// Cbus Mux control
UCHAR Cbus2H;
// Cbus Mux control
UCHAR Cbus3H;
// Cbus Mux control
UCHAR Cbus4H;
// Cbus Mux control
UCHAR Cbus5H;
// Cbus Mux control
UCHAR Cbus6H;
// Cbus Mux control
UCHAR Cbus7H;
// Cbus Mux control
UCHAR Cbus8H;
// Cbus Mux control
UCHAR Cbus9H;
// Cbus Mux control
UCHAR IsFifoH;
// non-zero if interface is 245 FIFO
UCHAR IsFifoTarH;
// non-zero if interface is 245 FIFO CPU target
UCHAR IsFastSerH;
// non-zero if interface is Fast serial
UCHAR IsFT1248H;
// non-zero if interface is FT1248
UCHAR FT1248CpolH;
// FT1248 clock polarity - clock idle high (1) or clock idle low (0)
UCHAR FT1248LsbH;
// FT1248 data is LSB (1) or MSB (0)
UCHAR FT1248FlowControlH;
// FT1248 flow control enable
UCHAR IsVCPH;
// non-zero if interface is to use VCP drivers
UCHAR PowerSaveEnableH;
// non-zero if using ACBUS7 to save power for self-powered designs
} FT_PROGRAM_DATA, *PFT_PROGRAM_DATA;
FT232H 장치에서 EEPROM 정보를 읽고 쓰는 함수 소스는 아래와 같다.
드라이버 및 라이브러리 다운로드 및 프로젝트 설정은 https://ryanclaire.blogspot.com/2020/06/ft232h-d2xx-gpio-example.html를 참조하면 된다.
#include "ftd2xx.h"
데이터 구조체 선언
typedef struct _ft232hdev_t
{
long locid;
FT_PROGRAM_DATA EEPData;
char ManufacturerBuffer[32];
char ManufacturerIdBuffer[16];
char DescriptionBuffer[64];
char SerialNumberBuffer[16];
}ft232hdev_t;
typedef struct _ft232h_dev_list_t
{
int counter;
ft232hdev_t *devs;
}_ft232h_dev_list;
PC에 연결된 FT232H 장치 찾는 함수
_ft232h_dev_list *probe_FT232H()
{
int i = 0;
int availdevs = 0;
DWORD numDevs = 0;
FT_STATUS ftStatus = 0;
_ft232h_dev_list *list = NULL;
ftStatus =
FT_CreateDeviceInfoList(&numDevs);
if (ftStatus != FT_OK || numDevs == 0)
{
return NULL;
}
list =
(_ft232h_dev_list*)malloc(sizeof(_ft232h_dev_list));
if (!list)
{
return NULL;
}
list->counter = numDevs;
list->devs =
(ft232hdev_t*)malloc(sizeof(ft232hdev_t)*numDevs);
if (!list->devs)
{
free(list);
return NULL;
}
memset(list->devs, 0,
sizeof(ft232hdev_t)*numDevs);
for (i = 0; i < numDevs &&
i<16; i++)
{
DWORD Flags;
DWORD ID;
DWORD Type;
DWORD LocId;
char sn[16];
ftStatus = FT_GetDeviceInfoDetail(i,
&Flags, &Type, &ID, &LocId, sn, NULL, NULL);
if (ftStatus == FT_OK)
{
list->devs[i].locid = LocId;
memcpy(list->devs[i].SerialNumberBuffer, sn, sizeof(char) * 16);
/*
Manufacturer/ ManufacturerId/ Description/ SerialNumber의 버퍼는 따로 지정해야
줘야 한다.
*/
list->devs[i].EEPData.Signature1 =
0x00000000;
list->devs[i].EEPData.Signature2 =
0xffffffff;
list->devs[i].EEPData.Manufacturer
= list->devs[i].ManufacturerBuffer;
list->devs[i].EEPData.ManufacturerId =
list->devs[i].ManufacturerIdBuffer;
list->devs[i].EEPData.Description =
list->devs[i].DescriptionBuffer;
list->devs[i].EEPData.SerialNumber
= list->devs[i].SerialNumberBuffer;
}
}
return list;
}
FT232H 장치의 EEPROM 정보를 FT_PROGRAM_DATA 구조체 데이터에 읽어오는 함수
FT_STATUS GetEEPROMInfo(ft232hdev_t *dev)
{
FT_HANDLE ftdiHandle = NULL;
FT_STATUS ftStatus =
FT_INVALID_HANDLE;
if (!dev) return FT_INVALID_ARGS;
if (dev->locid)
{
ftStatus =
FT_OpenEx((PVOID)dev->locid, FT_OPEN_BY_LOCATION, &ftdiHandle);
}
else if
(dev->SerialNumberBuffer[0])
{
ftStatus =
FT_OpenEx(dev->SerialNumberBuffer, FT_OPEN_BY_SERIAL_NUMBER,
&ftdiHandle);
}
if (ftStatus != FT_OK)
{
if (ftdiHandle)
{
FT_Close(ftdiHandle);
ftdiHandle = NULL;
}
return ftStatus;
}
/**/
ftStatus = FT_EE_Read(ftdiHandle,
&dev->EEPData);
if (ftStatus == FT_OK)
{
printf("VendorId : 0x%x \r\n",
dev->EEPData.VendorId);
printf("ProductId : 0x%x \r\n",
dev->EEPData.ProductId);
printf("SerialNumber : %s \r\n",
dev->EEPData.SerialNumber);
printf("Description : %s \r\n",
dev->EEPData.Description);
}
else
{
printf("EEPROM Read Fail \r\n");
}
FT_Close(ftdiHandle);
return ftStatus;
}
FT232H 장치의 EEPROM에 데이터를 저장하는 함수
FT_STATUS ProgramEEPROM(ft232hdev_t *dev)
{
FT_HANDLE ftdiHandle = NULL;
FT_STATUS ftStatus =
FT_INVALID_HANDLE;
if (!dev) return FT_INVALID_ARGS;
if (dev->locid)
{
ftStatus =
FT_OpenEx((PVOID)dev->locid, FT_OPEN_BY_LOCATION, &ftdiHandle);
}
else if
(dev->SerialNumberBuffer[0])
{
ftStatus =
FT_OpenEx(dev->SerialNumberBuffer, FT_OPEN_BY_SERIAL_NUMBER,
&ftdiHandle);
}
if (ftStatus != FT_OK)
{
if (ftdiHandle)
{
FT_Close(ftdiHandle);
ftdiHandle = NULL;
}
return ftStatus;
}
ftStatus = FT_EE_Program(ftdiHandle,
&dev->EEPData);
if (ftStatus == FT_OK)
{
printf("Program EEPROM SUCCESS !!
\r\n");
}
else
{
printf("Program EEPROM fail !! \r\n");
}
FT_Close(ftdiHandle);
return ftStatus;
}
FT232H 시리얼 넘버 변경 예제 소스
void reprogram_ft232h_eeprom()
{
_ft232h_dev_list *list =
probe_FT232H();
if (list)
{
for (int i = 0; i <
list->counter; i++)
{
printf("GetEEPROMInfo locid %d\r\n",
list->devs[i].locid);
GetEEPROMInfo(&list->devs[i]);
}
//
sprintf_s(list->devs[0].ManufacturerBuffer, "FTDI");
sprintf_s(list->devs[0].ManufacturerIdBuffer, "FT");
sprintf_s(list->devs[0].DescriptionBuffer, "USB HS Serial Converter");
sprintf_s(list->devs[0].SerialNumberBuffer, "RYANCLAIRE");
printf("ProgramEEPROM locid %d\r\n",
list->devs[0].locid);
ProgramEEPROM(&list->devs[0]);
Sleep(100);
printf("GetEEPROMInfo locid %d\r\n",
list->devs[0].locid);
GetEEPROMInfo(&list->devs[0]);
}
safe_free(list);
}
위 예제 소스의 실행 결과는 아래와 같다.
장치 관리자에서도 데이터의 Serial Number가 바뀐 것을 알 수 있다.
관련 글
댓글
댓글 쓰기