FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

Verilog实战:2026年用状态机实现SPI协议的正确打开方式

FPGA小白FPGA小白
技术分享
17小时前
0
0
5

Quick Start

  • 在Vivado 2024.2中新建工程,器件选择XC7A35T-2CSG324C(Arty A7-35T)。
  • 创建顶层文件spi_master.sv,定义端口:clkrst_nstartdata_in[7:0]sclkmosimisocs_nbusydata_out[7:0]done
  • 编写状态机代码(Moore型,5个状态:IDLE、LOAD、SHIFT、CAPTURE、DONE),实现SPI模式0(CPOL=0,CPHA=0)。
  • 编写testbench,驱动start脉冲,提供miso数据(如8'hA5),运行仿真500us。
  • 观察波形:cs_n拉低后sclk产生8个周期,mosi逐位输出data_inmisosclk下降沿被采样,done在传输结束后拉高一个周期。
  • 综合实现后检查资源:LUT ≤ 80,FF ≤ 60,Fmax ≥ 200MHz(典型值)。
  • 上板验证:连接SPI从设备(如ADC或DAC),通过ILA抓取sclkmosics_n,确认时序符合SPI模式0。

前置条件与环境

项目推荐值说明替代方案
器件/板卡Xilinx Artix-7 XC7A35T通用低成本FPGA,资源充足XC7A100T、Cyclone IV E
EDA版本Vivado 2024.2支持SystemVerilog-2017Vivado 2023.x、Quartus Prime 23.x
仿真器Vivado Simulator (xsim)内置于Vivado,无需额外安装ModelSim SE-64 2023.4、Verilator 5.x
时钟/复位100MHz 外部时钟,异步低电平复位板载晶振提供,复位按键50MHz、125MHz;同步复位(需修改状态机
接口依赖PMOD或Arduino Shield连接器用于连接SPI从设备自定义FMC子卡
约束文件XDC文件:时钟周期10ns,输入/输出延迟2ns保证时序收敛SDC格式(Quartus)

目标与验收标准

  • 功能点:支持SPI模式0(CPOL=0,CPHA=0),8位数据全双工传输,可连续发送。
  • 性能指标:SCLK频率可配置(默认12.5MHz,即100MHz/8分频);传输8位耗时≤0.8µs(含状态切换开销)。
  • 资源占用:LUT ≤ 80,FF ≤ 60(XC7A35T上实现)。
  • 时序收敛:综合后WNS ≥ 0.2ns,Fmax ≥ 200MHz。
  • 验收波形:仿真波形中cs_n在传输期间保持低电平;sclkcs_n拉低半个周期后开始翻转;mosisclk上升沿变化;misosclk下降沿被捕获;done在最后一位捕获后拉高一个时钟周期。

实施步骤

工程结构与顶层模块

创建以下文件结构:

spi_master/
├── rtl/
│   ├── spi_master.sv      // 顶层状态机
│   └── clk_divider.sv     // 时钟分频器(可选)
├── sim/
│   └── tb_spi_master.sv   // 测试平台
├── constr/
│   └── top.xdc            // 时序约束
└── vivado/                // Vivado工程目录

逐行说明

  • 第1行:顶层目录spi_master
  • 第2行:RTL源码文件夹。
  • 第3行:主状态机模块,实现SPI协议
  • 第4行:时钟分频模块,将100MHz分频为SCLK(12.5MHz)。
  • 第5行:仿真文件夹。
  • 第6行:测试平台文件。
  • 第7行:约束文件夹。
  • 第8行:时序约束文件。
  • 第9行:Vivado工程目录。

关键模块:状态机实现(spi_master.sv)

module spi_master #(
    parameter CLK_DIV = 8  // 分频系数:SCLK = clk / CLK_DIV
)(
    input  logic       clk,
    input  logic       rst_n,
    input  logic       start,
    input  logic [7:0] data_in,
    output logic       sclk,
    output logic       mosi,
    input  logic       miso,
    output logic       cs_n,
    output logic       busy,
    output logic [7:0] data_out,
    output logic       done
);

逐行说明

  • 第1行:模块定义,带参数CLK_DIV,默认8分频。
  • 第2行:参数定义结束。
  • 第3行:系统时钟输入。
  • 第4行:异步低电平复位。
  • 第5行:启动信号,高电平有效,至少保持一个时钟周期。
  • 第6行:待发送的8位并行数据。
  • 第7行:SPI串行时钟输出。
  • 第8行:主出从入数据线。
  • 第9行:主入从出数据线。
  • 第10行:片选信号,低电平有效。
  • 第11行:忙标志,传输期间为高。
  • 第12行:接收到的8位并行数据输出。
  • 第13行:传输完成标志,高电平持续一个时钟周期。
// 状态定义
    typedef enum logic [2:0] {
        IDLE   = 3'b000,
        LOAD   = 3'b001,
        SHIFT  = 3'b010,
        CAPTURE= 3'b011,
        DONE   = 3'b100
    } state_t;
    state_t state, next_state;

逐行说明

  • 第1行:注释,状态定义。
  • 第2行:枚举类型定义,3位宽。
  • 第3行:IDLE状态,等待start
  • 第4行:LOAD状态,加载数据到移位寄存器。
  • 第5行:SHIFT状态,在SCLK上升沿输出mosi
  • 第6行:CAPTURE状态,在SCLK下降沿采样miso
  • 第7行:DONE状态,置位完成信号。
  • 第8行:枚举定义结束。
  • 第9行:声明当前状态和下一状态变量。
// 内部寄存器
    logic [7:0] shift_reg;      // 移位寄存器(发送+接收)
    logic [3:0] bit_cnt;        // 位计数器(0~7)
    logic [7:0] clk_cnt;        // 分频计数器
    logic       sclk_en;        // SCLK使能信号

逐行说明

  • 第1行:注释,内部寄存器声明。
  • 第2行:8位移位寄存器,用于串行发送和接收。
  • 第3行:4位计数器,记录已传输位数(0~7)。
  • 第4行:8位分频计数器,用于生成SCLK。
  • 第5行:SCLK使能信号,为1时允许SCLK翻转。
// 状态转移(时序逻辑)
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            state <= IDLE;
        else
            state <= next_state;
    end

逐行说明

  • 第1行:注释,状态转移时序逻辑。
  • 第2行:时钟上升沿或复位下降沿触发。
  • 第3行:复位有效时进入IDLE状态。
  • 第4行:否则更新为下一状态。
// 下一状态组合逻辑
    always_comb begin
        next_state = state;  // 默认保持
        case (state)
            IDLE: begin
                if (start)
                    next_state = LOAD;
            end
            LOAD: begin
                next_state = SHIFT;
            end
            SHIFT: begin
                if (bit_cnt == 4'd7 && clk_cnt == CLK_DIV-1)
                    next_state = DONE;
                else if (clk_cnt == CLK_DIV-1)
                    next_state = CAPTURE;
            end
            CAPTURE: begin
                if (clk_cnt == CLK_DIV-1)
                    next_state = SHIFT;
            end
            DONE: begin
                next_state = IDLE;
            end
        endcase
    end

逐行说明

  • 第1行:注释,下一状态组合逻辑块。
  • 第2行:默认保持当前状态。
  • 第3行:状态选择。
  • 第4行:IDLE状态:检测start信号。
  • 第5行:若start为高,跳转到LOAD。
  • 第7行:LOAD状态:无条件跳转到SHIFT。
  • 第10行:SHIFT状态:若已传输8位且分频计数器满,跳转到DONE。
  • 第11行:否则若分频计数器满,跳转到CAPTURE。
  • 第14行:CAPTURE状态:若分频计数器满,跳转到SHIFT。
  • 第17行:DONE状态:无条件回到IDLE。
// 分频计数器与SCLK生成
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            clk_cnt <= 0;
            sclk    <= 0;
        end else if (state == IDLE || state == DONE) begin
            clk_cnt <= 0;
            sclk    <= 0;  // IDLE时SCLK为低
        end else if (sclk_en) begin
            if (clk_cnt == CLK_DIV-1) begin
                clk_cnt <= 0;
                sclk    <= ~sclk;
            end else begin
                clk_cnt <= clk_cnt + 1;
            end
        end
    end

逐行说明

  • 第1行:注释,分频计数器与SCLK生成。
  • 第2行:时序逻辑,时钟上升沿或复位下降沿触发。
  • 第3行:复位时清空计数器,SCLK置0。
  • 第5行:IDLE或DONE状态时,计数器清零,SCLK保持低电平。
  • 第7行:SCLK使能时,进行分频。
  • 第8行:计数器满(CLK_DIV-1)时,清零并翻转SCLK。
  • 第11行:否则计数器递增。
// SCLK使能逻辑(状态机控制)
    always_comb begin
        sclk_en = (state == SHIFT) || (state == CAPTURE);
    end

逐行说明

  • 第1行:注释,SCLK使能逻辑。
  • 第2行:组合逻辑,SHIFT或CAPTURE状态时使能SCLK。
// 移位寄存器与位计数
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            shift_reg <= 0;
            bit_cnt   <= 0;
            data_out  <= 0;
        end else begin
            case (state)
                LOAD: begin
                    shift_reg <= data_in;  // 加载发送数据
                    bit_cnt   <= 0;
                end
                SHIFT: begin
                    if (clk_cnt == 0) begin  // SCLK上升沿前
                        mosi <= shift_reg[7];  // 输出最高位
                        shift_reg <= {shift_reg[6:0], miso}; // 左移并捕获miso
                    end
                end
                CAPTURE: begin
                    if (clk_cnt == CLK_DIV/2 - 1) begin  // SCLK下降沿后采样
                        bit_cnt <= bit_cnt + 1;
                    end
                end
                DONE: begin
                    data_out <= shift_reg;  // 输出接收数据
                end
            endcase
        end
    end

逐行说明

  • 第1行:注释,移位寄存器与位计数。
  • 第2行:时序逻辑。
  • 第3行:复位时清零所有寄存器。
  • 第7行:LOAD状态:加载data_in到移位寄存器,位计数清零。
  • 第11行:SHIFT状态:在clk_cnt==0时(SCLK上升沿前)输出mosi并移位。
  • 第12行:mosi输出移位寄存器最高位。
  • 第13行:左移一位,并将miso移入最低位。
  • 第16行:CAPTURE状态:在clk_cnt == CLK_DIV/2 - 1时(SCLK下降沿后)递增位计数。
  • 第20行:DONE状态:将移位寄存器内容输出到data_out
// 片选与忙标志
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cs_n <= 1;
            busy <= 0;
            done <= 0;
        end else begin
            case (state)
                IDLE: begin
                    cs_n <= 1;
                    busy <= 0;
                    done <= 0;
                end
                LOAD: begin
                    cs_n <= 0;  // 拉低片选
                    busy <= 1;
                end
                DONE: begin
                    cs_n <= 1;  // 拉高片选
                    busy <= 0;
                    done <= 1;  // 完成脉冲
                end
            endcase
        end
    end

逐行说明

  • 第1行:注释,片选与忙标志。
  • 第2行:时序逻辑。
  • 第3行:复位时片选拉高,忙标志清零,完成信号清零。
  • 第8行:IDLE状态:片选拉高,忙标志清零。
  • 第13行:LOAD状态:片选拉低(开始传输),忙标志置位。
  • 第17行:DONE状态:片选拉高(结束传输),忙标志清零,完成信号置位一个周期。
endmodule

逐行说明 <!--

标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/41855.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
39521.30W7.26W34.40W
分享:
成电国芯FPGA赛事课即将上线
2026年Q2 FPGA行业深度观察:AI数据中心、国产边缘部署与开源EDA生态加速演进
2026年Q2 FPGA行业深度观察:AI数据中心、国产边缘部署与开源EDA生态加速演进上一篇
FPGA时序约束:跨时钟域同步器设计实现指南下一篇
FPGA时序约束:跨时钟域同步器设计实现指南
相关文章
总数:1.05K
FPGA实现CNN加速器:Winograd算法优化与资源分配策略

FPGA实现CNN加速器:Winograd算法优化与资源分配策略

本文档旨在指导读者在FPGA上高效实现基于Winograd算法的卷积神经…
技术分享
23天前
0
0
48
0
FPGA开发中Vivado与ModelSim联合仿真的高效配置方法

FPGA开发中Vivado与ModelSim联合仿真的高效配置方法

在FPGA开发流程中,功能仿真是验证设计逻辑正确性的关键环节。Vivad…
技术分享
18天前
0
0
88
0
FPGA竞赛高分实践:系统架构设计与调试策略指南

FPGA竞赛高分实践:系统架构设计与调试策略指南

QuickStart:从零到跑通竞赛基础框架以下步骤帮助你在30分钟内…
技术分享
11天前
0
0
27
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容