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

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
http://www.xdnf.cn/news/4839.html

相关文章:

  • 学习黑客认识数字取证与事件响应(DFIR)
  • 安科瑞ADL3000-E-A/KC三相交流电能表CE认证导轨表
  • Spring AI 系列——使用大模型对文本内容分类归纳并标签化输出
  • React 中 useMemo 和 useEffect 的区别(计算与监听方面)
  • 传统销售VS智能销售:AI如何重构商业变现逻辑
  • Microsoft 365 Copilot:为Teams在线会议带来多语言语音交流新体验
  • 【计算机网络-传输层】传输层协议-TCP核心机制与可靠性保障
  • Ubuntu通过源码编译方式单独安装python3.12
  • 分享一款开源的图片去重软件 ImageContrastTools,基于Electron和hash算法
  • 二叉树的深度
  • 《被讨厌的勇气》书摘
  • JVM——即时编译
  • RabbitMQ-运维
  • 【C++设计模式之Observer观察者模式】
  • 5G让媒体传播更快更智能——技术赋能内容新时代
  • 深入详解人工智能数学基础——微积分中的微分方程在神经常微分方程(Neural ODE)中的应用
  • Vue3+ts复制图片到剪贴板
  • git相关
  • TB6600HG-富利威
  • k8s之statefulset
  • 养生:塑造健康生活的良方
  • 信赖域策略优化TRPO算法详解:python从零实现
  • Unity3D实现Render Streaming推送视频流的解决方案
  • Python爬虫(22)Python爬虫进阶:Scrapy框架动态页面爬取与高效数据管道设计
  • matlab转python
  • learning ray之ray强化学习/超参调优和数据处理
  • 出一期Source Insigned的使用教程
  • 湖南省密码协会成立,麒麟信安担任副会长单位共话密码创新应用之道
  • python里面的class,类,方法,函数,def
  • 深入剖析 I/O 复用之 select 机制