USB转SPI芯片简介
高速USB转接芯片CH347是一款集成480Mbps高速USB接口、JTAG接口、SPI接口、I2C接口、异步UART串口、GPIO接口等多种硬件接口的转换芯片。
接口示意图:
CH347-SPI接口特点
- CH347-SPI接口特点
- USB传输采用USB2.0高速(480Mbps)
- 工作在 Host/Master主机模式;
- 内置硬件DMA,支持批量数据的快速发送和读取;
- 支持SPI模式0/1/2/3,支持传输频率配置,传输频率可达60MHz;
- 硬件信号:SCS0、SCS1、SCK、MISO和MOSI;
- 传输位序:MSB/LSB;
- 数据结构:8位/16位传输;
- 提供计算机端驱动程序和USB转SPI函数库,支持二次开发;
使用芯片准备工作
选择CH347工作模式
CH347芯片在复位时,会根据DTR1(CFG0)和RTS1(CFG1)引脚的电平状态配置其工作模式,各工作模式及功能说明如下
| 工作模式 |
模式说明 |
CFG0 |
CFG1 |
| Mode0 |
480Mbps高速USB转双UART(Baudrate最高9Mbps) |
1 |
1 |
| Mode1 |
480Mbps高速USB转UART+SPI+I2C(厂商驱动模式) |
0 |
1 |
| Mode2 |
480Mbps高速USB转UART+SPI+I2C(系统HID驱动模式) |
1 |
0 |
| Mode3 |
480Mbps高速USB转UART+JTAG(厂商驱动模式) |
0 |
0 |
CH347可使用SPI的模式有两种,其区别在Mode1需要安装厂商驱动,Mode3可以使用系统内置HID驱动无需额外安装,只需在编程时调用CH347动态库进行软件编程即可,此处我们使用Mode1来进行操作。

驱动安装
windows驱动安装
从WCH官网下载CH347转SPI/I2C/JTAG/GPIO驱动:CH341PAR.EXE - 南京沁恒微电子股份有限公司
驱动下载后进行一次安装,后续即可实现系统“免驱”效果无需二次安装。未插入设备时安装会显示“驱动预安装成功”,此时驱动已经正常安装,硬件即插即用。
Windows驱动通过微软数字签名认证,支持32/64位 Windows 11/10/8.1/8/7/VISTA/XP/2000,SERVER 2019/2016/2012/2008/2003等系统,无需担心Windows不同系统兼容性问题。
官方同时提供驱动资源包CH341PAR.ZIP - 南京沁恒微电子股份有限公司,可将驱动安装文件打包至成熟产品一齐发布,且支持无界面安装操作,可通过软件编程调用命令行操作,只需执行“SETUP /S”命令即可静默驱动安装。

点击安装之后,等待弹出安装成功窗口后点击确定即可。

Linux驱动安装
联系WCH技术支持获取到CH347-Linux驱动,然后进行安装
1、执行make编译驱动;
2、执行make load动态加载驱动,或执行make install后可实现重新启动自动检测硬件并加载驱动;
3、插入设备可查看到生成前缀为ch34x_pis的设备节点。

使用USB操作FLASH
本次操作CH347开发板板载FLASH:W25Q16JVSSIQ。
除此之外,CH347也可操作常见AT25/26、GD25等FLASH
调用函数
WCH提供了一套公用的库函数接口,即Windows&Linux平台接口函数名称与参数一致,其库函数接口特性如下:
操作SPI、I2C、GPIO等的接口在任何工作模式下都可使用同一API,在进行软件编写时,只需调用接口完成代码操作逻辑而不用关注当前硬件工作模式。提供插拔检测函数可动态监测设备插拔信息,更方便进行设备管理。
具体详细内容可参考官方开发手册:CH347EVT.ZIP - 南京沁恒微电子股份有限公司 【目录:CH347EVT\EVT\PUB\CH347应用开发手册.PDF】
/*插拔监测函数/ BOOL WINAPI CH347SetDeviceNotify( // 设定设备事件通知程序 ULONG iIndex, // 指定设备序号,0对应第一个设备 PCHAR iDeviceID, // 可选参数,指向字符串,指定被监控的设备的ID,字符串以\0终止 mPCH347_NOTIFY_ROUTINE iNotifyRoutine ); // 指定设备事件回调程序,为NULL则取消事件通知,否则在检测到事件时调用该程序 /*SPI接口函数通用于Mode1/2/ // SPI控制器初始化 BOOL WINAPI CH347SPI_Init(ULONG iIndex,mSpiCfgS *SpiCfg); //获取SPI控制器配置信息 BOOL WINAPI CH347SPI_GetCfg(ULONG iIndex,mSpiCfgS *SpiCfg); //设置片选状态,使用前需先调用CH347SPI_Init对CS进行设置 BOOL WINAPI CH347SPI_ChangeCS(ULONG iIndex, // 指定设备序号 UCHAR iStatus); // 0=撤消片选,1=设置片选 //设置SPI片选 BOOL WINAPI CH347SPI_SetChipSelect(ULONG iIndex, // 指定设备序号 USHORT iEnableSelect, // 低八位为CS1,高八位为CS2; 字节值为1=设置CS,为0=忽略此CS设置 USHORT iChipSelect, // 低八位为CS1,高八位为CS2;片选输出,0=撤消片选,1=设置片选 ULONG iIsAutoDeativeCS, // 低16位为CS1,高16位为CS2;操作完成后是否自动撤消片选 ULONG iActiveDelay, // 低16位为CS1,高16位为CS2;设置片选后执行读写操作的延时时间,单位us ULONG iDelayDeactive); // 低16位为CS1,高16位为CS2;撤消片选后执行读写操作的延时时间,单位us //SPI4写数据 BOOL WINAPI CH347SPI_Write(ULONG iIndex, // 指定设备序号 ULONG iChipSelect, // 片选控制, 位7为0则忽略片选控制, 位7为1进行片选操作 ULONG iLength, // 准备传输的数据字节数 ULONG iWriteStep, // 准备读取的单个块的长度 PVOID ioBuffer); // 指向一个缓冲区,放置准备从MOSI写出的数据 //SPI4读数据.无需先写数据,效率较CH347SPI_WriteRead高很多 BOOL WINAPI CH347SPI_Read(ULONG iIndex, // 指定设备序号 ULONG iChipSelect, // 片选控制, 位7为0则忽略片选控制, 位7为1进行片选操作 ULONG oLength, // 准备发出的字节数 PULONG iLength, // 准备读入的数据字节数 PVOID ioBuffer); // 指向一个缓冲区,放置准备从DOUT写出的数据,返回后是从DIN读入的数据 // 处理SPI数据流,4线接口 BOOL WINAPI CH347SPI_WriteRead(ULONG iIndex, // 指定设备序号 ULONG iChipSelect, // 片选控制, 位7为0则忽略片选控制, 位7为1则操作片选 ULONG iLength, // 准备传输的数据字节数 PVOID ioBuffer ); // 指向一个缓冲区,放置准备从DOUT写出的数据,返回后是从DIN读入的数据 // 处理SPI数据流,4线接口 BOOL WINAPI CH347StreamSPI4(ULONG iIndex, // 指定设备序号 ULONG iChipSelect, // 片选控制, 位7为0则忽略片选控制, 位7为1则参数有效 ULONG iLength, // 准备传输的数据字节数 PVOID ioBuffer ); // 指向一个缓冲区,放置准备从DOUT写出的数据,返回后是从DIN读入的数据
讯享网
操作流程

代码示例
Windows例程
可参考官方开发资料:CH347EVT.ZIP - 南京沁恒微电子股份有限公司 【目录:CH347EVT\EVT\TOOLS\CH347Demo】
界面读写示例如下:

Linux例程
可参考如下代码,链接地址:CH341PAR_LINUX.ZIP - 南京沁恒微电子股份有限公司USB转JTAG/SPI/I2C/并口/GPIO等接口的Linux设备驱动程序,支持CH341的USB转SPI/I2C/EPP并口/MEM并口等,支持CH347的480Mbps高速USB转JTAG/SPI/I2C/GPIO等,支持32/64位操作系统。
https://www.wch.cn/downloads/CH341PAR_LINUX_ZIP.html
讯享网/* * ch347 application demo * * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd. * Web: http://wch.cn * Author: WCH <> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Cross-compile with cross-gcc -I /path/to/cross-kernel/include * * V1.0 - initial version * V1.1 - add operation for HID mode * V1.2 - add serial port operation in HID and TTY mode * V1.3 - update with new library * V1.4 - add gpio interrupt funciton, update with new library, * - support more SPI and I2C stretching * - support I2C clock stretch */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <stdint.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> #include <endian.h> #include <linux/hidraw.h> #include "ch347_lib.h" #define CMD_FLASH_SECTOR_ERASE 0x20 #define CMD_FLASH_BYTE_PROG 0x02 #define CMD_FLASH_READ 0x03 #define CMD_FLASH_RDSR 0x05 #define CMD_FLASH_WREN 0x06 #define CMD_FLASH_JEDEC_ID 0x9F #define SPI_FLASH_PerWritePageSize 256 typedef enum _CH347FUNCTYPE { FUNC_UART = 0, FUNC_SPI_I2C_GPIO, FUNC_JTAG_GPIO, FUNC_SPI_I2C_JTAG_GPIO, } CH347FUNCTYPE; struct ch34x { int fd; char version[100]; CHIP_TYPE chiptype; uint32_t dev_id; CH347FUNCTYPE functype; }; static struct ch34x ch347device; bool CH347_SPI_Init() { bool ret; mSpiCfgS SpiCfg = { 0 }; /* set spi interface in [mode3] & [15MHz] & [MSB] & output [0xFF] by default */ SpiCfg.iMode = 3; SpiCfg.iSpiSpeedHz = 30e6; SpiCfg.iByteOrder = 1; SpiCfg.iSpiOutDefaultData = 0xFF; SpiCfg.iChipSelect = 0x80; /* init spi interface */ ret = CH347SPI_Init(ch347device.fd, &SpiCfg); if (!ret) { printf("Failed to init SPI interface.\n"); return false; } return true; } bool CH347_I2C_Init() { bool ret; int iMode; /* set i2c interface in 750KHZ */ iMode = 0x03; /* init i2c interface */ ret = CH347I2C_Set(ch347device.fd, iMode); if (!ret) { printf("Failed to init I2C interface.\n"); return false; } return true; } bool Flash_ID_Read() { int iChipSelect; int iLength; uint8_t ioBuffer[4] = { 0 }; uint32_t Flash_ID; iChipSelect = 0x80; iLength = 4; ioBuffer[0] = CMD_FLASH_JEDEC_ID; memset(ioBuffer + 1, 0xFF, 3); if (CH347SPI_WriteRead(ch347device.fd, false, iChipSelect, iLength, ioBuffer) == false) return false; else { ioBuffer[0] = 0x00; memcpy(&Flash_ID, ioBuffer, 4); } Flash_ID = htole32(Flash_ID); printf("Read flash ID: 0x%x.\n", Flash_ID); if (Flash_ID == 0x000000 || Flash_ID == 0xffffff00) { printf("Read flash ID error.\n"); return false; } return true; } unsigned int Flash_Block_Read(unsigned int address, uint8_t *pbuf, unsigned int len) { int iChipSelect; int iLength; int oLength; uint8_t ioBuffer[8192] = { 0 }; iChipSelect = 0x80; iLength = 0x04; oLength = len; ioBuffer[0] = CMD_FLASH_READ; ioBuffer[1] = (uint8_t)(address >> 16); ioBuffer[2] = (uint8_t)(address >> 8); ioBuffer[3] = (uint8_t)(address); if (!CH347SPI_Read(ch347device.fd, false, iChipSelect, iLength, &oLength, ioBuffer)) { printf("Flash_Block_Read read %d bytes failed.\n", len); return 0; } else memcpy(pbuf, ioBuffer, oLength); return oLength; } bool Flash_Block_Read_Test() { double UseT; uint32_t DataLen, FlashAddr, i; uint8_t ioBuffer[8192] = { 0 }; char FmtStr1[8 * 1024 * 3 + 16] = ""; static struct timeval t1, t2; int delta_sec, delta_usec; FlashAddr = 0x00; DataLen = 0x500; gettimeofday(&t1, NULL); DataLen = Flash_Block_Read(FlashAddr, ioBuffer, DataLen); if (DataLen <= 0) { printf("\tFlash Read: Addr[0x%x] read %d bytes failed.\n", FlashAddr, DataLen); return false; } gettimeofday(&t2, NULL); delta_sec = t2.tv_sec - t1.tv_sec; delta_usec = t2.tv_usec - t1.tv_usec; UseT = (float)delta_sec + (float)delta_usec / ; printf("\tFlash Read: Addr[0x%x] read %d bytes in %.3f seconds.\n", FlashAddr, DataLen, UseT); for (i = 0; i < DataLen; i++) sprintf(&FmtStr1[strlen(FmtStr1)], "%02x ", ioBuffer[i]); printf("\nRead: \n%s\n\n", FmtStr1); return true; } bool Flash_Write_Enable() { int iChipSelect; int iLength; uint8_t ioBuffer; iChipSelect = 0x80; iLength = 1; ioBuffer = CMD_FLASH_WREN; return CH347SPI_WriteRead(ch347device.fd, false, iChipSelect, iLength, &ioBuffer); } bool Flash_Wait() { int iChipSelect; int iLength; uint8_t ioBuffer[2]; uint8_t status; int retry_times = 1000; iChipSelect = 0x80; iLength = 2; do { ioBuffer[0] = CMD_FLASH_RDSR; if (CH347SPI_WriteRead(ch347device.fd, false, iChipSelect, iLength, ioBuffer) == false) return false; status = ioBuffer[1]; usleep(100); } while ((status & 0x01) && (retry_times--)); if ((status & 0x01) == 0) return true; else return false; } bool Flash_Sector_Erase(uint32_t StartAddr) { int iChipSelect; int iLength; uint8_t ioBuffer[4]; if (Flash_Write_Enable() == false) return false; iChipSelect = 0x80; iLength = 4; ioBuffer[0] = CMD_FLASH_SECTOR_ERASE; ioBuffer[1] = (uint8_t)(StartAddr >> 16 & 0xff); ioBuffer[2] = (uint8_t)(StartAddr >> 8 & 0xf0); ioBuffer[3] = 0x00; if (CH347SPI_WriteRead(ch347device.fd, false, iChipSelect, iLength, ioBuffer) == false) return false; if (Flash_Wait() == false) return false; return true; } bool W25X_Flash_Write_Page(uint8_t *pBuf, uint32_t address, uint32_t len) { int iChipSelect; int iLength; uint8_t ioBuffer[8192]; if (!Flash_Write_Enable()) return false; iChipSelect = 0x80; iLength = len + 4; ioBuffer[0] = CMD_FLASH_BYTE_PROG; ioBuffer[1] = (uint8_t)(address >> 16); ioBuffer[2] = (uint8_t)(address >> 8); ioBuffer[3] = (uint8_t)address; memcpy(&ioBuffer[4], pBuf, len); if (CH347SPI_Write(ch347device.fd, false, iChipSelect, iLength, SPI_FLASH_PerWritePageSize + 4, ioBuffer) == false) return false; memset(ioBuffer, 0, sizeof(uint8_t) * len); if (!Flash_Wait()) return false; return true; } bool Flash_Block_Write() { int ret; int i = 0; uint32_t DataLen, FlashAddr, BeginAddr, NumOfPage, NumOfSingle; uint8_t ioBuffer[0x500] = { 0 }; uint8_t *pbuf = ioBuffer; double UseT; static struct timeval t1, t2; int delta_sec, delta_usec; /* write flash from addr 0 */ FlashAddr = 0x00; BeginAddr = FlashAddr; DataLen = 0x500; for (i = 0; i < DataLen; i++) ioBuffer[i] = i; NumOfPage = DataLen / SPI_FLASH_PerWritePageSize; NumOfSingle = DataLen % SPI_FLASH_PerWritePageSize; /* caculate flash write time */ gettimeofday(&t1, NULL); while (NumOfPage--) { ret = W25X_Flash_Write_Page(pbuf, FlashAddr, SPI_FLASH_PerWritePageSize); if (ret == false) goto exit; pbuf += SPI_FLASH_PerWritePageSize; FlashAddr += SPI_FLASH_PerWritePageSize; } if (NumOfSingle) { ret = W25X_Flash_Write_Page(pbuf, FlashAddr, NumOfSingle); if (ret == false) goto exit; } gettimeofday(&t2, NULL); delta_sec = t2.tv_sec - t1.tv_sec; delta_usec = t2.tv_usec - t1.tv_usec; UseT = ((float)delta_sec + (float)delta_usec / ); printf("\tFlash Write: Addr[0x%x] write %d bytes in %.3f seconds.\n", BeginAddr, DataLen, UseT / 1000); return true; exit: printf("\tFlash Write: Addr [0x%x] write %d bytes failed.\n", BeginAddr, DataLen); return false; } bool EEPROM_Read() { bool ret = false; EEPROM_TYPE eeprom; int iAddr; int iLength; int i; uint8_t oBuffer[256] = { 0 }; eeprom = ID_24C02; iAddr = 0; iLength = 256; ret = CH347ReadEEPROM(ch347device.fd, eeprom, 0, iLength, oBuffer); if (ret == false) goto exit; printf("\nRead EEPROM data:\n"); for (i = 0; i < iLength; i++) { printf("%02x ", oBuffer[i]); if (((i + 1) % 10) == 0) putchar(10); } putchar(10); exit: return ret; } bool EEPROM_Write() { bool ret = false; EEPROM_TYPE eeprom; int iAddr; int iLength; int i; uint8_t iBuffer[256] = { 0 }; eeprom = ID_24C02; iAddr = 0; iLength = 256; for (i = 0; i < 256; i++) iBuffer[i] = i; printf("\nWrite EEPROM data:\n"); ret = CH347WriteEEPROM(ch347device.fd, eeprom, iAddr, iLength, iBuffer); if (ret == false) goto exit; for (i = 0; i < iLength; i++) { printf("%02x ", iBuffer[i]); if (((i + 1) % 10) == 0) putchar(10); } putchar(10); exit: return ret; } void ch34x_demo_flash_operate() { bool ret = false; ret = CH347_SPI_Init(); if (ret == false) { printf("Failed to init CH347 SPI interface.\n"); return; } printf("CH347 SPI interface init succeed.\n"); /* read flash ID */ ret = Flash_ID_Read(); if (!ret) { printf("Failed to read flash ID.\n"); return; } /* read flash block data */ ret = Flash_Block_Read_Test(); if (!ret) { printf("Failed to read flash.\n"); return; } /* erase flash sector data */ ret = Flash_Sector_Erase(0x00); if (!ret) { printf("Failed to erase flash.\n"); return; } printf("Erase one sector from Addr[0x%x] of flash succeed.\n", 0x00); /* write flash block data */ ret = Flash_Block_Write(); if (!ret) { printf("Failed to write flash.\n"); return; } /* read flash block data */ ret = Flash_Block_Read_Test(); if (!ret) { printf("Failed to read flash.\n"); return; } } void ch34x_demo_eeprom_operate() { bool ret = false; ret = CH347_I2C_Init(); if (!ret) { printf("Failed to init CH347 I2C.\n"); return; } printf("CH347 I2C interface init succeed.\n"); ret = EEPROM_Read(); if (!ret) { printf("Failed to read eeprom.\n"); return; } ret = EEPROM_Write(); if (!ret) { printf("Failed to write eeprom.\n"); return; } ret = EEPROM_Read(); if (!ret) { printf("Failed to read eeprom.\n"); return; } } void ch34x_demo_jtag_operate() { int i; int oReadLength; uint8_t retue[32] = { 0 }; uint8_t IDCODE[4096] = { 0 }; oReadLength = 32; /* init jtag tck clock */ CH347Jtag_INIT(ch347device.fd, 4); /* reset target jtag device */ CH347Jtag_SwitchTapState(ch347device.fd, 0); /* SHIFT-DR Read the Target IDCODE */ CH347Jtag_ByteReadDR(ch347device.fd, &oReadLength, &retue); printf("Target IDCODE: \n"); for (i = 0; i < 4; i++) { printf("0x%2x", retue[3 - i]); } puts(""); return; } bool CH347_SPI_Slave_Init() { bool ret; mSpiCfgS SpiCfg = { 0 }; /* set spi interface in spi slave mode, [mode3] & [MSB] & output [0xFF] by default */ SpiCfg.iByteOrder = 1; SpiCfg.iSpiOutDefaultData = 0xFF; SpiCfg.iMode = 0x83; /* init spi interface */ ret = CH347SPI_Init(ch347device.fd, &SpiCfg); if (!ret) { printf("Failed to init SPI interface.\n"); return false; } else { printf("SPI init slave ok.\n"); } return true; } void ch34x_demo_spi_slave_operate(bool enable) { bool ret = false; uint8_t oBuffer[SPI_SLAVE_MAX_LENGTH]; uint32_t oLength; int i; if (enable) { ret = CH347_SPI_Slave_Init(); if (ret == false) { printf("Failed to init CH347 SPI interface.\n"); return; } printf("CH347 SPI interface init succeed.\n"); ret = CH347SPI_Slave_Control(ch347device.fd, true); if (!ret) return; printf("Begin read data in slave mode.\n"); while (1) { ret = CH347SPI_Slave_QweryData(ch347device.fd, &oLength); if (!ret) { printf("CH347SPI_Slave_QweryData failed.\n"); goto exit; } if (oLength == 0) { usleep(10 * 1000); continue; } ret = CH347SPI_Slave_ReadData(ch347device.fd, oBuffer, &oLength); if (!ret) { printf("CH347SPI_Slave_ReadData failed.\n"); goto exit; } printf("\nRead Slave data, len: %d, contents:\n", oLength); for (i = 0; i < oLength; i++) { printf("%02x ", oBuffer[i]); if (((i + 1) % 20) == 0) putchar(20); } putchar(20); } } else ret = CH347SPI_Slave_Control(ch347device.fd, false); return; exit: CH347SPI_Slave_Control(ch347device.fd, false); } static void ch34x_demo_gpio_input_operate() { bool ret; int i, j; int gpiocount = 8; uint8_t iDir = 0xff; uint8_t iData = 0x00; ret = CH347GPIO_Get(ch347device.fd, &iDir, &iData); if (ret == false) { printf("CH347GPIO_Set error.\n"); return; } printf("\n GPIO Input Start \n\n"); for (i = 0; i < gpiocount; i++) { if ((iData & (1 << i))) printf("H"); else printf("L"); } printf("\n"); printf("\n GPIO Input End \n\n"); } static void ch34x_demo_gpio_output_operate() { bool ret; int i, j; int gpiocount = 8; uint8_t iEnable = 0xff; uint8_t iSetDirOut = 0xff; uint8_t iSetDataOut = 0x00; /* analog leds here */ CH347GPIO_Set(ch347device.fd, iEnable, iSetDirOut, iSetDataOut); printf("\n GPIO Output Start \n"); for (i = 0; i < gpiocount; i++) { iSetDataOut = 1 << i; ret = CH347GPIO_Set(ch347device.fd, iEnable, iSetDirOut, iSetDataOut); if (ret == false) { printf("CH347GPIO_Set error.\n"); return; } printf("\n"); for (j = 0; j < gpiocount; j++) { if (j == i) printf("H"); else printf("L"); } printf("\n"); usleep(200 * 1000); } iSetDataOut = 0x00; CH347GPIO_Set(ch347device.fd, iEnable, iSetDirOut, iSetDataOut); printf("\n GPIO Output End \n\n"); } static void ch34x_demo_isr_handler(int signo) { static int int_times = 0; printf("ch34x interrupt times: %d\n", int_times++); } static void ch34x_demo_irq_operate(bool enable) { bool ret; int gpioindex = 6; ret = CH347GPIO_IRQ_Set(ch347device.fd, gpioindex, enable, IRQ_TYPE_EDGE_BOTH, ch34x_demo_isr_handler); if (!ret) { printf("Failed to set CH347 irq function."); return; } } void ch34x_demo_uart_operate() { bool ret = false; uint8_t iBuffer[256]; uint8_t oBuffer[256]; uint32_t ioLength; int i; ioLength = 256; for (i = 0; i < 256; i++) iBuffer[i] = i; ret = CH347Uart_Init(ch347device.fd, , 3, 0, 0, 1); if (!ret) { printf("Failed to init CH347 UART interface.\n"); return; } printf("CH347 UART interface init succeed.\n"); ret = CH347Uart_Write(ch347device.fd, iBuffer, &ioLength); if (ret == false) { printf("CH347Uart_Write failed.\n"); return; } printf("Uart wrote %d bytes already.\n", ioLength); ret = CH347Uart_Read(ch347device.fd, oBuffer, &ioLength); if (ret == false) { printf("CH347Uart_Read failed.\n"); return; } printf("\nRead Uart data:\n"); for (i = 0; i < ioLength; i++) { printf("%02x ", oBuffer[i]); if (((i + 1) % 10) == 0) putchar(10); } putchar(10); } bool Show_DevMsg(char *pathname) { unsigned char buf[256]; int ret; int i; struct hidraw_devinfo info; uint16_t vendor, product; CHIP_TYPE chiptype; if (strstr(pathname, "tty")) { printf("Device operating has function [UART].\n"); ch347device.functype = FUNC_UART; } else if (strstr(pathname, "hidraw")) { /* Get Raw Name */ ret = ioctl(ch347device.fd, HIDIOCGRAWNAME(256), buf); if (ret < 0) { perror("HIDIOCGRAWNAME"); goto exit; } else printf("Raw Name: %s\n", buf); /* Get Raw Info */ ret = ioctl(ch347device.fd, HIDIOCGRAWINFO, &info); if (ret < 0) { perror("HIDIOCGRAWINFO"); goto exit; } else { printf("Raw Info:\n"); printf("\tvendor: 0x%04hx\n", info.vendor); printf("\tproduct: 0x%04hx\n", info.product); } if (info.vendor == 0x1a86) { if (info.product == 0x55dc) ch347device.chiptype = CHIP_CH347T; else if (info.product == 0x55e5) ch347device.chiptype = CHIP_CH347F; else { printf("Current HID device PID is not CH347.\n"); return -1; } } else { printf("Current HID device VID is not CH347.\n"); return -1; } /* Get Physical Location */ ret = ioctl(ch347device.fd, HIDIOCGRAWPHYS(256), buf); if (ret < 0) { perror("HIDIOCGRAWPHYS"); goto exit; } else printf("Raw Phys: %s\n", buf); if (ch347device.chiptype == CHIP_CH347T) { if (strstr(buf, "input0")) { ch347device.functype = FUNC_UART; printf("Device operating has function [UART].\n"); } else { ch347device.functype = FUNC_SPI_I2C_GPIO; printf("Device operating has function [SPI+I2C+GPIO].\n"); } } else { if (strstr(buf, "input0")) { ch347device.functype = FUNC_UART; printf("Device operating has function [UART].\n"); } else if (strstr(buf, "input2")) { ch347device.functype = FUNC_UART; printf("Device operating has function [UART].\n"); } else { ch347device.functype = FUNC_SPI_I2C_GPIO; printf("Device operating has function [SPI+I2C+JTAG+GPIO].\n"); } } } else if (strstr(pathname, "ch34x_pis")) { /* Get Driver Version */ ret = CH34x_GetDriverVersion(ch347device.fd, ch347device.version); if (ret == false) { printf("CH34x_GetDriverVersion error.\n"); goto exit; } printf("Driver version: %s\n", ch347device.version); /* Get Chip Type */ ret = CH34x_GetChipType(ch347device.fd, &ch347device.chiptype); if (ret == false) { printf("CH34x_GetChipType error.\n"); goto exit; } if (ch347device.chiptype == CHIP_CH341) { printf("Current chip operating is CH341, please use ch341_demo.\n"); goto exit; } /* Get Device ID */ ret = CH34X_GetDeviceID(ch347device.fd, &ch347device.dev_id); if (ret == false) { printf("CH34X_GetDeviceID error.\n"); goto exit; } vendor = ch347device.dev_id; product = ch347device.dev_id >> 16; printf("Vendor ID: 0x%4x, Product ID: 0x%4x\n", vendor, product); if (product == 0x55db) { ch347device.functype = FUNC_SPI_I2C_GPIO; printf("Device operating has function [SPI+I2C+GPIO].\n"); } else if (product == 0x55dd) { ch347device.functype = FUNC_JTAG_GPIO; printf("Device operating has function [JTAG+GPIO].\n"); } else if (product == 0x55de) { ch347device.functype = FUNC_SPI_I2C_JTAG_GPIO; printf("Device operating has function [SPI+I2C+JTAG+GPIO].\n"); } } return true; exit: return false; } int main(int argc, char *argv[]) { bool ret; char choice, ch; if (argc != 2) { printf("Usage: sudo %s [device]\n", argv[0]); return -1; } /* open device */ ch347device.fd = CH347OpenDevice(argv[1]); if (ch347device.fd < 0) { printf("CH347OpenDevice false.\n"); return -1; } printf("Open device %s succeed, fd: %d\n", argv[1], ch347device.fd); ret = Show_DevMsg(argv[1]); if (ret == false) return -1; sleep(1); if (strstr(argv[1], "ch34x_pis")) { ret = CH34xSetTimeout(ch347device.fd, 2000, 2000); if (ret == false) { printf("CH34xSetTimeout false.\n"); return -1; } } switch (ch347device.functype) { case FUNC_UART: while (1) { printf("\npress u to operate uart, q to quit.\n"); scanf("%c", &choice); while ((ch = getchar()) != EOF && ch != '\n') ; if (choice == 'q') break; switch (choice) { case 'u': ch34x_demo_uart_operate(); break; default: break; } } break; case FUNC_SPI_I2C_GPIO: case FUNC_SPI_I2C_JTAG_GPIO: while (1) { printf("\npress f to operate spi flash, e to operate eeprom,\n" "a to get gpio status, g to gpio output test, j to operate jtag interface,\n" "s to enable spi slave mode, o to disable spi slave mode,\n" "i to enable interrupt, d to disable interrupt, q to quit.\n"); scanf("%c", &choice); while ((ch = getchar()) != EOF && ch != '\n') ; if (choice == 'q') break; switch (choice) { case 'f': printf("FLASH Test begin.\n"); ch34x_demo_flash_operate(); break; case 'e': printf("EEPROM Test begin.\n"); ch34x_demo_eeprom_operate(); break; case 'a': printf("GPIO Input Test Begin.\n"); ch34x_demo_gpio_input_operate(); break; case 'g': printf("GPIO Output Test Begin.\n"); ch34x_demo_gpio_output_operate(); break; case 'i': printf("IRQ Test Begin."); ch34x_demo_irq_operate(true); break; case 'd': printf("IRQ Test Over.\n"); ch34x_demo_irq_operate(false); break; case 'j': if (ch347device.functype == FUNC_SPI_I2C_JTAG_GPIO) { printf("JTAG Test begin.\n"); ch34x_demo_jtag_operate(); } else { printf("Chip is not CH347F.\n"); } break; case 's': if (ch347device.chiptype == CHIP_CH347F) { printf("SPI Slave Test Begin.\n"); ch34x_demo_spi_slave_operate(true); } else { printf("Chip is not CH347F.\n"); } break; case 'o': if (ch347device.chiptype == CHIP_CH347F) { printf("SPI Slave Test Over.\n"); ch34x_demo_spi_slave_operate(false); } else { printf("Chip is not CH347F.\n"); } break; default: printf("Bad choice, please input again.\n"); break; } } break; case FUNC_JTAG_GPIO: while (1) { printf("\npress j to operate jtag interface, a to get gpio status,\n" "g to gpio output test q to quit.\n"); scanf("%c", &choice); while ((ch = getchar()) != EOF && ch != '\n') ; if (choice == 'q') break; switch (choice) { case 'j': printf("JTAG Test begin.\n"); ch34x_demo_jtag_operate(); break; case 'a': printf("GPIO Input Test Begin.\n"); ch34x_demo_gpio_input_operate(); break; case 'g': printf("GPIO Test begin.\n"); ch34x_demo_gpio_output_operate(); default: printf("Bad choice, please input again.\n"); break; } } break; default: break; } /* close the device */ if (CH347CloseDevice(ch347device.fd)) { printf("Close device succeed.\n"); } return 0; }
执行截图:


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/42138.html