CH347实战 USB转JTAG:基于openFPGALoader实现多平台FPGA烧录指南
1. 为什么你需要一个“万能”的下载器?聊聊CH347与openFPGALoader
如果你玩过FPGA,肯定对那个方方正正的、价格不菲的官方下载器不陌生。好用是好用,但每次换平台、换芯片,要么得找对应的驱动,要么就得祈祷它别出什么兼容性问题。更别提有时候想在家里用Windows,在公司用Linux,来回切换的麻烦。我自己就经历过好几次,在Linux下编译好的程序,拿到Windows环境下载,结果驱动死活装不上,一折腾就是半天。
后来我发现,很多开发者的痛点其实很集中:需要一个简单、便宜、跨平台通吃的FPGA程序下载方案。直到我遇到了CH347这款USB转接芯片和openFPGALoader这个开源工具,才算是真正找到了一个“一站式”的解决方案。今天,我就把自己折腾了挺久才搞明白的实战经验,从头到尾、手把手地分享给你。无论你是刚入门的新手,还是被各种下载器折磨过的老鸟,这篇指南都能帮你快速搭建起一个稳定、高效的FPGA烧录环境。
简单来说,CH347是一个国产的“瑞士军刀”芯片。它通过一个USB口,能同时或者分时模拟出串口、I2C、SPI和最重要的JTAG接口。这意味着,你只需要一根USB线,就能搞定FPGA的调试、下载,甚至还能兼顾板子上的其他外设通信,性价比非常高。而openFPGALoader,你可以把它理解成FPGA界的“openOCD”。它专注于一件事:把编译好的程序文件(.bit, .bin等)灌进FPGA里。它支持Xilinx、Intel(原Altera)、Lattice、高云(Gowin)等主流厂商的芯片,而且完全开源、命令行操作,非常适合集成到自动化脚本里。
把这两者结合起来,你就得到了一套成本极低、跨平台支持、命令行驱动的FPGA下载方案。这套方案特别适合哪些场景呢?比如学生党做课程设计、创客DIY自己的小项目、或者中小团队做产品原型验证,你不再需要为每个工程师配备昂贵的官方下载器,也不用担心不同操作系统下的兼容性噩梦。接下来,我们就从硬件连接开始,一步步把它用起来。
2. 硬件准备与连接:选对型号,连对线
工欲善其事,必先利其器。第一步,你得先搞明白CH347的型号和你的硬件该怎么接。这步要是错了,后面软件怎么调都是白搭。
CH347主要有两种封装型号:CH347F和CH347T。别看就差一个字母,区别可大了。CH347F是“全能模式”,它的多个接口(比如UART、JTAG)可以同时工作。这意味着你可以一边用JTAG下载程序,一边用串口打印调试信息,非常方便。而CH347T则需要通过芯片上的某个引脚进行模式切换,同一时间只能使用一种功能组合(比如模式3是JTAG+SPI)。对于FPGA下载这个核心需求,我强烈推荐你直接使用CH347F,省去切换的麻烦,体验更接近传统的专用下载器。市面上很多模块会直接标明型号,购买时留意一下。
拿到模块后,连接FPGA开发板是关键。CH347的JTAG接口引脚定义是标准的,你需要找到模块上的TCK、TMS、TDI、TDO这四根线,以及GND。通常模块上会有清晰的丝印标注。把它们一一对应连接到你的FPGA开发板的JTAG接口上。这里有个小细节:很多开发板的JTAG接口是10针或14针的牛角座,你需要一个转接板或者杜邦线来连接。务必确保GND可靠连接,这是信号稳定的基础。如果手头有示波器,可以量一下TCK的波形,连接正常后,运行检测命令应该能看到规整的时钟信号。
除了JTAG,还有一个重要的接口是电源。有些CH347模块可以从USB取电,并通过一个3.3V引脚给FPGA板供电(注意核对电压!)。但更稳妥的做法是,让CH347模块和FPGA开发板各自独立供电,或者只由其中一方给另一方供电,避免共地不良或电流不足的问题。我自己的习惯是,都使用外部电源适配器供电,USB只负责数据传输。这样在烧录大容量Flash时,能避免因电流波动导致的失败。
3. 软件环境搭建:Windows与Linux下的详细攻略
硬件连好了,接下来就是软件环境。这是跨平台方案的核心魅力,也是新手最容易踩坑的地方。我会分别详细说明Windows和Linux下的安装与配置过程,你可以根据自己的主力系统选择阅读。
3.1 Linux系统:简单直接的编译安装
在Linux下(我以Ubuntu 22.04为例),整个过程非常顺畅,几乎是一路绿灯。首先,打开终端,我们需要安装一些基础的编译工具和依赖库。运行下面的命令:
sudo apt update sudo apt install -y build-essential cmake pkg-config libusb-1.0-0-dev zlib1g-dev这些包包括了编译器(gcc/g++)、构建工具(cmake)、USB库等,是编译openFPGALoader所必需的。接下来,获取开源代码。我推荐直接克隆官方的Git仓库,这样可以随时拉取最新的更新:
git clone https://github.com/trabucayre/openFPGALoader.git cd openFPGALoader注意,这里我使用了trabucayre维护的仓库,它是原ZhiyuanYuanNJ仓库的一个活跃分支,更新和维护更频繁。进入代码目录后,标准的CMake编译“三板斧”就上场了:
mkdir build cd build cmake .. make -j$(nproc)-j$(nproc)参数会让make使用你电脑所有的CPU核心来并行编译,速度飞快。编译完成后,在当前build目录下,你就会得到可执行文件openFPGALoader。为了方便,你可以把它复制到系统路径,比如/usr/local/bin/:
sudo cp openFPGALoader /usr/local/bin/现在,在任何位置打开终端,输入openFPGALoader,如果看到帮助信息,就说明安装成功了。Linux系统通常对USB设备的访问有权限限制,为了让普通用户也能操作CH347,我们需要添加一个USB规则。创建一个新的规则文件:
sudo nano /etc/udev/rules.d/99-ch347.rules在文件中填入下面这行规则:
SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="55de", MODE="0666"保存退出后,重新加载udev规则并重新插拔你的CH347设备:
sudo udevadm control --reload-rules sudo udevadm trigger这样,你就不用每次都加上sudo来运行openFPGALoader了。
3.2 Windows系统:借助MSYS2模拟Linux环境
Windows下的步骤稍微多一点,但一旦配置好,用起来同样方便。我们主要依靠MSYS2这个工具来提供一个类似Linux的编译和运行环境。首先,去MSYS2官网下载安装程序,并按照指引安装。安装完成后,启动MSYS2 UCRT64(或MINGW64)这个终端。
首先,更新MSYS2的软件包数据库并升级基础包:
pacman -Syu关闭终端,再次打开,然后安装我们需要的开发工具链:
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain cmake git mingw-w64-ucrt-x86_64-libusb这些包包含了GCC编译器、CMake、Git和USB库。接下来,和Linux下一样,克隆代码并编译:
git clone https://github.com/trabucayre/openFPGALoader.git cd openFPGALoader mkdir build cd build cmake -G "MinGW Makefiles" .. cmake --build .编译完成后,在build目录下会生成openFPGALoader.exe。你可以把这个exe文件所在的路径(比如C:\msys64\home\你的用户名\openFPGALoader\build)添加到系统的PATH环境变量里,这样在任意命令行窗口都能直接调用。还有一个关键步骤:安装CH347的Windows JTAG驱动。你需要去芯片厂商的官网,找到CH347的驱动程序包,里面会有一个专门用于JTAG模式的驱动(通常叫CH347JTAG.DLL或类似的inf文件)。按照说明安装好,Windows的设备管理器里才能正确识别出JTAG设备。
4. 首次握手:检测设备与FPGA芯片
环境搭好了,让我们进行第一次“握手”,验证整个链路是否通畅。这一步能帮你快速定位问题是出在硬件连接、驱动,还是软件配置上。
首先,把CH347模块用USB线连接到电脑,并确保JTAG线正确连接到了FPGA开发板,给开发板上电。打开终端(Windows下用MSYS2终端或PowerShell),我们先用最基础的系统命令看看设备有没有被识别。
在Linux下,使用lsusb命令:
lsusb你应该能在输出列表中看到类似这样的一行:
Bus 003 Device 007: ID 1a86:55de QinHeng Electronics这里的1a86是厂商ID(VID),55de是产品ID(PID)。这个0x55de对应的是CH347F在多功能模式下的PID,非常重要,我们后面会用到。如果你看到的是0x55dd,那说明你的模块可能工作在CH347T的模式3下,这也没关系,只是后续命令中指定的PID需要改为0x55dd。
在Windows下,你可以通过设备管理器查看“通用串行总线控制器”里是否有“USB2.0 HS JTAG”之类的设备,或者使用MSYS2终端里的lsusb(如果安装了相关包)来查看。
设备识别成功后,就该让openFPGALoader去探测FPGA了。这里我们使用--detect参数。注意,因为CH347F的PID不是openFPGALoader默认的,我们必须通过--pid参数明确告诉它。在终端里输入:
openFPGALoader -c ch347_jtag --pid 0x55de --detect(如果你的是0x55dd,就把0x55de替换掉)
如果一切顺利,你会看到类似下面的成功信息:
Cable PID overridden JTAG TCK frequency set to 7.500 MHz index 0: idcode 0x4001093 manufacturer xilinx family spartan6 model xc6slx9 irlength 6这短短几行信息包含了巨大的成功喜悦!它告诉我们:1. 电缆(CH347)被正确识别且PID已覆盖;2. JTAG时钟默认设为了7.5MHz;3. 最重要的是,它扫描JTAG链,在索引0位置找到了一个IDCODE为0x4001093的芯片,并识别出这是Xilinx Spartan-6系列的XC6SLX9。看到这个,就说明从电脑USB口,到CH347,再到FPGA的JTAG链路,已经完全打通了。
如果这一步失败了,别慌,我们可以按顺序排查:首先确认USB连接和驱动(Windows尤其要检查驱动签名);其次检查JTAG四根线是否接错、虚焊;然后可以尝试降低JTAG频率,比如加上--freq 100000(100kHz)来尝试;最后,检查FPGA板是否已上电,有些板子需要特定的启动模式才能进入JTAG状态。
5. 核心实战:将程序下载到SRAM与Flash
链路通了,接下来就是最核心的操作:下载程序。FPGA的配置方式主要有两种:下载到SRAM和固化到Flash。前者掉电就丢失,用于调试;后者掉电保存,用于产品发布。openFPGALoader对这两种操作都提供了直接支持。
5.1 调试利器:快速下载到SRAM
当你正在调试代码,需要反复修改、下载、测试时,下载到SRAM是最快的方式。假设你有一个编译好的比特流文件led_test.bit,想用1.875MHz的JTAG时钟频率下载进去,命令非常简单:
openFPGALoader -c ch347_jtag --pid 0x55de --freq 1875000 -f led_test.bit解释一下这个命令:
-c ch347_jtag:指定使用ch347_jtag这种编程电缆。--pid 0x55de:指定CH347F的设备PID。--freq 1875000:设置JTAG的TCK时钟频率为1.875MHz。频率可以根据需要调整,后面会详细讲。-f led_test.bit:指定要下载的比特流文件。
命令执行后,你会看到一个进度条快速跑完,显示“Load SRAM: 100% Done”。整个过程通常只需要几秒钟。下载完成后,程序会立刻在FPGA上运行起来。你可以马上看到LED的闪烁变化,或者通过串口收到数据。这种即时反馈的体验,对于调试来说效率极高。
5.2 产品发布:固化程序到Flash
当你的代码调试稳定,需要让板子下次上电自动运行时,就需要把程序固化到板载的SPI Flash芯片里。这个过程比下载到SRAM多一个步骤:需要先通过JTAG给FPGA加载一个特殊的“桥接”程序,这个程序会让FPGA的JTAG接口临时变成一个SPI控制器,从而去操作外挂的Flash芯片。
这个特殊的桥接程序,在openFPGALoader的源码目录里,通常位于spiOverJtag/文件夹下,文件名和具体的FPGA型号、封装一一对应。例如,对于Xilinx Spartan-6 XC6SLX9-CSG324这个芯片,桥接文件就是spiOverJtag_xc6slx9csg324.bit.gz。使用-B参数来指定这个文件至关重要。
完整的固化命令如下:
openFPGALoader -c ch347_jtag --pid 0x55de --freq 30000000 -B spiOverJtag_xc6slx9csg324.bit.gz -f led_test.bit这个命令做了以下几件事:
-B ...:首先将桥接文件下载到FPGA的SRAM,此时FPGA变身为一个SPI编程器。- 接着,工具会通过这个“编程器”去探测连接在FPGA上的SPI Flash芯片的型号和容量(例如常见的Winbond W25Q16、W25Q64等)。
- 擦除Flash中对应的区域。
- 最后,将
led_test.bit文件写入Flash,并完成校验。
在输出信息中,你会依次看到“Load SRAM”、“Detected: xxx Flash”、“Erasing”、“Writing”等步骤的完成提示。看到最后一个“Writing: 100% Done”,就表示固化成功了。此时给板子重新上电,FPGA就会自动从Flash加载程序运行。
6. 参数详解与性能调优:让下载又快又稳
掌握了基本命令,我们再来深入聊聊那些影响下载成功率和速度的关键参数。理解它们,你就能自己解决大部分疑难杂症。
首先是JTAG时钟频率(--freq)。这是最重要的一个参数。CH347支持的JTAG时钟频率是分档的,并不是任意值都可以。它支持以下几个档位(单位Hz):
- 468750 (468.75 kHz)
- 937500 (937.5 kHz)
- 1875000 (1.875 MHz)
- 3750000 (3.75 MHz)
- 7500000 (7.5 MHz)
- 15000000 (15 MHz)
- 30000000 (30 MHz)
- 60000000 (60 MHz)
当你使用--freq参数时,openFPGALoader会自动向上选择最接近的可用档位。比如你设置--freq 20000000(20MHz),实际会使用30MHz的档位。高频意味着下载速度快,但同时对PCB布线、线缆长度的要求也更高。如果遇到下载不稳定、识别Flash失败等问题,第一个尝试的方法就是逐步降低频率。我个人的经验是,对于连接线较长或者板子干扰较大的情况,先从15MHz或7.5MHz开始试,稳定后再尝试提升。
其次是PID指定(--pid)。正如前面反复强调的,CH347F的PID(0x55de)不是工具默认值,所以必须显式指定。如果你忘记指定,工具会尝试用默认PID去打开设备,结果就是报“找不到设备”的错误。这是一个非常常见的新手坑。记住这个参数,或者你可以写一个简单的shell脚本或批处理文件,把常用命令封装起来,避免每次输入。
关于-B桥接文件。不同FPGA型号、甚至不同封装的桥接文件都可能不同。务必在spiOverJtag/目录下找到与你芯片型号完全匹配的那个文件。用错了文件,会导致SPI Flash无法被正确识别和操作。如果你在这个目录下找不到你的芯片型号,可能需要去开源社区查询,或者尝试用其他型号的桥接文件(有一定风险),最稳妥的方法是参照源码自己为你的芯片生成一个。
最后是操作模式。-f参数默认行为是写入Flash。如果你只想下载到SRAM,不应该使用-f,而应该使用-m参数,或者像前面那样,只提供文件而不加-B参数。工具的输出信息是很好的调试帮手,仔细阅读“Detected:”后面跟的Flash型号和容量,可以确认硬件连接是否正确。
7. 避坑指南:常见问题与解决方法
在实际使用中,你肯定会遇到一些“坑”。我把最常见的问题和解决方法整理出来,希望能帮你节省大量排查时间。
问题一:执行命令报错 “Unable to find cable” 或 “No device found”。
- 排查思路:这是最典型的连接问题。首先,运行
lsusb(Linux)或检查设备管理器(Windows),确认系统是否识别到了CH347设备。如果没看到,检查USB线、尝试换USB口、重启电脑。 - 驱动问题(Windows专属):确保安装了正确的JTAG模式驱动,而不是普通的串口驱动。在设备管理器中,设备应该显示为“USB2.0 HS JTAG”或类似描述,而不是“USB Serial Port”。
- PID错误:确认你使用的PID是否正确。CH347F是
0x55de,CH347T模式3是0x55dd。在命令中通过--pid参数指定。 - 权限问题(Linux专属):如果
lsusb能看到设备但命令报错,尝试在命令前加sudo。如果加了sudo可以,说明需要按照前面章节配置USB设备权限。
问题二:--detect能发现FPGA,但固化到Flash时失败,提示“flash chip unknown”或“unlock blocks timeout”。
- 首要检查
-B参数:99%的问题出在这里。请百分之百确认-B指定的桥接文件路径正确,且文件名与你的FPGA型号、封装完全一致。一个字母都不能错。 - 降低JTAG频率:这是第二有效的办法。将
--freq参数从30MHz逐步降低到15MHz、7.5MHz、1.875MHz甚至更低,直到操作成功。长导线、劣质杜邦线、板内干扰都会影响高速信号质量。 - 检查硬件连接:重点检查CH347与FPGA板之间的GND连接是否牢固可靠。SPI Flash相关的引脚(FPGA上连接Flash的MOSI, MISO, SCK, CS)是否正常,Flash芯片本身是否完好。
- 电源稳定性:在擦写Flash的瞬间,电流需求可能增大。确保你的FPGA板和CH347模块供电充足、稳定。可以尝试外接电源而非仅靠USB供电。
问题三:下载到SRAM成功,但程序功能不正常。
- 时钟频率过高:尝试降低
--freq。过高的JTAG时钟可能导致数据传输出错,虽然进度条能走完,但写入SRAM的数据是错的。 - 比特流文件问题:确认你生成的
.bit文件是正确的,并且是针对当前这块FPGA板生成的(引脚约束、时钟频率等)。可以用回官方编程软件(如Vivado Hardware Manager)下载一次,验证文件本身是否正确。 - FPGA配置模式:确保FPGA的启动模式(M0, M1, M2等引脚)设置在了JTAG模式,而不是SPI或其它模式。
问题四:在Windows下,MSYS2环境编译或运行报错。
- 确保使用正确的终端:一定要在MSYS2 UCRT64或MINGW64终端中执行编译和运行命令,不要在普通的Windows CMD或PowerShell中操作。
- 编译时找不到libusb:确认已通过
pacman -S mingw-w64-ucrt-x86_64-libusb安装了libusb库。 - 运行时找不到DLL:如果直接双击exe或在CMD中运行提示缺少
libusb-1.0.dll,需要将这个DLL(位于MSYS2安装目录的ucrt64\bin下)复制到和openFPGALoader.exe相同的目录,或者将其路径添加到系统环境变量PATH中。
遇到问题别着急,按照“硬件连接 -> 驱动/PID -> 桥接文件 -> 降低频率”这个顺序一步步排查,大部分问题都能迎刃而解。多动手试几次,你对整个流程的理解会深刻得多。
