文章目录
前言
支持EEPROM配置的USB转串口设备型号有很多包括:CH340B、CH342F(USB转双串)、CH343P、CH344L/Q(USB转4串)、CH347T、CH348L/Q(USB转8串口)、CH9101U/R/Y、CH9102F、CH9103M(USB转双串)、CH‘9104L(USB转4串口)等型号。下面将使用CH343PT库中的接口去配置USB转串口设备CH9102F的EERPOM中的厂商字符串、产品字符串和Serial 字符串。
一、配置EEPROM接口函数介绍
1.1 芯片功能信息结构体
//芯片功能信息结构
typedef struct _USBSER_Property
{
UCHAR ChipType; //芯片型号,USER_TYPE_CHxxx
CHAR ChipTypeStr[32]; //芯片型号字符串
CHAR FwVerStr[32]; //固件版本字符串
UCHAR GpioCount; //GPIO脚数,如果大于0,此型号有专用GPIO脚或复用脚;为0表示芯片不支持GPIO引脚
BOOL IsEmbbedEeprom; //是否内置EEPROM,如支持,可进行设备信息的配置
BOOL IsSupportMcuBootCtrl; //是否支持Modem引脚作为103 MCU下载控制
CHAR ManufacturerString[64];//USB描述符内厂商字符串
CHAR ProductString[64]; //USB描述符内产品字符串
USHORT bcdDevice; //USB描述符内bcdDevice值
UCHAR PortIndex; //单串为0,如多串则为芯片第几个号串口
BOOL IsSupportGPIOInit; //是否支持GPIO上电初始化设置
CHAR PortName[32]; //串口号
ULONG ResvD[8]; //预留数据
}ChipPropertyS,*pChipPropertyS;
如果想过滤CH9102F,可以使用该结构体中ChipType去判断芯片是否是CH9102F。代码实现如下:
BOOL IsCH9102F(HANDLE hCom, pChipPropertyS ChipProperty)
{
CH343PT_GetChipProperty(hCom, ChipProperty);
if(ChipProperty->ChipType == USER_TYPE_CH9102F)
return TRUE;
else
return FALSE;
}
使用该函数会打开关闭未占用的串口(COM端口),如果想避免打开串口,可以用友好名称中CH9102F去过滤,如下图所示。
1.2 USB串口芯片配置EEPROM结构体
//除CH340和CH341之外的所有USB串口芯片配置EEPROM
typedef struct _USERCFG_343
{
UCHAR SIG; //对于 CH340B:内部配置信息有效标志,必须是 5BH。
//对于 CH340H/S:外部配置芯片有效标志,必须是 53H。
//对于 CH343??:外部配置芯片有效标志,必须是 53H。
//其它值则配置无效
UCHAR MODE; //串口模式,必须是23H
UCHAR CFG; //芯片功能配置字节
//BIT7:USB设备序列号字符串控制位;1=有效;0=无效;
//BIT6:USB产品信息字符串控制位;1=有效;0=无效;
//BIT5:USB厂商信息字符串控制位;1=有效;0=无效;
//BIT4:CDC模式下是否启用硬件流控;1=启用;0=禁止;
//BIT3:芯片引脚是否启用EEPROM的默认配置;如果启用则芯片上电后会根据EEPROM中的配置初始化引脚方向及电平状态,以及使能状态。具体配置值见后面说明。 1=启用;0=禁止;
UCHAR WP; //内部配置信息写保护标志,为 57H 则只读,否则可改写
UCHAR Vid[2]; //Vendor ID,厂商识别码,高字节在后,任意值。
UCHAR Pid[2]; //Product ID,产品识别码,高字节在后,任意值
UCHAR BCD[2]; //高字节在后,任意值
UCHAR Power; //Max Power,USB电流配置字,以2mA为单位的最大电源电流
UCHAR Attributes;// USB供电方式、睡眠唤醒等功能配置信息
//BIT7:必须设置成1;
//BIT6:1= Self-Powered;
//0=Bus-Powered;
//BIT5:1= Remote Wakeup Enable;
//0= Remote Wakeup Disable;
//BIT4-BIT0:必须设置成0;
UCHAR Reserved[4]; //保留字节00H或FFH
CHAR SN[24]; //USB设备序列号字符串.首字节是全部字节数(不超过16H),次字节开始为标准的USB字符串描述符格式(第1个字节为总长度,第2个字节固定为03H,第3个字节开始奇数为Unicode字符,偶数为0x00),如果不符合上述特征则使用厂商默认说明。
UCHAR PROD[40]; //USB产品信息字符串.首字节是全部字节数(不超过28H),次字节开始为标准的USB字符串描述符格式(第1个字节为总长度,第2个字节固定为03H,第3个字节开始奇数为Unicode字符,偶数为0x00),如果不符合上述特征则使用厂商默认说明。
UCHAR MAU[40]; //USB厂商信息字符串.首字节是全部字节数(不超过28H),次字节开始为标准的USB字符串描述符格式(第1个字节为总长度,第2个字节固定为03H,第3个字节开始奇数为Unicode字符,偶数为0x00),如果不符合上述特征则使用厂商默认说明。
}USERCFG_343,*pUSERCFG_343;
从结构体可以看出厂商字符串最多可以支持配置18个字节,产品字符串最多可以支持配置18个字节,Serial String最多可以支持配置10个字节。
1.3 进入芯片配置模式和退出芯片配置模式
调用CH343PT_EnterConfigMode函数成功后才能读取和写入EEPROM中的数据,成功调用CH343PT_ExitConfigMode函数后退出EEPROM配置模式。
//进入芯片配置模式:300bpsp;可进行非标准波特率配置和配置空间读写
BOOL WINAPI CH343PT_EnterConfigMode(HANDLE iPortH);
//退出芯片配置模式:300bps
BOOL WINAPI CH343PT_ExitConfigMode(HANDLE iPortH);
1.4 读取和写入芯片EEPROM中的信息
调用CH343PT_ReadDevConfig函数后可以读取芯片EEPROM中VID、PID、最大电流、厂商字符串、产品字符串、Serial字符串等信息。修改EEPROM中厂商字符串、产品字符串、Serial字符串需要调用CH343PT_WriteDevConfig函数。
//通过串口读取芯片EERPOM内设备配置数据
BOOL WINAPI CH343PT_ReadDevConfig(HANDLE iPortH, // 指定CH341设备序号
PULONG DataLen, // 要读取的数据长度
PUCHAR DataBuf); // 数据缓冲区
//通过串口向芯片EERPOM内写入设备的配置数据,写入前需确保写位保护位已关闭。
BOOL WINAPI CH343PT_WriteDevConfig(HANDLE iPortH,
ULONG BufferSize,
PUCHAR DataBuf);
二、使用上述接口去配置CH9102F的EEPROM
2.1 进入EEPROM配置和退出EEPROM配置模式
代码实现如下:
//打开串口进入EEPROM配置模式
BOOL OpenCH34xCom(HANDLE hCom, LPCTSTR ComName)
{
//打开串口
hCom = CreateFile(ComName, GENERIC_READ|GENERIC_WRITE,
0,NULL,OPEN_EXISTING,
NULL,
NULL);
if(hCom == INVALID_HANDLE_VALUE)
{
return FALSE;
}
CH343PT_EnterConfigMode(hCom); //进入EEPROM配置模式
return TRUE;
}
//关闭串口退出EEPROM配置模式
BOOL CloseCH34xCom(HANDLE hCom)
{
if (INVALID_HANDLE_VALUE != hCom)
{
CH343PT_ExitConfigMode(hCom); //退出EERPOM配置模式
If(!CloseHandle(hCom)) //关闭串口
return FALSE;
hCom = INVALID_HANDLE_VALUE;
}
return TRUE;
}
2.2 读写芯片中的EEPROM参数
//读EEPROM中厂商字符串
BOOL ReadEEPROMManuStr(USERCFG_343 *CH34XSetSerialStr, PCHAR ManuStrBuffer)
{
UCHAR StrSize, StrType;
//显示厂商字符串
StrSize = CH34XSetSerialStr->MAU[0];
StrType = CH34XSetSerialStr->MAU[2];
if( ( StrSize>0 ) && //字符串长度
( StrType == 0x03 ) )//固定字符串类型
wcstombs(&ManuStrBuffer[0],(WCHAR *)&CH34XSetSerialStr->MAU[3],(CH34XSetSerialStr->MAU[0] - 0)/2);
else //无效字符串
return FALSE;
return TRUE;
}
//读取EEPROM中的产品字符串
BOOL ReadEEPROMProdStr(USERCFG_343 *CH34XSetSerialStr, PCHAR ProdStrBuffer)
{
UCHAR StrSize, StrType;
//显示产品字符串
StrSize = CH34XSetSerialStr->PROD[0];
StrType = CH34XSetSerialStr->PROD[2];
if( ( StrSize>0 ) && //字符串长度
( StrType == 0x03 ) )//固定字符串类型
wcstombs(&ProdStrBuffer[0],(WCHAR *)&CH34XSetSerialStr->PROD[3],(CH34XSetSerialStr->PROD[0] - 2)/2);
else //无效字符串
return FALSE;
return TRUE;
}
//读取EEPROM中的SN字符串
BOOL ReadEEPROMSNStr(USERCFG_343 *CH34XSetSerialStr, PCHAR SNStrBuffer)
{
UCHAR StrSize, StrType;
//获取EERPROM中的SN字符串
StrSize = CH34XSetSerialStr->SN[0];
StrType = CH34XSetSerialStr->SN[2];
if( ( StrSize>0 ) && //字符串长度
( StrType == 0x03 ) )//固定字符串类型
sprintf(SNStrBuffer,"%S",&CH34XSetSerialStr->SN[3]);
else //无效字符串
return FALSE;
return TRUE;
}
//写EEPROM中的厂商字符串,产品字符串,SN字符串
BOOL WriteCH34xEEPROMStr(USERCFG_343 *CH34XSetSerialStr)
{
ULONG CH34xEepromSize;
CH34xEepromSize = sizeof(CH34XSetSerialStr); //获取配置空间大小
if( !CH343PT_WriteDevConfig(hCom,CH34xEepromSize,(PUCHAR)&CH34XSetSerialStr) ) //写EEPROM
{
return FALSE;
}
return TRUE;
}
三、软件实现
使用VC6++创建一个对话框,界面如下。
3.1 获取界面中配置信息
//读取EDIT控件中的厂商字符串,并传入CH34XSetSerialStr结构体中
VOID ReadManuEditConfig(USERCFG_343 *CH34XSetSerialStr,PCHAR MauBuffer, ULONG ManuStrLength)
{
//获取厂商字符串Manufacture String
memset(CH34XSetSerialStr->MAU, 0, sizeof(CH34XSetSerialStr->MAU));
mbstowcs((PWCHAR)(&CH34XSetSerialStr->MAU[3]),MauBuffer,ManuStrLength);
CH34XSetSerialStr->MAU[0] = ManuStrLength*2+2; //字符个数
CH34XSetSerialStr->MAU[1] = ManuStrLength*2+2; //字符个数
CH34XSetSerialStr->MAU[2] = 0x03; //字符串类型,固定03
CH34XSetSerialStr->CFG |= 0x20; //设置序列号有效标志
return;
}
//读取EDIT控件中的产品字符串,并传入CH34XSetSerialStr结构体中
VOID ReadProdEditConfig(USERCFG_343 *CH34XSetSerialStr,PCHAR ProdBuffer, ULONG ProdStrLength)
{
//获取产品字符串Product String
memset(CH34XSetSerialStr->PROD, 0, sizeof(CH34XSetSerialStr->PROD));
mbstowcs((PWCHAR)(&CH34XSetSerialStr->PROD[3]),ProdBuffer,ProdStrLength);
CH34XSetSerialStr->PROD[0] = ProdStrLength*2+2; //字符个数
CH34XSetSerialStr->PROD[1] = ProdStrLength*2+2; //字符个数
CH34XSetSerialStr->PROD[2] = 0x03; //字符串类型,固定03
CH34XSetSerialStr->CFG |= 0x40; //设置序列号有效标志
return;
}
//读取EDIT控件中的serial string字符串,并传入CH34XSetSerialStr结构体中
VOID ReadSNEditConfig(USERCFG_343 *CH34XSetSerialStr, PCHAR SNBuffer, ULONG SNStrLength)
{
//获取Serial String
memset(CH34XSetSerialStr->SN, 0, sizeof(CH34XSetSerialStr->SN));
mbstowcs((PWCHAR)(&CH34XSetSerialStr->SN[3]),SNBuffer,SNStrLength);
CH34XSetSerialStr->SN[0] = SNStrLength*2+2; //字符个数
CH34XSetSerialStr->SN[1] = SNStrLength*2+2; //字符个数
CH34XSetSerialStr->SN[2] = 0x03; //字符串类型,固定为0x03
CH34XSetSerialStr->CFG |= 0x80; //设置序列号有效标志
return;
}
//读取界面中的厂商、产品和Serial字符串
VOID ReadEditConfig(USERCFG_343 *CH34XSetSerialStr)
{
CHAR SerStr[1024] = {
0};
CHAR ProductStr[1024] = {
0};
CHAR MauBuffer[256] = ""; //需写入的厂商字符串
CHAR ProdBuffer[256] = "";
CHAR SNBuffer[256] = "";
CHAR Temp[20] = {
0};
CHAR buf[512] ="";
USHORT bcdDevice;
ULONG ManuStrLength,ProdStrLength,SNStrLength;
CH34XSetSerialStr->SIG = 0x53;
CH34XSetSerialStr->MODE = 0x23;
CH34XSetSerialStr->CFG = 0xE0;
*(PUSHORT)CH34XSetSerialStr->Pid = 0x55D4;
*(PUSHORT)CH34XSetSerialStr->Vid = 0x1A86;
//*(PUSHORT)CH34XSetSerialStr->BCD = 0x0442;
CH34XSetSerialStr->Power = 0x44;
CH34XSetSerialStr->Attributes = 0xA0;
//获取bcdDevice
CH343PT_GetUsbComDevBcd(hCom,&bcdDevice);
*(PUSHORT)CH34XSetSerialStr->BCD = bcdDevice;
//获取厂商字符串Manufacture String
memset(MauBuffer,0,sizeof(MauBuffer));
GetDlgItemText(AfxMainHwnd,IDC_ManuString,MauBuffer,sizeof(MauBuffer));
ManuStrLength = strlen(MauBuffer);
ReadManuEditConfig(CH34XSetSerialStr,MauBuffer,ManuStrLength);
//获取产品字符串Product String
memset(ProdBuffer,0,sizeof(ProdBuffer));
GetDlgItemText(AfxMainHwnd,IDC_ProductString,ProdBuffer,sizeof(ProdBuffer));
ProdStrLength = strlen(ProdBuffer);
ReadProdEditConfig(CH34XSetSerialStr,ProdBuffer,ProdStrLength);
//获取Serial String
memset(SNBuffer,0,sizeof(SNBuffer));
GetDlgItemText(AfxMainHwnd,IDC_SerialString,SNBuffer,sizeof(SNBuffer));
SNStrLength = strlen(SNBuffer);
ReadSNEditConfig(CH34XSetSerialStr,SNBuffer,SNStrLength);
return;
}
3.2 在界面中显示读取EEPROM中的厂商、产品和Serial字符串
//读EEPROM中厂商字符串,产品字符串,SN字符串
BOOL ReadEEPROMStr(HANDLE hCom, USERCFG_343 *CH34XSetSerialStr, LPCTSTR ComName)
{
CHAR TempStr[1024] = "";
CHAR ManuStrBuffer[64] = "";
CHAR ProdStrBuffer[256] = "";
CHAR SNStrBuffer[64] = "";
ULONG CH34xEepromSize,Retval;
if(!OpenCH34xCom(hCom,ComName))
{
goto Exit;
}
CH34xEepromSize = sizeof(CH34XSetSerialStr);
if( !CH343PT_ReadDevConfig(hCom,&CH34xEepromSize,(PUCHAR)&CH34XSetSerialStr) )
{
goto Exit;
}
//读EEPROM中厂商字符串,产品字符串,SN字符串
Retval = ReadEEPROMManuStr(CH34XSetSerialStr, ManuStrBuffer);
if(Retval)
SetDlgItemText(AfxMainHwnd,IDC_ManuString,ManuStrBuffer);
else
SetDlgItemText(AfxMainHwnd,IDC_ManuString,"");
Retval = ReadEEPROMProdStr(CH34XSetSerialStr, ProdStrBuffer);
if(Retval)
SetDlgItemText(AfxMainHwnd,IDC_ProductString,ProdStrBuffer);
else
SetDlgItemText(AfxMainHwnd,IDC_ProductString,"");
Retval = ReadEEPROMSNStr(CH34XSetSerialStr, SNStrBuffer);
if(Retval)
SetDlgItemText(AfxMainHwnd,IDC_SerialString,SNStrBuffer);
else
SetDlgItemText(AfxMainHwnd,IDC_SerialString,"");
CloseCH34xCom(hCom); //关闭串口并退出配置模式
return TRUE;
Exit:
CloseCH34xCom(hCom); //关闭串口并退出配置模式
return FALSE;
}
读取芯片默认的参数,如下图所示。
3.3 写入EEPROM配置
//写EEPROM中的厂商字符串,产品字符串,SN字符串
BOOL WriteEEPROMStr(USERCFG_343 CH34XSetSerialStr, LPCTSTR ComName)
{
USERCFG_343 CH34XSetSerialStr;
//打开串口进入EEPROM配置模式
if(!OpenCH34xCom(hCom, ComName))
{
CloseCH34xCom(hCom);
return FALSE;
}
ReadEditConfig(CH34XSetSerialStr); //读取界面中的厂商、产品和Serial字符串
WriteCH34xEEPROMStr(CH34XSetSerialStr)
{
CloseCH34xCom(hCom);
return FALSE;
}
CloseCH34xCom(hCom); //关闭串口并退出EEPROM配置模式
ResetFlag = TRUE;
return TRUE;
}
写入成功可以用USB View工具查看是否修改成功,如下图所示。
写入配置界面
USBView界面可以看出修改后厂商、产品和Serial字符串已经配置成功了。
上述demo函数调用方法去配置芯片EEPROM参数,同样适应于支持EEPROM配置的芯片(CH342、CH343、CH344、CH347、CH348、CH9101、CH9102、CH9103、CH9104)。