ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

107.零报错可复用!FPGA UART/SPI/DDR3 完整 Verilog 源码教程

107.零报错可复用!FPGA UART/SPI/DDR3 完整 Verilog 源码教程 摘要接口设计是FPGA工程化能力的核心分水岭。本文以实际项目中最高频的三大接口场景为线索:UART串口、SPI从机、DDR3控制器读写,从协议时序拆解、代码架构设计到仿真与板级调试方法,完整呈现一套可复用的接口设计方法论。所有代码均基于Verilog HDL编写,已在Xilinx Artix-7系列器件上验证通过,逻辑清晰、可直接移植。应用场景接口设计在以下场景中决定系统成败:工业控制:FPGA与MCU之间通过UART或SPI交换状态与指令,波特率误差超过2%即导致乱码。高速数据采集:ADC采样数据需经SPI或LVDS接口实时写入DDR3缓存,接口带宽不足直接丢数。嵌入式视觉:图像传感器输出并行数据,FPGA需完成时序转换后经AXI4接口存入DDR3,供处理器读取。通信基带:多通道串行收发接口的时钟恢复与相位对齐,是误码率的决定性因素。掌握接口设计的本质,是理解“协议时序”与“物理实现”之间的映射关系,而非死记代码。核心原理接口设计的三要素:时钟域、时序约束、状态机。时钟域:每个接口必须明确其时钟来源。UART使用系统时钟分频产生波特率时钟;SPI从机直接使用主机提供的SCK;DDR3则需经过MMCM/PLL产生高频读写时钟,并满足严格的相位关系。时序约束:对于跨时钟域信号,必须使用同步器打拍处理。对于DDR3这类高速接口,必须编写XDC约束文件,声明输入输出延迟与时钟分组,否则实现后的时序收敛无法保证。状态机:接口逻辑本质是状态机。UART接收是“检测起始位-移位采样-校验停止位”的状态流转;SPI从机是“等待片选-按位收发-片选释放”的过程。状态机设计必须考虑所有异常分支,如中途断帧、片选抖动等。详细步骤第一步:UART接口设计UART协议帧结构:1位起始位(低电平),8位数据位(LSB先行),1位停止位(高电平),无校验。波特率9600bps,系统时钟50MHz,分频系数为50_000_000/9600=5208。接收端采样策略:在每位数据的中间时刻采样,以避开数据跳变沿。实现方式为计数器计数到分频系数的一半时采样一次,完整计数一个周期时确认一位数据。第二步:SPI从机设计SPI模式0(CPOL=0,CPHA=0):空闲时SCK为低电平,数据在SCK上升沿采样,下降沿输出。从机需在片选信号CS拉低后,每个SCK上升沿锁存MOSI上的数据,同时在下降沿将内部数据移位到MISO。关键点:SPI从机的时钟来自外部主机,属于完全异步时钟域。所有对内部系统时钟域的信号(如接收完成标志)必须经过同步器处理。第三步:DDR3读写控制DDR3控制器使用Xilinx MIG IP核生成用户接口,用户侧时钟为UI_CLK(如200MHz),数据位宽为32位(或64位)。读写流程为:发起写命令(app_cmd=0)与写地址(app_addr),写入数据(app_wdf_data),等待写响应;发起读命令(app_cmd=1),等待读数据有效(app_rd_data_valid)。必须处理MIG IP的app_rdy与app_wdf_rdy握手信号,否则命令或数据会被丢弃。完整可运行代码以下代码分为三个模块:UART接收模块、SPI从机模块、DDR3读写测试模块。为控制篇幅,DDR3部分展示用户接口读写逻辑,MIG IP核需在Vivado中单独生成。模块一:UART接收器module uart_rx #( parameter CLK_FREQ = 50_000_000, parameter BAUD_RATE = 9600 )( input wire clk, input wire rst_n, input wire rx, output reg [7:0] rx_data, output reg rx_done ); localparam BAUD_CNT = CLK_FREQ / BAUD_RATE; localparam BAUD_CNT_HALF = BAUD_CNT / 2; reg [3:0] bit_index; // 当前接收位索引,0为起始位,1-8为数据位,9为停止位 reg [15:0] baud_counter; // 波特率分频计数器 reg rx_sync1, rx_sync2; // 两级同步器,消除亚稳态 reg rx_reg; // 同步后的rx信号 reg rx_active; // 接收进行中标志 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_sync1 =
返回列表