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가 바뀐 것을 알 수 있다.
 


관련 글 

댓글

이 블로그의 인기 게시물

간단한 cfar 알고리즘에 대해

바로 프로젝트 적용 가능한 FIR Filter (low/high/band pass filter )를 c나 python으로 만들기

쉽게 설명한 파티클 필터(particle filter) 동작 원리와 예제

ARM NEON asm memcpy 코드

windows에서 간단하게 크롬캐스트(Chromecast)를 통해 윈도우 화면 미러링 방법