2025年USB转SPI芯片操作FLASH--CH347应用

USB转SPI芯片操作FLASH--CH347应用USB 转 SPI 芯片简介 高速 USB 转接芯片 CH347 是一款集成 480Mbps 高速 USB 接口 JTAG 接口 SPI 接口 I2C 接口 异步 UART 串口 GPIO 接口等多种硬件接口的转换芯片 接口示意图 CH347 SPI 接口特点 CH347 SPI 接口特点 USB 传输采用 USB2 0 高速 480Mbps 工作在

大家好,我是讯享网,很高兴认识大家。

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位操作系统。icon-default.png?t=N7T8https://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; } 

执行截图:

小讯
上一篇 2025-03-06 22:16
下一篇 2025-01-24 12:00

相关推荐

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