/***************************************************************************** ** Copyright (C) WCH 2001-2025 ** ** Web: http://wch.cn ** ****************************************************************************** Abstract: CH347/CH339W SPI/I2C接口数据流操作 Environment: user mode only,VC6.0 and later Notes: Copyright (c) 2025 Nanjing Qinheng Microelectronics Co., Ltd. Revision History: 4/3/2022: TECH30 --*/ #include "Main.h" #define WM_CH347DevArrive WM_USER+10 //设备插入通知事件,窗体进程接收 #define WM_CH347DevRemove WM_USER+11 //设备拔出通知事件,窗体进程接收 #define CH347DevID "VID_1A86&PID_55\0" //监视CH347&CH339W USB插拔动作,插入时可自动打开设备;关闭时自动关闭设备 //如需准确监测各模式下串口插拔动作,可写如下完整USBID。因DEMO汇总了所有模式,所以只需取ID共同部分 //设置指定设备的USB插拔监测: CH347SetDeviceNotify(,USBID_Mode???,) //取消指定设备的USB插拔监测: CH347SetDeviceNotify(,USBID_Mode???,) //#define USBID_VCP_Mode0_UART0 "VID_1A86&PID_55DA&MI_00\0" //MODE0 UART0 //#define USBID_VCP_Mode0_UART1 "VID_1A86&PID_55DA&MI_01\0" //MODE0 UART1 //#define USBID_VCP_Mode0_UART "VID_1A86&PID_55DA\0" //MODE0 UART //#define USBID_VEN_Mode1_UART1 "VID_1A86&PID_55DB&MI_00\0" //MODE1 UART //#define USBID_HID_Mode2_UART1 "VID_1A86&PID_55DB&MI_00\0" //MODE2 UART //#define USBID_VEN_Mode3_UART1 "VID_1A86&PID_55DB&MI_00\0" //MODE3 UART //如需准确监测各模式下接口插拔动作,可写如下完整USBID。因DEMO汇总了所有模式,所以只需取ID共同部分 //设置指定设备的USB插拔监测: CH347Uart_SetDeviceNotify(,USBID_Mode???,) //取消指定设备的USB插拔监测: CH347Uart_SetDeviceNotify(,USBID,) //#define USBID_VEN_Mode1_SPI_I2C "VID_1A86&PID_55DA&MI_00\0" //MODE1 SPI/I2C //#define USBID_HID_Mode2_SPI_I2C "VID_1A86&PID_55DA&MI_00\0" //MODE2 SPI/I2C //#define USBID_VEN_Mode3_JTAG_I2C "VID_1A86&PID_55DA&MI_00\0" //MODE3 JTAG/I2C extern BOOL g_isChinese; extern HINSTANCE AfxMainIns; //进程实例 extern HWND AfxActiveHwnd; extern HWND JtagDlgHwnd; extern HWND FlashEepromDbgHwnd; extern HWND UartDebugHwnd; extern BOOL EnablePnPAutoOpen_Jtag; //启用插拔后设备自动打开关闭功能 extern BOOL EnablePnPAutoOpen_Uart; //启用插拔后设备自动打开关闭功能 extern BOOL EnablePnPAutoOpen_Flash; //启用插拔后设备自动打开关闭功能 //全局变量 HWND SpiI2cGpioDebugHwnd; //窗体句柄 BOOL DevIsOpened; //设备是否打开 BOOL SpiIsCfg; BOOL I2CIsCfg; ULONG SpiI2cGpioDevIndex; mDeviceInforS SpiI2cDevInfor[16] = {0}; BOOL EnablePnPAutoOpen; //启用插拔后设备自动打开关闭功能 BOOL IntIsEnable=FALSE; //中断使能 // CH347设备插拔检测通知程序.因回调函数对函数操作有限制,通过窗体消息转移到消息处理函数内进行处理。 VOID CALLBACK UsbDevPnpNotify (ULONG iEventStatus ) { if(iEventStatus==CH347_DEVICE_ARRIVAL)// 设备插入事件,已经插入 PostMessage(SpiI2cGpioDebugHwnd,WM_CH347DevArrive,0,0); else if(iEventStatus==CH347_DEVICE_REMOVE)// 设备拔出事件,已经拔出 PostMessage(SpiI2cGpioDebugHwnd,WM_CH347DevRemove,0,0); return; } //打开设备 BOOL OpenDevice() { //获取设备序号 SpiI2cGpioDevIndex = SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_ObjList,CB_GETCURSEL,0,0); if(SpiI2cGpioDevIndex==CB_ERR) { if (g_isChinese) DbgPrint("打开设备失败,请先选择设备"); else DbgPrint("Failed to open the device, please select the device first"); goto Exit; //退出 } DevIsOpened = (CH347OpenDevice(SpiI2cGpioDevIndex) != INVALID_HANDLE_VALUE); CH347SetTimeout(SpiI2cGpioDevIndex,500,500); DbgPrint(">>Open the device...%s",DevIsOpened?"Success":"Failed"); CH347InitSpi(); Exit: return DevIsOpened; } //关闭设备 BOOL CloseDevice() { CH347CloseDevice(SpiI2cGpioDevIndex); if(IntIsEnable) SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_DisableIntNotify,BM_CLICK,0,0); IntIsEnable = FALSE; DevIsOpened = FALSE; DbgPrint(">>Close the Device"); return TRUE; } BOOL CH347InitSpi() { BOOL RetVal = FALSE; mSpiCfgS SpiCfg = {0}; mSpiCfgS TestSpiCfg = {0}; UCHAR HwVer = 0; CHAR Frequency[32]=""; DOUBLE SpiFrequency = 0; // 设置的频率 UCHAR SpiDatabits = 0; // 设置的数据位 默认0 SpiCfg.iMode = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_Mode,CB_GETCURSEL,0,0); SpiCfg.iClock = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_Clock,CB_GETCURSEL,0,0); SpiCfg.iByteOrder = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_ByteBitOrder,CB_GETCURSEL,0,0); SpiCfg.iSpiWriteReadInterval = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_SpiCfg_OutInIntervalT,NULL,FALSE); SpiCfg.iSpiOutDefaultData = 0xFF; SpiCfg.iChipSelect = SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_ChipIndex,CB_GETCURSEL,0,0); SpiCfg.CS1Polarity = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_CS1Polarity,CB_GETCURSEL,0,0); SpiCfg.CS2Polarity = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_CS2Polarity,CB_GETCURSEL,0,0); if(IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_EnableCS)==BST_CHECKED) SpiCfg.iChipSelect |= 0x80; SpiCfg.iIsAutoDeativeCS = (IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_AutoDeativeCS)==BST_CHECKED); SpiCfg.iActiveDelay = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_SpiCfg_ActiveDelay,NULL,FALSE); SpiCfg.iDelayDeactive = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_SpiCfg_DelayDeactive,NULL,FALSE); // 若使能设置其他速率,则调用CH347SPISetFrequency if (IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_SpiCfg_SetFreq) == BST_CHECKED) { // 设置SPI频率 GetDlgItemText(SpiI2cGpioDebugHwnd, IDC_SpiCfg_Frequency, Frequency, 10); SpiFrequency = atof(Frequency); DbgPrint("SpiFrequency %.2f\n", SpiFrequency); // 获取设置单位 if (SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_frequencyUnit,CB_GETCURSEL,0,0)) RetVal = CH347SPI_SetFrequency(SpiI2cGpioDevIndex, KHZ(SpiFrequency)); else RetVal = CH347SPI_SetFrequency(SpiI2cGpioDevIndex, MHZ(SpiFrequency)); } else { RetVal = CH347SPI_SetFrequency(SpiI2cGpioDevIndex, 0); } // 设置SPI 数据位 SpiDatabits = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_Databits,CB_GETCURSEL,0,0); RetVal = CH347SPI_SetDataBits(SpiI2cGpioDevIndex, SpiDatabits); RetVal = CH347SPI_Init(SpiI2cGpioDevIndex,&SpiCfg); CH347SPI_GetCfg(SpiI2cGpioDevIndex, &TestSpiCfg); DbgPrint("iByteOrder:%02x.\n", TestSpiCfg.iByteOrder); DbgPrint("CH347SPI_Init %s",RetVal?"succ":"failure"); return RetVal; } // 添加此处对齐SPI初始化操作 BOOL CH347InitI2C() { BOOL RetVal = FALSE; BOOL isStrentch = FALSE; ULONG iMode; // I2C模式 ULONG I2CDelayMs = 0; iMode = SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_I2CCfg_Clock,CB_GETCURSEL,0,0); isStrentch = SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_I2CCfg_SclStretch,CB_GETCURSEL,0,0) ? FALSE : TRUE ; I2CDelayMs = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_I2CCfg_Delay,NULL,FALSE); RetVal = CH347I2C_Set(SpiI2cGpioDevIndex, iMode); DbgPrint("CH347I2C Set clock %s",RetVal ? "succ" : "failure"); DbgPrint("CH347 I2C set stetching %s",RetVal ? "succ" : "failure"); if (I2CDelayMs > 0) RetVal = CH347I2C_SetDelaymS(SpiI2cGpioDevIndex, I2CDelayMs); DbgPrint("CH347InitI2C %s",RetVal ? "succ" : "failure"); return RetVal; } BOOL CH347SpiCsCtrl() { USHORT iEnableSelect; // 低八位为CS1,高八位为CS2; 字节值为1=设置CS,为0=忽略此CS设置 USHORT iChipSelect; // 低八位为CS1,高八位为CS2;片选输出,0=L,1=H USHORT iIsAutoDeativeCS; // 低八位为CS1,高八位为CS2;操作完成后是否自动撤消片选 ULONG iActiveDelay; // 低八位为CS1,高八位为CS2;设置片选后执行读写操作的延时时间 ULONG iDelayDeactive; // 低八位为CS1,高八位为CS2;撤消片选后执行读写操作的延时时间 UCHAR CsSel; BOOL RetVal; mSpiCfgS SpiCfg = {0}; CsSel = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCfg_ChipIndex,CB_GETCURSEL,0,0); iEnableSelect = ( IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_EnableCS)==BST_CHECKED ); iChipSelect = (UCHAR)SendDlgItemMessage(SpiI2cGpioDebugHwnd,IDC_SpiCsStatus,CB_GETCURSEL,0,0); iIsAutoDeativeCS = (IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_AutoDeativeCS)==BST_CHECKED); iActiveDelay = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_SpiCfg_ActiveDelay,NULL,FALSE)&0xFF; iDelayDeactive = GetDlgItemInt(SpiI2cGpioDebugHwnd,IDC_SpiCfg_DelayDeactive,NULL,FALSE)&0xFF; if(iEnableSelect) { if( CsSel ) { iEnableSelect = 0x0100; iChipSelect = (iChipSelect<<8)&0xFF00; iIsAutoDeativeCS = (iIsAutoDeativeCS<<8)&0xFF00; iActiveDelay = (iActiveDelay<<16)&0xFFFF0000; iDelayDeactive = (iDelayDeactive<<16)&0xFFFF0000; } else { iEnableSelect = 0x01; } } else iEnableSelect = 0; RetVal = CH347SPI_SetChipSelect(SpiI2cGpioDevIndex,iEnableSelect,iChipSelect,iIsAutoDeativeCS,iActiveDelay,iDelayDeactive); DbgPrint("CH347SPI_ConfigCS %s",RetVal?"succ":"failure"); return RetVal; } BOOL CH347SpiStream(ULONG CmdCode) { ULONG SpiOutLen,SpiInLen,FlashAddr=0,i,StrLen; UCHAR InBuf[4096] = "",OutBuf[4096] = ""; CHAR FmtStr[4096*3*6] = "",ValStr[16]="",FmtStr2[4096*3*6]; double BT,UseT; UCHAR ChipSelect; BOOL RetVal = FALSE; if(IsDlgButtonChecked(SpiI2cGpioDebugHwnd,IDC_EnableCS)==BST_CHECKED ) ChipSelect = 0x80; else ChipSelect = 0x00; StrLen = GetDlgItemText(SpiI2cGpioDebugHwnd,IDC_SpiOut,FmtStr,sizeof(FmtStr)); if(StrLen > 4096*3) StrLen = 4096*3; SpiOutLen = 0; for(i=0;i4096) SpiInLen = 4096; SetDlgItemText(SpiI2cGpioDebugHwnd,IDC_SpiIn,""); memset(FmtStr,0,sizeof(FmtStr)); BT = GetCurrentTimerVal(); if(CmdCode == 0xC2) { SpiInLen = SpiOutLen; //输出字节数与输入字节数相等 if(SpiOutLen<1) { DbgPrint("SPI read length not specified"); return FALSE; } memcpy(InBuf,OutBuf,SpiOutLen); RetVal = CH347StreamSPI4(SpiI2cGpioDevIndex,0x80,SpiOutLen,InBuf); sprintf(FmtStr,"Cmd%X(StreamSpi) %s.",CmdCode,RetVal?"succ":"failure"); } else if(CmdCode == 0xC3) { if(SpiInLen<1) { DbgPrint("SPI read length not specified"); return FALSE; } if (SpiOutLen < 1) SpiOutLen = 0; memcpy(InBuf, OutBuf, SpiOutLen); RetVal = CH347SPI_Read(SpiI2cGpioDevIndex,ChipSelect,SpiOutLen,&SpiInLen,InBuf); sprintf(FmtStr,"Cmd%X(StreamSpiBulkRead) %s.",CmdCode,RetVal?"succ":"failure"); } else if(CmdCode == 0xC4) { if(SpiOutLen<1) { DbgPrint("SPI read length not specified"); return FALSE; } SpiInLen = 0; RetVal = CH347SPI_Write(SpiI2cGpioDevIndex,ChipSelect,SpiOutLen,512,OutBuf); sprintf(FmtStr,"Cmd%X(StreamSpiBulkWrite) %s.",CmdCode,RetVal?"succ":"failure"); } else return FALSE; UseT = GetCurrentTimerVal()-BT; sprintf(&FmtStr[strlen(FmtStr)],",Time %.3fS.",UseT/1000); if(RetVal) { if(SpiOutLen) {//打印 sprintf(&FmtStr[strlen(FmtStr)],"\r\n OutData(%d):",SpiOutLen); //16进制显示 for(i=0;i 4096*3) StrLen = 4096*3; OutLen = 0; for(i=0;i4096) InLen = 4096; if((OutLen+InLen)<1) { DbgPrint("Read length not specified"); return FALSE; } BT = GetCurrentTimerVal(); RetVal = CH347StreamI2C(SpiI2cGpioDevIndex,OutLen,OutBuf,InLen,InBuf); UseT = GetCurrentTimerVal()-BT; if(RetVal) { if(InLen) {//打印 memset(FmtStr,0,sizeof(FmtStr)); for(i=0;icode == PSN_SETACTIVE) AfxActiveHwnd = hWnd; } break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDC_RefreshObjList: EnumDevice(); //枚举并显示设备 break; case IDC_ObjList: ShowDevInfor(); break; case IDC_EnablePnPAutoOpen: EnablePnPAutoOpen = (IsDlgButtonChecked(hWnd,IDC_EnablePnPAutoOpen)==BST_CHECKED); break; case IDC_OpenDevice://打开设备 OpenDevice(); EnableButtonEnable(); //更新按钮状态 break; case IDC_CloseDevice: CloseDevice(); EnableButtonEnable(); //更新按钮状态 break; case IDC_FlashIdentify: FlashIdentify(); break; case IDC_FlashRead: FlashBlockRead(); break; case IDC_FlashWrite://将IDC_FLASHDATA框内数据写入FLASH FlashBlockWrite(); break; case IDC_FlashErase: FlashBlockErase(); break; case IDC_CMD_InitSPI: SpiIsCfg = CH347InitSpi(); // CH347I2C_Set(SpiI2cGpioDevIndex,3); //配置I2C速度为快速750K EnableButtonEnable(); break; case IDC_I2CInit: I2CIsCfg = CH347InitI2C(); // 单独的初始化I2C操作 EnableButtonEnable(); break; case IDC_CMD_SPICsCtrl: CH347SpiCsCtrl(); EnableButtonEnable(); break; case IDC_CMD_SPIStream: CH347SpiStream(0xC2); break; case IDC_CMD_BulkSpiIn: CH347SpiStream(0xC3); break; case IDC_CMD_BulkSpiOut: CH347SpiStream(0xC4); break; case IDC_FlashVerify: CloseHandle(CreateThread(NULL,0,FlashVerifyWithFile,NULL,0,&ThreadID)); //开始USB下载 break; case IDC_WriteFormFile: CloseHandle(CreateThread(NULL,0,WriteFlashFromFile,NULL,0,&ThreadID)); //开始USB下载 break; case IDC_ReadToFile: CloseHandle(CreateThread(NULL,0,ReadFlashToFile,NULL,0,&ThreadID)); //开始USB下载 break; case IDC_FlashRWSpeedTest://读写测速 CloseHandle(CreateThread(NULL,0,FlashRWSpeedTest,NULL,0,&ThreadID)); //开始USB下载 break; case IDC_CMD_I2C_RW: I2C_WriteRead(); break; case IDC_SetGpio://GPIO设置 Gpio_Set(); break; case IDC_GetGpio://GPIO状态获取 Gpio_Get(); break; case IDC_GpioSetDataAll://选中全部GPIO电平 GpioSetDataAll(); break; case IDC_GpioEnableAll://使能全部GPIO GpioEnableAll(); break; case IDC_GpioSetDirAll://选中全部GPIO方向 GpioSetDirAll(); break; case IDC_EnableIntNotify: IntEnable(); //开启中断 break; case IDC_DisableIntNotify: IntDisable(); //关闭中断 break; case IDC_ClearInfor: SetDlgItemText(hWnd,IDC_InforShow,""); break; case WM_DESTROY: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_DESTROY: SendDlgItemMessage(hWnd,IDC_CloseDevice,BM_CLICK,0,0); CH347SetDeviceNotify(SpiI2cGpioDevIndex,CH347DevID,NULL); PostQuitMessage(0); break; } return 0; }