当前位置: 首页 > article >正文

FPGA实战项目2———多协议通信控制器

1. 多协议通信控制器模块 (multi_protocol_controller)

简要介绍

这是整个设计的顶层模块,承担着整合各个子模块的重要任务,是整个系统的核心枢纽。它负责协调 UART、SPI、I2C 等不同通信协议模块以及 DMA 模块的工作,同时处理不同时钟域之间的信号交互,确保各个模块能够在不同的时钟环境下稳定、高效地协同工作。

原理
  • 时钟管理:系统存在两个不同的时钟域,即系统时钟域(clk_sys)和外设时钟域(clk_peri)。不同的模块可能工作在不同的时钟域,这就需要进行跨时钟域处理,以避免数据传输过程中出现亚稳态等问题。
  • 信号同步:对于单比特信号(如 dma_start 和 dma_done),使用同步器sync_module)进行跨时钟域同步。同步器通过两级触发器的方式,将输入信号在目标时钟域下进行同步,从而避免亚稳态信号传播到后续逻辑中。对于多比特数据的跨时钟域传输,则使用同步 FIFOsync_fifo)来缓存和传输数据,确保数据在不同时钟域之间的可靠传输。
  • 模块实例化:实例化 UART、SPI、I2C 模块以及 DMA 模块,并将它们的输入输出信号进行合理连接,使得各个模块能够相互协作,完成多协议通信和数据传输的任务。
代码展示:
module multi_protocol_controller #(parameter SYS_CLK_FREQ = 100_000_000,  // 系统时钟频率 (Hz)parameter PERI_CLK_FREQ = 50_000_000    // 外设时钟频率 (Hz)
)(// 系统时钟域(高速时钟,如 CPU 时钟)input wire clk_sys,        // 系统时钟(通常 50MHz/100MHz)input wire rst_n_sys,      // 系统时钟域复位(异步,低有效)// 外设时钟域(低速时钟,如外设接口时钟)input wire clk_peri,       // 外设时钟(通常 50MHz 或更低)input wire rst_n_peri,     // 外设时钟域复位(异步,低有效)// UART 接口input wire uart_rx,        // UART 接收output wire uart_tx,       // UART 发送// SPI 接口input wire spi_miso,       // SPI 主入从出output wire spi_mosi,      // SPI 主出从入output wire spi_sclk,      // SPI 时钟output wire spi_cs_n,      // SPI 片选(低有效)// I2C 接口inout wire i2c_sda,        // I2C 双向数据线output wire i2c_scl,       // I2C 时钟线// DMA 控制接口(系统时钟域)input wire dma_start,       // DMA 传输启动信号(系统时钟域)input wire [31:0] dma_src_addr,  // 源地址(系统地址空间)input wire [31:0] dma_dst_addr,  // 目的地址(系统地址空间)input wire [15:0] dma_length,    // 传输长度(字节数)output wire dma_done,        // DMA 完成标志(系统时钟域)// 调试接口output wire [7:0] debug_info  // 预留调试信号
);// ========== 跨时钟域信号声明 ==========
// 系统时钟域 → 外设时钟域(单比特同步)
wire dma_start_peri;          // 同步后的 DMA 启动信号(外设时钟域)
// 外设时钟域 → 系统时钟域(单比特同步)
wire dma_done_sys;            // 同步后的 DMA 完成信号(系统时钟域)// 多比特数据跨时钟域(外设 ↔ 系统)
wire [7:0] dma_data_peri;     // 外设时钟域 DMA 数据
wire [7:0] dma_data_sys;      // 系统时钟域 DMA 数据
wire dma_data_valid_peri;     // 外设时钟域数据有效
wire dma_data_valid_sys;      // 系统时钟域数据有效// ========== 同步器实例化(单比特跨时钟域) ==========
// DMA 启动信号同步(系统 → 外设)
sync_module #(.WIDTH(1)) u_sync_dma_start (.clk_dst(clk_peri),.rst_n_dst(rst_n_peri),.data_in(dma_start),.data_out(dma_start_peri)
);// DMA 完成信号同步(外设 → 系统)
sync_module #(.WIDTH(1)) u_sync_dma_done (.clk_dst(clk_sys),.rst_n_dst(rst_n_sys),.data_in(dma_done),    // 注意:dma_done 是外设时钟域生成的信号(见 DMA 模块连接).data_out(dma_done_sys)
);
assign dma_done = dma_done_sys;  // 输出到系统时钟域的完成标志// ========== 同步 FIFO 实例化(多比特跨时钟域) ==========
sync_fifo #(.DATA_WIDTH(8),.DEPTH(64)  // 深度扩展至 64
) u_sync_fifo (.wr_clk(clk_peri),       // 写时钟:外设时钟域(协议模块输出数据).wr_rst_n(rst_n_peri),.wr_en(dma_data_valid_peri),.din(dma_data_peri),.rd_clk(clk_sys),       // 读时钟:系统时钟域(DMA 读取数据).rd_rst_n(rst_n_sys),.rd_en(dma_data_valid_sys),.dout(dma_data_sys)
);// ========== 协议模块实例化(外设时钟域) ==========
// UART 模块
uart_module u_uart (.clk(clk_peri),.rst_n(rst_n_peri),.baud_rate_div(26'd500),  // 波特率 115200 @ 50MHz 时钟.rx(uart_rx),.tx(uart_tx),.data_out(dma_data_peri),  // UART 接收数据作为 DMA 输入(外设 → 系统).data_valid(dma_data_valid_peri)
);// SPI 模块(主设备模式)
spi_module u_spi (.clk(clk_peri),.rst_n(rst_n_peri),.clk_div(8'd10),         // SPI 时钟分频(生成 5MHz 时钟 @ 50MHz 外设时钟).miso(spi_miso),.mosi(spi_mosi),.sclk(spi_sclk),.cs_n(spi_cs_n),.data_out(dma_data_peri),  // SPI 接收数据作为 DMA 输入.data_valid(dma_data_valid_peri)
);// I2C 模块(主设备模式)
i2c_module u_i2c (.clk(clk_peri),.rst_n(rst_n_peri),.CLK_FREQ(PERI_CLK_FREQ),.I2C_FREQ(400_000),       // I2C 总线频率 400kHz.start(1'b0),             // 预留 I2C 启动信号(可扩展).i2c_addr(7'd0),          // 预留设备地址(可扩展).tx_data(8'd0),           // 预留发送数据(可扩展).tx_en(1'b0),             // 预留发送使能(可扩展).rx_en(1'b0),             // 预留接收使能(可扩展).tx_done(),               // 预留发送完成(可扩展).rx_done(),               // 预留接收完成(可扩展).rx_data(dma_data_peri),  // I2C 接收数据作为 DMA 输入.ack_error(debug_info[0]),// 调试信号(应答错误).sda(i2c_sda),.scl(i2c_scl)
);// ========== DMA 模块实例化(双时钟域) ==========
dma_module u_dma (.clk_sys(clk_sys),.rst_n_sys(rst_n_sys),.clk_peri(clk_peri),.rst_n_peri(rst_n_peri),.dma_start(dma_start_peri),  // 同步后的启动信号(外设时钟域).dma_src_addr(dma_src_addr),.dma_dst_addr(dma_dst_addr),.dma_length(dma_length),.dma_data_in(dma_data_sys),   // 系统时钟域数据(来自同步 FIFO).dma_data_out(dma_data_peri), // 外设时钟域数据(发送到协议模块).dma_data_valid_in(dma_data_valid_sys),  // 系统时钟域数据有效.dma_data_valid_out(dma_data_valid_peri),// 外设时钟域数据有效.dma_done(dma_done)          // DMA 完成标志(外设时钟域生成,同步到系统)
);// ========== 调试信号 ==========
assign debug_info = {dma_data_valid_peri,    // 调试位 0:外设数据有效dma_data_valid_sys,     // 调试位 1:系统数据有效u_i2c.ack_error,        // 调试位 2:I2C 应答错误5'b0                   // 预留其他调试位
};endmodule


2. 同步器模块 (sync_module)

简要介绍

该模块主要用于处理单比特信号的跨时钟域同步问题。在数字电路中,当信号从一个时钟域传输到另一个时钟域时,如果不进行同步处理,可能会出现亚稳态现象,导致后续逻辑出现错误。同步器通过简单的两级触发器结构,有效地解决了这个问题。

原理
  • 两级触发器结构:同步器内部包含两级触发器,第一级触发器在源时钟域下采样输入信号,将其存储在 sync_reg 中。第二级触发器在目标时钟域下采样 sync_reg 的输出,并将其作为最终的同步输出信号 dat

相关文章:

FPGA实战项目2———多协议通信控制器

1. 多协议通信控制器模块 (multi_protocol_controller) 简要介绍 这是整个设计的顶层模块,承担着整合各个子模块的重要任务,是整个系统的核心枢纽。它负责协调 UART、SPI、I2C 等不同通信协议模块以及 DMA 模块的工作,同时处理不同时钟域之间的信号交互,确保各个模块能够…...

CST软件仿真案例——太阳能薄膜频谱吸收率

CST软件中的太阳能薄膜的功率吸收可用光频电磁波在介质材料中的损耗来计算。本案例计算非晶硅的功率吸收,然后考虑真实太阳频谱,计算有效吸收频谱。 用太阳能单元模板,时域求解器: 材料库提取四个材料,非晶硅&#xf…...

多线程进阶核心知识详解(通俗版)

Java多线程进阶详解 一、锁策略:如何高效管理资源竞争 在多线程环境中,锁是协调资源访问的核心机制。不同的锁策略适用于不同的场景,理解它们的差异能帮助优化程序性能。 1. 乐观锁 vs 悲观锁 悲观锁: 核心思想:假设…...

大模型中的KV Cache

1. KV Cache的定义与核心原理 KV Cache(Key-Value Cache)是一种在Transformer架构的大模型推理阶段使用的优化技术,通过缓存自注意力机制中的键(Key)和值(Value)矩阵,避免重复计算&…...

FHQ平衡树

FHQ平衡树 大致是这样的题目: 您需要动态地维护一个可重集合 M M M,并且提供以下操作: 向 M M M 中插入一个数 x x x。从 M M M 中删除一个数 x x x(若有多个相同的数,应只删除一个)。查询 M M M 中…...

力扣算法---总结篇

5.13 数组总结 数组是存放在连续内存空间上的相同类型数据的集合。 数组可以方便的通过下标索引的方式获取到下标对应的数据。 正是因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。 数组的元素是不…...

ABAP+旧数据接管的会计年度未确定

导资产主数据时,报错旧数据接管的会计年度未确定 是因为程序里面使用了下列函数AISCO_CALCULATE_FIRST_DAY,输入公司代码,获取会计年度,这个数据是在后台表T093C表中取数的,通过SE16N可以看到后台表数据没有数&#xf…...

Java【10_1】用户注册登录(面向过程与面向对象)

测试题 1、基于文本界面实现登录注册的需求(要求可以满足多个用户的注册和登录) 通过工具去完成 公共类: public class User { private int id;//用户编号 private int username;//用户名 private int password;//密码 private String name;//真…...

养生:打造健康生活的全方位策略

在生活节奏不断加快的当下,养生已成为提升生活质量、维护身心平衡的重要方式。从饮食、运动到睡眠,再到心态调节,各个方面的养生之道共同构建起健康生活的坚实基础。以下为您详细介绍养生的关键要点,助您拥抱健康生活。 饮食养生…...

贪吃蛇游戏排行榜模块开发总结:从数据到视觉的实现

一、项目背景与成果概览 在完成贪吃蛇游戏核心玩法后,本次开发重点聚焦于排行榜系统的实现。该系统具备以下核心特性: 🌐 双数据源支持:本地存储(localStorage)与远程API自由切换 🕒 时间维度统计:日榜/周榜/月榜/全时段数据筛选 🎮 模式区分:闯关模式(关卡进度…...

pytorch 数据预处理和常用工具

文章目录 NumPyNumpy数据结构安装和使用NumPy Matplotlib的安装和导入安装和导入Matplotlib绘制基础图画折线图散点图柱状图图例 数据清洗据清洗的作用Pandas进行数据清洗Pandas数据结构Series 数据结构DataFrame数据结构 Pandas数据清洗常用代码 特征工程主成分分析线性判别分…...

如何界定合法收集数据?

首席数据官高鹏律师团队 在当今数字化时代,数据的价值日益凸显,而合法收集数据成为了企业、机构以及各类组织必须严守的关键准则。作为律师,深入理解并准确界定合法收集数据的范畴,对于保障各方权益、维护法律秩序至关重要。 一…...

企业对数据集成工具的需求及 ETL 工具工作原理详解

当下,数据已然成为企业运营发展过程中的关键生产要素,其重要性不言而喻。 海量的数据分散在企业的各类系统、平台以及不同的业务部门之中,企业要充分挖掘这些数据背后所蕴含的巨大价值,实现数据驱动的精准决策,数据集…...

内核深入学习3——分析ARM32和ARM64体系架构下的Linux内存区域示意图与页表的建立流程

内核深入学习3——ARM32/ARM64在Linux内核中的实现(2) ​ 今天我们来讨论的是一个硬核的内容,也是一个老生常谈的话题——那就是分析ARM32和ARM64体系架构下的Linux内存区域示意图的内容。对于ARM64的部分,我们早就知道一个基本的…...

MapReduce基本介绍

核心思想 分而治之:将大规模的数据处理任务分解成多个可以并行处理的子任务,然后将这些子任务分配到不同的计算节点上进行处理,最后将各个子任务的处理结果合并起来,得到最终的结果。 工作流程 Map 阶段: 输入数据被…...

屏幕与触摸调试

本章配套视频介绍: 《28-屏幕与触摸设置》 【鲁班猫】28-屏幕与触摸设置_哔哩哔哩_bilibili LubanCat-RK3588系列板卡都支持mipi屏以及hdmi显示屏的显示。 19.1. 旋转触摸屏 参考文章 触摸校准 参考文章 旋转触摸方向 配置触摸旋转方向 1 2 # 1.查看触摸输入设备 xinput…...

使用 百度云大模型平台 做 【提示词优化】

1. 百度云大模型平台 百度智能云千帆大模型平台  平台功能:演示了阿里云大模型的百炼平台,该平台提供Prompt工程功能,支持在线创建和优化Prompt模板模板类型:平台提供多种预制模板,同时也支持用户自定义…...

C 语言_常见排序算法全解析

排序算法是计算机科学中的基础内容,本文将介绍 C 语言中几种常见的排序算法,包括实现代码、时间复杂度分析、适用场景和详细解析。 一、冒泡排序(Bubble Sort) 基本思想:重复遍历数组,比较相邻元素,将较大元素交换到右侧。 代码实现: void bubbleSort(int arr[], i…...

IJCAI 2025 | 高德首个原生3D生成基座大模型「G3PT」重塑3D生成的未来

国际人工智能联合会议(IJCAI)是人工智能领域最古老、最具权威性的学术会议之一,自1969年首次举办以来,至今已有近六十年的历史。它见证了人工智能从萌芽到蓬勃发展的全过程,是全球人工智能研究者、学者、工程师和行业专…...

Samtec助力电视广播行业

【摘要前言】 现代广播电视技术最有趣的方面之一就是界限的模糊。过去,音频和视频是通过射频电缆传输的模拟技术采集的,而现在,数字世界已经取代了模拟技术。物理胶片和磁带已让位于数字存储设备和流媒体。 在这个过程中,连接器…...

密码学--仿射密码

一、实验目的 1、通过实现简单的古典密码算法,理解密码学的相关概念 2、理解明文、密文、加密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。 二、实验内容 1、题目内容描述 ①随机生成加密密钥,并验证密钥的可行性 ②从plain文件读入待…...

生成式图像水印研究综述

生成式图像水印研究综述 一、引言二、生成式图像水印研究背景三、生成式图像水印算法研究进展3.1 基于流模型的方案3.2 基于生成对抗网络的方案3.3 基于扩散模型的方案3.3.1 修改图像数据3.3.2 调整生成模型3.3.3 修改隐变量空间四、算法的性能与评价指标五、常用数据集六、本章…...

TCP协议详细讲解及C++代码实例

目录 一. TCP协议详细讲解及C代码实例1、TCP协议概述2、TCP通信流程1) 三次握手2) 数据传输3) 四次挥手 3、关键点解析1) 套接字创建2) 三次握手实现3) 数据传输4) 四次挥手实现 4、TCP与UDP对比 一. TCP协议详细讲解及…...

深度剖析:Vue2 项目兼容第三方库模块格式的终极解决方案

当我们为 Vue2 项目引入某些现代 JavaScript 库时,常常会遇到这样的报错: error in ./node_modules/some-lib/lib/index.mjs Cant import the named export xxx from non EcmaScript module这类问题的本质是模块格式的世纪之争 —— ES Module&#xff…...

APISQL免费版安装教程(视频)

APISQL 一款通用的API开发管理软件,支持将主流数据库中的表、视图、SQL语句、存储过程等快速封装为标准的 RESTful API,支持多种安全认证方式和可视化管理界面。适用于接口开发、系统集成、数据共享等场景。 支持主流数据库的表、视图、自定义函数、存储…...

SpringBoot整合MQTT实战:基于EMQX实现双向设备通信(附源码)

简言: 在万物互联的时代,MQTT协议凭借其轻量级、高效率的特性,已成为物联网通信的事实标准。本教程将带领您在Ubuntu系统上搭建EMQX 5.9.0消息服务器,并使用Spring Boot快速实现两个客户端的高效通信。通过本指南,您将…...

从零开始掌握FreeRTOS(2)链表之节点的定义

目录 节点 节点定义 节点实现 根节点 根节点定义 精简节点定义 根节点实现 在上篇文章,我们完成了 FreeRTOS 的移植。在创建任务之前,我们需要先了解FreeRTOS的运转机制。 FreeRTOS是一个多任务系统,由操作系统来管理执行每个任务。这些任务全都挂载到一个双向循…...

Java的While循环写的出票简单程序

import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int balance 0;while(true){System.out.print("请投币: ");int amount in.nextInt();balance balance amount;if(balance >10 )…...

详解Windows(十一)——网络连接设置

Windows网络连接设置完全指南 1. Windows网络连接基础 网络连接类型 有线连接: 通过网线将电脑连接到路由器或调制解调器优点:连接稳定,速度快,延迟低适合:需要高速稳定网络的场景,如游戏、大文件下载、…...

多线程爬虫语言选择与实现

之前文中有人提到:想要一个简单易用、能快速实现多线程爬虫的方案,而且目标是小网站,基本可以确定对反爬虫措施要求不高,这些就比较简单了。 以往我肯定要考虑常见的编程语言中哪些适合爬虫。Python、JavaScript(Node…...