当前位置:首页 > EDA > 电子设计自动化
[导读]SPI是嵌入式系统中应用最广泛的串行同步接口之一,以其全双工、高速率、硬件连线少的优势,在ADC、DAC、MEMS传感器、Flash存储器等场景中占据统治地位。FPGA的硬件并行特性天然适合SPI时序的精确控制——你可以自定义时钟极性/相位、数据位宽和传输速率,不受MCU外设限制。本文给出可直接综合的SPI主模式和从模式Verilog代码,覆盖CPOL=0、CPHA=0的经典模式。


SPI是嵌入式系统中应用最广泛的串行同步接口之一,以其全双工、高速率、硬件连线少的优势,在ADC、DAC、MEMS传感器、Flash存储器等场景中占据统治地位。FPGA的硬件并行特性天然适合SPI时序的精确控制——你可以自定义时钟极性/相位、数据位宽和传输速率,不受MCU外设限制。本文给出可直接综合的SPI主模式和从模式Verilog代码,覆盖CPOL=0、CPHA=0的经典模式。

SPI协议回顾

SPI四线制:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、SS(片选,低有效)。全双工传输:每个时钟周期主从各移出一位数据。CPOL=0表示空闲时SCLK为低电平,CPHA=0表示在第一个时钟沿(上升沿)采样数据。

SPI主模式设计

主模式负责产生SCLK和SS,并按位收发数据。核心是一个状态机:空闲→发送/接收→完成。

module spi_master #(parameter DATA_WIDTH = 8, CLK_DIV = 100) (

   input clk, rst_n,

   input start,                     // 启动传输

   input [DATA_WIDTH-1:0] data_in,  // 待发送数据

   output reg [DATA_WIDTH-1:0] data_out, // 接收数据

   output reg done,                 // 传输完成标志

   output reg sclk, ss, mosi,

   input miso

);

   localparam IDLE = 0, TRANSFER = 1, FINISH = 2;

   reg [1:0] state;

   reg [7:0] clk_cnt;

   reg [3:0] bit_cnt;

   reg [DATA_WIDTH-1:0] shift_reg;


   always @(posedge clk or negedge rst_n) begin

       if (!rst_n) begin

           state <= IDLE; sclk <= 0; ss <= 1; mosi <= 0;

           done <= 0; clk_cnt <= 0; bit_cnt <= 0;

       end else case (state)

           IDLE: begin

               ss <= 1; done <= 0;

               if (start) begin

                   ss <= 0;

                   shift_reg <= data_in;

                   clk_cnt <= 0; bit_cnt <= 0;

                   state <= TRANSFER;

               end

           end

           TRANSFER: begin

               if (clk_cnt == CLK_DIV/2 - 1) begin // 半个周期

                   sclk <= ~sclk;

                   if (sclk) begin // 下降沿,输出数据

                       mosi <= shift_reg[DATA_WIDTH-1];

                       shift_reg <= {shift_reg[DATA_WIDTH-2:0], 1'b0};

                   end else begin // 上升沿,采样MISO

                       shift_reg[0] <= miso;

                       if (bit_cnt == DATA_WIDTH-1) state <= FINISH;

                       else bit_cnt <= bit_cnt + 1;

                   end

                   clk_cnt <= 0;

               end else clk_cnt <= clk_cnt + 1;

           end

           FINISH: begin

               ss <= 1; sclk <= 0;

               data_out <= shift_reg;

               done <= 1;

               state <= IDLE;

           end

       endcase

   end

endmodule

CLK_DIV参数控制SCLK频率:系统时钟÷(2×CLK_DIV)。例如50MHz时钟,CLK_DIV=100时SCLK为250kHz。

SPI从模式设计

从模式被动接收SCLK和SS,在时钟沿同步收发。不需要分频逻辑,但必须确保SCLK不超过FPGA的处理能力。

module spi_slave #(parameter DATA_WIDTH = 8) (

   input clk, rst_n,

   input sclk, ss, mosi,

   output reg miso,

   output reg [DATA_WIDTH-1:0] data_out,

   output reg data_valid

);

   reg [DATA_WIDTH-1:0] shift_reg;

   reg [3:0] bit_cnt;

   reg sclk_d1, sclk_d2; // 同步与边沿检测

   wire pos_edge = sclk_d1 & ~sclk_d2; // 上升沿


   always @(posedge clk or negedge rst_n) begin

       if (!rst_n) begin

           sclk_d1 <= 0; sclk_d2 <= 0;

           shift_reg <= 0; bit_cnt <= 0;

           data_out <= 0; data_valid <= 0;

           miso <= 0;

       end else begin

           {sclk_d2, sclk_d1} <= {sclk_d1, sclk}; // 两级同步

           if (!ss) begin

               if (pos_edge) begin

                   shift_reg <= {shift_reg[DATA_WIDTH-2:0], mosi};

                   if (bit_cnt == DATA_WIDTH-1) begin

                       data_out <= {shift_reg[DATA_WIDTH-2:0], mosi};

                       data_valid <= 1;

                       bit_cnt <= 0;

                   end else bit_cnt <= bit_cnt + 1;

               end

               // 在SCLK下降沿更新MISO(CPHA=0时)

               // 此处略,可根据需要添加

           end else begin

               bit_cnt <= 0;

               data_valid <= 0;

           end

       end

   end

endmodule

注意:从模式的SCLK必须用两级触发器同步到FPGA系统时钟域,避免亚稳态。边沿检测在同步后的信号上进行。

仿真与验证

编写testbench,将主从模块相连,验证数据传输的正确性。关键检查点:SS拉低后主模块开始产生SCLK;8个时钟周期后done拉高,data_out等于发送的data_in。

写在最后

SPI主从模块是FPGA接口设计的基本功。掌握这两个模板后,你可以轻松适配各类SPI传感器:调整DATA_WIDTH适配12位ADC,修改CLK_DIV匹配器件最高速率,增加CPOL/CPHA选择逻辑支持不同模式。当你的FPGA需要以10MHz以上的速率与高速ADC交换数据时,自己写的SPI控制器比调用IP核更可控、更节省资源。从仿真通过到板级联调,SPI协议的FPGA实现是通往复杂接口设计的坚实一步。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭