FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解
FPGA之Usb数据传输
Usb 通信
你也许会有疑问,明明有这么多通信方式和数据传输(SPI、I2C、UART、以太网)为什么偏偏使用USB呢?
原因有很多,如下:
1. 高速数据传输能力
- 高带宽:USB接口提供了较高的数据传输速率,尤其是随着USB版本的升级(如USB 3.0及更高版本),其理论速度可达5 Gbps甚至更高。这对于需要高速数据传输的应用(如视频处理、实时数据采集等)尤为重要。
- 低延迟:相比一些其他接口(如UART),USB的延迟更低,能够满足实时性要求较高的场景。
2. 通用性和兼容性
- 广泛的硬件支持:几乎所有现代计算机和嵌入式系统都配备了USB接口,这意味着使用USB进行通信可以轻松实现跨平台支持,无需额外的硬件适配。
- 标准化接口:USB是一种标准化的接口,遵循统一的协议和规范。这不仅简化了开发过程,还确保了不同设备之间的互操作性。
3. 开发便利性
- 丰富的工具支持:大多数FPGA开发工具(如Xilinx Vivado、Altera Quartus等)都提供了对USB接口的支持,简化了设计和验证过程。
- 成熟的驱动和库资源:大量的现成驱动程序和库资源可以轻松集成到项目中,减少了软件开发的工作量。
4. 灵活的通信模式
- 全双工通信:USB支持全双工通信模式,允许同时进行数据的上传和下载,提高了通信效率。
- 多种数据传输类型:USB支持控制传输、批量传输、中断传输和同步传输等多种数据传输类型,能够适应不同应用场景的需求。
成本效益
- 低成本解决方案:相比于一些高端接口(如PCIe),USB的成本较低,适合预算有限的项目。
- 减少外部组件需求:由于USB的标准化和广泛支持,可以减少对外部组件的需求,从而降低整体硬件成本。
也正是因为如此,usb广泛应用于数据的采集和处理、视频和音频传输、嵌入式系统开发等。
而我们今天即将要学习的,就是FPGA的USB传输,以FX2芯片为例
FX2
USB是一种通用的数据传输协议和接口标准,定义了设备与主机(如电脑)之间的通信规则(如协议、电气特性、数据传输模式等);FX系列芯片(FX2, FX3)是Cypress(现英飞凌)推出的USB控制芯片,用于实现高速USB设备的功能。说的再简单,直白一点:USB是协议标准,FX芯片是实现这一标准的硬件载体
FX芯片可以
- 自动处理USB复杂协议,无需开发者手动实现,
- 支持高速传输(FX2:支持USB2.0高速传输, 480Mbps; FX3则为 5Gbps)
- 提供灵活的接口(GPIF,Slave FIFO)方便直接连接外设,
- 内置微控制器,可以通过固件配置USB功能
FX2控制器内部结构图如下

FX2可以通过两种方式到FPGA,一个是(通用可编程接口)GPIF模式和从设备FIFO模式
GPIF:FX2是总线的主控者,用户自定义时序,灵活但开发复杂
Slave FIFO: FX2是被动的FIFO从设备,外部主控直接控制,简单但灵活性受限

在实际项目中,Slave FIFO模式更常用(尤其是FPGA做为主控的场景),而GPIF模式需要更精确控制总线的特殊需求
回环测试
介绍
我们此处就以简单的回环测试为例,实现FPGA的Usb数据传输。

所谓回环测试,就是说由 PC 发送数据到 FX2 芯片的 OUT 端点 2,然后再由主机将端点 2 中的数据读出,拷贝到IN 端点 6。使用 FPGA 设计 SlaveFIFO 读取和写入接口逻辑,将端点 2 中的数据读出,然后写入端点 6 中,再由电脑上位机从端点 6 中将数据读回,从而实现数据的回环。
代码
FIFO
module FiFo #( Depth = 512,Width = 16
)
(input fifo_clk,input rst_n,input write_busy,input read_busy,input fifo_flush,input [Width-1:0]din,output reg fifo_full,output reg fifo_empty,output reg [Width-1:0] dout
);localparam ADDR_Width =$clog2(Depth);//计数多加一位,防止溢出
reg [ADDR_Width:0] write_occupancy;
reg [ADDR_Width:0] read_occupancy;
wire [ADDR_Width:0] next_write_occupancy;
wire [ADDR_Width:0] next_read_occupancy;//fifo 地址索引
wire [ADDR_Width-1:0] next_write_ptr;
reg [ADDR_Width-1:0] write_ptr;
wire [ADDR_Width-1:0] next_read_ptr;
reg [ADDR_Width-1:0] read_ptr;reg [Width-1:0] data_array[Depth-1:0];wire write_enable;
wire read_enable;// 写使能和读使能逻辑
assign write_enable = !write_busy && !fifo_full;
assign read_enable = !read_busy && !fifo_empty;// 下一个指针和计数器计算
assign next_write_ptr = (write_enable) ? (write_ptr + 1) : write_ptr;
assign next_read_ptr = (read_enable) ? (read_ptr + 1) : read_ptr;assign next_write_occupancy = fifo_flush ? 10'd0 : (write_enable ? (write_occupancy + 1) : write_occupancy);
assign next_read_occupancy = fifo_flush ? 10'd0 : (read_enable ? (read_occupancy + 1) : read_occupancy);// 满/空状态判断(基于下一个计数器值)
wire [ADDR_Width:0] next_occupancy_diff = next_write_occupancy - next_read_occupancy;
wire next_fifo_full = (next_occupancy_diff >= Depth);
wire next_fifo_empty = (next_occupancy_diff == 0);//更新指针
always @(posedge fifo_clk or negedge rst_n)beginif(!rst_n)beginwrite_ptr<=0;read_ptr<=0;end else if(fifo_flush)beginwrite_ptr<=0;read_ptr<=0;end else beginwrite_ptr<=next_write_ptr;read_ptr<=next_read_ptr;end//else
end//always// 更行空/满信号
always @(posedge fifo_clk or negedge rst_n)beginif(!rst_n)beginfifo_full<=0;fifo_empty<=1;end else if (fifo_flush)beginfifo_full<=0;fifo_empty<=1;end else beginfifo_full<=next_fifo_full;fifo_empty<=next_fifo_empty;end
end//always// 读/写计数always @(posedge fifo_clk or negedge rst_n)beginif(!rst_n)beginwrite_occupancy<=0;read_occupancy<=0;end else if(fifo_flush)beginwrite_occupancy<=0;read_occupancy<=0;end else beginwrite_occupancy<=next_write_occupancy;read_occupancy<=next_read_occupancy;end//else
end//always//输出数据
always @(posedge fifo_clk or negedge rst_n)beginif(!rst_n)dout<=0;else if(fifo_flush) dout<=0;else dout<=data_array[read_ptr];
end//always//数据写入存储阵列
always @(posedge fifo_clk)beginif(write_enable)data_array[write_ptr]<=din;
end// 溢出警告
always @(posedge fifo_clk) beginif (fifo_full && write_busy) begin$display("ERROR: %m: Fifo overflow at time %t", $time);$finish;end
end // always// 下溢警告
always @(posedge fifo_clk) beginif (fifo_empty && read_busy) begin$display("ERROR: %m: Fifo underflow at time %t", $time);$finish;end
end // always
// synthesis translate_on
endmodule
FX2_SF
module FX2_SF(input clk,input reset_n,inout [15:0] fx2_fdata, // 双向数据总线output [1:0] fx2_faddr, // FIFO地址选择output fx2_slrd, // 读使能(低有效)output fx2_slwr, // 写使能(低有效)output fx2_sloe, // 输出使能(低有效)input ep6_full_flag, // EP6满标志(可写)input ep2_empty_flag, // EP2空标志(可读)input fx2_ifclk, // 接口时钟(60MHz)output fx2_pkt_end, // 包结束脉冲output fx2_clear, // 复位信号output fx2_slcs // 片选(常低)
);//------------------------ 参数优化 ------------------------//
localparam [1:0] LOOPBACK_IDLE = 2'd0,LOOPBACK_READ = 2'd1,LOOPBACK_WAIT_ep6_full = 2'd2,LOOPBACK_WRITE = 2'd3;localparam [1:0]FIFO_ADDR_READ = 2'b00, // EP2FIFO_ADDR_WRITE = 2'b10; // EP6//------------------------ 信号声明 ------------------------//
reg [1:0] current_state, next_state;// FIFO控制信号
wire fifo_wr_en;
wire fifo_rd_en;
reg [15:0] fifo_din;
wire [15:0] fifo_dout;// FX2接口信号
reg slrd_n;
reg slwr_n;
reg sloe_n;
reg [1:0] faddr_n;
reg pkt_end_n;//------------------------ 接口分配 ------------------------//
assign fx2_slwr = slwr_n;
assign fx2_slrd = slrd_n;
assign fx2_sloe = sloe_n;
assign fx2_faddr = faddr_n;
assign fx2_pkt_end= pkt_end_n;
assign fx2_slcs = 1'b0; // 常使能
assign fx2_clear = 1'b0; // 未使用// 三态总线控制
assign fx2_fdata = (slwr_n == 1'b0) ? fifo_dout : 16'hzzzz;//------------------------ 状态机 ------------------------//
always @(posedge fx2_ifclk or negedge reset_n) beginif(!reset_n) current_state <= LOOPBACK_IDLE;else current_state <= next_state;
endalways @(*) beginnext_state = current_state;case(current_state)LOOPBACK_IDLE: //ep2为空, 上位机可传输数据if(ep2_empty_flag) next_state = LOOPBACK_READ;LOOPBACK_READ: if(!ep2_empty_flag) next_state = LOOPBACK_WAIT_ep6_full;LOOPBACK_WAIT_ep6_full: if(ep6_full_flag) next_state = LOOPBACK_WRITE;LOOPBACK_WRITE: beginif(!ep6_full_flag || fifo_empty) next_state = LOOPBACK_IDLE;enddefault: next_state = LOOPBACK_IDLE;endcase
end//------------------------ 控制信号生成 ------------------------//
always @(*) begin// 默认值slrd_n = 1'b1;sloe_n = 1'b1;slwr_n = 1'b1;faddr_n = FIFO_ADDR_READ;pkt_end_n = 1'b1;case(current_state)LOOPBACK_READ: beginfaddr_n = FIFO_ADDR_READ;slrd_n = !ep2_empty_flag; // 有数据时持续读取sloe_n = !ep2_empty_flag;endLOOPBACK_WRITE: beginfaddr_n = FIFO_ADDR_WRITE;slwr_n = !(ep6_full_flag && !fifo_empty);// 在最后一次写入后生成包结束脉冲pkt_end_n = (slwr_n == 1'b0) ? 1'b0 : 1'b1;endendcase
end//------------------------ FIFO接口 ------------------------//
assign fifo_wr_en = (current_state == LOOPBACK_READ) && !slrd_n;
assign fifo_rd_en = (current_state == LOOPBACK_WRITE) && !slwr_n;// 数据输入寄存器
always @(posedge fx2_ifclk) beginif(fifo_wr_en) fifo_din <= fx2_fdata;
endFiFo #(.Depth(512),.Width(16)
) u_fifo (.fifo_clk (fx2_ifclk),.rst_n (reset_n),.write_busy (1'b0), // 外部无写阻塞.read_busy (1'b0), // 外部无读阻塞.fifo_flush (1'b0), // 禁用自动flush.din (fifo_din),.fifo_full (fifo_full),.fifo_empty (fifo_empty),.dout (fifo_dout)
);wire clk_96m;//生成96M时钟用于ILA采样pll pll_inst(.clk_out1(clk_96m),.clk_in1(clk));//------------------------ 调试模块注释 ------------------------//ila_0 ila_0_inst(.clk(clk_96m), // input wire clk.probe0(fx2_fdata), // input wire [15:0] probe0 .probe1(fx2_faddr), // input wire [1:0] probe1 .probe2(ep2_empty_flag), // input wire [0:0] probe2 .probe3(ep6_full_flag), // input wire [0:0] probe3 .probe4(fx2_sloe), // input wire [0:0] probe4 .probe5(fx2_slwr), // input wire [0:0] probe5 .probe6(fx2_slrd), // input wire [0:0] probe6 .probe7(fifo_empty), // input wire [0:0] probe7 .probe8(fifo_full), // input wire [0:0] probe8 .probe9(fifo_flush) // input wire [0:0] probe9);endmodule
注:实现该项目时需要使用到 Cypress提供的基本开发包(名为CySuiteUsb)和安装对应的驱动,可以到官网上去下载。
相关文章:
FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解
FPGA之Usb数据传输 Usb 通信 你也许会有疑问,明明有这么多通信方式和数据传输(SPI、I2C、UART、以太网)为什么偏偏使用USB呢? 原因有很多,如下: 1. 高速数据传输能力 高带宽:USB接口提供了较高的数据传…...
【Office-Word】如何自动生成中英文目录
1.目录介绍 Word这个自动生成目录非常强大,涉及的功能很琐碎,想要完美的生成目录不仅仅是只会目录这么简单,前后涉及到的大纲级别、目标样式和域代码等操作是比较头疼的。 下面就一步一步开始介绍 2.多级标题级别编号设置 目录想要设置好…...
Oracle删除重复数据保留其中一条
Oracle删除重复数据保留其中一条 在Oracle数据库中,要删除重复数据并保留其中一条记录,可以使用多种方法。这里介绍两种常见的方法:使用ROWID或使用ROW_NUMBER()窗口函数。 方法1:使用ROWID ROWID是Oracle中用来唯一标识表中每…...
CentOS 7 安装Nginx-1.26.3
无论安装啥工具、首先认准了就是官网。Nginx Nginx官网下载安装包 Windows下载: http://nginx.org/download/nginx-1.26.3.zipLinxu下载 wget http://nginx.org/download/nginx-1.26.3.tar.gzLinux安装Nginx-1.26.3 安装之前先安装Nginx依赖包、自行选择 yum -y i…...
家政预约小程序用例图分析
在和客户进行需求沟通的时候,除了使用常规的问答的形式,我还使用图形化工具更深入的沟通。比如借助UML的用例图来开展系统分析,并且按照角色详细拆解了家政预约小程序的各个用例。在分析阶段思考的越多,沟通的越多,在系…...
112页精品PPT | DeepSeek行业应用实践报告
这份文件是一份关于DeepSeek行业应用实践的报告,以PPT形式呈现,共112页,详细介绍了DeepSeek及其核心产品DeepSeek-R1的技术特点、市场表现、应用路径以及在多领域的实践案例。报告展示了DeepSeek在市场上的快速崛起,包括其日活用户…...
计算机毕业设计SpringBoot+Vue.js航空机票预定系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
C语言学习笔记-初阶(27)操作符详解1:位操作
1. 操作符的分类 上述的操作符,我们已经学过算术操作符、赋值操作符、逻辑操作符、条件操作符和部分的单目操作符,今天继续介绍⼀部分,操作符中有一些操作符和二进制有关系,我们先铺垫一下二进制的和进制转换的知识。 2. 二进制、…...
网络安全需要学多久才能入门?
网络安全是一个复杂且不断发展的领域,想要入行该领域,我们需要付出足够多的时间和精力好好学习相关知识,才可以获得一份不错的工作,那么网络安全需要学多久才能入门?我们通过这篇文章来了解一下。 学习网络安全的入门时间因个人的…...
20250304学习记录
第一部分,先来了解一下各种论文期刊吧,毕竟也是这把岁数了,还什么都不懂呢 国际期刊: EI收集的主要有两种, JA:EI源刊 CA:EI会议 CPCI也叫 ISTP 常说的SCI分区是指,JCR的一区、…...
【星云 Orbit • STM32F4】08. 用判断数据头来接收据的串口通用程序框架
【星云 Orbit • STM32F4】08. 用判断数据头来接收据的串口通用程序框架 1. 引言 本教程旨在帮助嵌入式开发小白从零开始,学习如何在STM32F407微控制器上实现一个基于串口的数据接收程序。该程序能够通过判断数据头来接收一串数据,并将其存储到缓冲区中…...
文件上传复现
文件上传漏洞的概念 在现代互联网的web应用程序中,上传文件是一种常见的功能,因为它有助于提高业务效率,比如社交 网站中,允许用户上传图片、视频、头像和许多其他类型的文件。然而向用户提供的功能越多, web应 用受到…...
Redis——缓存穿透、击穿、雪崩
缓存穿透 什么是缓存穿透 缓存穿透说简单点就是大量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层。举个例子:某个黑客故意制造我们缓存中不存在的 key 发起大量请求,导致大量请求落到数据库…...
HMC7043和HMC7044芯片配置使用
一,HMC7043芯片 MC7043独特的特性是对14个通道分别进行独立灵活的相位管理。所有14个通道均支持频率和相位调整。这些输出还可针对50 Ω或100 Ω内部和外部端接选项进行编程。HMC7043器件具有RF SYNC功能,支持确定性同步多个HMC7043器件,即确保所有时钟输出从同一时钟沿开始…...
STM32程序的加密与破解以及烧录方法
STM32程序的加密与破解,以及烧录方法。 盗取他人的PCB和烧录文件,可以节省大大开发成本,何乐而不为呢。因此,就滋生了一些协助他人盗版的公司。为了防止被盗版和复制,单片机工程师也是煞费苦心,对硬件和软…...
Redis和MySQL的实时数据同步方案
针对 Redis 和 MySQL 的实时数据同步,需根据业务场景选择不同的技术方案,核心目标是保障数据一致性、降低延迟、提升系统可靠性。以下是几种典型方案及其适用场景: 方案一:基于 MySQL Binlog 的异步同步 原理 监听 MySQL 的 Bin…...
VSCode知名主题带毒 安装量900万次
目前微软已经从 Visual Studio Marketplace 中删除非常流行的主题扩展 Material Theme Free 和 Material Theme Icons,微软称这些主题扩展包含恶意代码。 统计显示这些扩展程序的安装总次数近 900 万次,在微软实施删除后现在已安装这些扩展的开发者也会…...
JavaScript 进阶A(作用域、闭包、变量和函数提升、函数相关只是、数组解构、对象解构、构造函数
1.作用域 作用域主要分为:局部作用域和全局作用域。 局部作用域又分为:函数作用域和块作用域 函数作用域:在函数中定义的变量只能在函数内部使用,外部无法访问块作用域:被大括号{}包起来的代码块,在这个…...
mybatis映射文件相关的知识点总结
mybatis映射文件相关的知识点总结 mybatis官网地址 英文版:https://mybatis.org/mybatis-3/index.html 中文版:https://mybatis.p2hp.com/ 搭建环境 /* SQLyog Ultimate v10.00 Beta1 MySQL - 8.0.30 : Database - mybatis-label *****************…...
【UCB CS 61B SP24】Lecture 21: Data Structures 5: Priority Queues and Heaps 学习笔记
本文介绍了优先队列与堆,分析了最小堆的插入与删除过程,并用 Java 实现了一个通用类型的最小堆。 1. 优先队列 1.1 介绍 优先队列是一种抽象数据类型,其元素按照优先级顺序被处理。不同于普通队列的先进先出(FIFO)&…...
【JAVA】ThreadPoolTaskExecutor 线程池学习、后端异步、高并发处理
ThreadPoolTaskExecutor 是 Spring 框架提供的一个线程池实现类,基于 Java 原生的 ThreadPoolExecutor 进行了封装和扩展,支持更灵活的配置,并与 Spring 的依赖注入、生命周期管理等功能无缝集成。它常用于异步任务处理、定时任务调度和高并发…...
C#:LINQ学习笔记01:LINQ基础概念
一、LINQ 架构体系 1. LINQ 的核心思想 统一查询模型:对对象、XML、数据库等不同数据源使用一致的语法。强类型检查:编译时类型安全,减少运行时错误。 2. 核心组件 技术数据源典型场景LINQ to Objects内存集合 (IEnumerable)过滤/排序集合…...
爬虫系列之发送请求与响应《一》
一、请求组成 1.1 请求方式:GET和POST请求 GET:从服务器获取,请求参数直接附在URL之后,便于查看和分享,常用于获取数据和查询操作 POST:用于向服务器提交数据,其参数不会显示在URL中,而是包含在…...
【零基础到精通Java合集】第十集:List集合框架
课程标题:List集合框架(15分钟) 目标:掌握List接口核心实现类(ArrayList/LinkedList)的使用与场景选择,熟练操作有序集合 0-1分钟:List概念引入 以“购物清单”类比List特性:元素有序(添加顺序)、可重复、支持索引访问。说明List是Java集合框架中最常用的数据结构…...
小米手机如何录制屏幕?手机、电脑屏幕录制方法分享
大家最近有没有遇到想记录手机屏幕操作的情况? 比如精彩的游戏瞬间、有趣的视频教程,或者需要录制屏幕来制作演示材料。小米手机在这方面可是个好帮手,今天就来给你好好唠唠,小米手机如何录制屏幕,以及后续如何处理这…...
【RTC】 TM32 RTC(实时时钟)库函数 配置
1. 硬件配置 与HAL库相同,需确保以下硬件条件: 外部低速晶振(LSE,32.768kHz)连接至 OSC32_IN 和 OSC32_OUT 引脚。 备用电池(VBAT)已连接,确保断电时RTC持续运行。 2. 标准外设库(库函数)配置步骤 2.1 初始化RTC时钟源 #include "stm32f10x.h" #include…...
策略模式的C++实现示例
核心思想 策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装在独立的类中,使得它们可以互相替换。策略模式让算法的变化独立于使用它的客户端,从而使得客户端可以根据需要动态切换算法,而不需要修改…...
deepseek、腾讯元宝deepseek R1、百度deepseekR1关系
分析与结论 区别与联系 技术基础与定制方向: DeepSeek官网R1版本:作为基础版本,通常保留通用性设计,适用于广泛的AI应用场景(如自然语言处理、数据分析等)。其优势在于技术原生性和官方直接支持。腾讯元宝…...
Leetcode 面试150题(三)
一、题目 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &am…...
3D Web轻量化引擎HOOPS Communicator的核心优势解析:高性能可视化与灵活部署!
在当今数字化时代,工业领域的工程应用不断向基于Web的方向发展,而HOOPS Web平台作为一款专为构建此类工程应用程序打造的软件开发套件集,正发挥着日益重要的作用,成为构建强大工程应用的基石。 一、HOOPS Web平台概述 HOOPS Web…...
