手把手用Verilog实现SPI主从通信:基于Xilinx Artix-7的FPGA实战教程

张开发
2026/4/20 2:56:56 15 分钟阅读

分享文章

手把手用Verilog实现SPI主从通信:基于Xilinx Artix-7的FPGA实战教程
手把手用Verilog实现SPI主从通信基于Xilinx Artix-7的FPGA实战教程在嵌入式系统开发中SPISerial Peripheral Interface因其高速、全双工和硬件简单的特性成为连接Flash存储器、传感器等外设的首选协议。本文将带你从零开始用Verilog在Xilinx Artix-7 FPGA上实现SPI主设备控制W25Q128 Flash和从设备连接MPU6050加速度计的完整流程。不同于使用现成IP核我们将深入时序细节通过仿真和逻辑分析仪验证每个信号跳变真正掌握同步串行通信的核心原理。1. SPI协议核心与硬件准备SPI协议通过四根信号线实现全双工通信SCK主设备提供的同步时钟MOSI主设备输出从设备输入MISO从设备输出主设备输入SS从设备片选低电平有效以W25Q128 Flash为例其关键时序参数如下参数典型值说明SCK频率50MHz最大支持时钟速率建立时间(tSU)3ns数据在SCK上升沿前稳定时间保持时间(tH)2ns数据在SCK上升沿后保持时间硬件连接需注意// Artix-7引脚分配示例 set_property PACKAGE_PIN F12 [get_ports {spi_clk}] // SCK set_property PACKAGE_PIN D10 [get_ports {spi_mosi}] // MOSI set_property PACKAGE_PIN E11 [get_ports {spi_miso}] // MISO set_property PACKAGE_PIN G13 [get_ports {spi_cs_n}] // SS提示实际布线时需确保SCK与数据线等长避免时序偏移超过1/4时钟周期2. SPI主设备Verilog实现主设备状态机设计采用三段式结构确保时序清晰2.1 时钟生成与相位控制SPI模式0CPOL0, CPHA0的时钟生成逻辑always (posedge sys_clk or negedge rst_n) begin if(!rst_n) begin spi_clk 1b0; clk_cnt 0; end else if(trans_en) begin clk_cnt (clk_cnt CLK_DIV-1) ? 0 : clk_cnt 1; spi_clk (clk_cnt CLK_DIV/2) ? 1b0 : 1b1; end end2.2 数据移位与采样并行转串行发送逻辑always (posedge sys_clk or negedge rst_n) begin if(!rst_n) begin shift_reg 8h00; bit_cnt 0; end else if(trans_start) begin shift_reg tx_data; // 加载并行数据 bit_cnt 7; // 8位计数器 end else if(clk_cnt CLK_DIV-1) begin shift_reg {shift_reg[6:0], 1b0}; // 左移 bit_cnt bit_cnt - 1; end end assign spi_mosi shift_reg[7]; // 输出最高位2.3 Flash操作指令实现W25Q128的页编程PP指令时序拉低SS发送0x02指令码发送24位地址A23-A0发送最多256字节数据拉高SS结束传输对应Verilog实现case(state) IDLE: if(cmd_valid) begin tx_data 8h02; // PP指令 state ADDR_H; end ADDR_H: begin tx_data addr[23:16]; state ADDR_M; end // ... 其他状态转移 endcase3. SPI从设备适配MPU6050MPU6050作为I2C/SPI双模器件需配置为SPI模式// 初始化序列 initial begin spi_write(0x6B, 8h00); // 退出睡眠模式 spi_write(0x6A, 8h10); // 禁用I2C启用SPI end task spi_write; input [7:0] reg_addr; input [7:0] reg_data; begin ss_n 0; spi_xfer(reg_addr); spi_xfer(reg_data); ss_n 1; end endtask加速度计数据读取的时序要点寄存器地址最高位置1表示读操作连续读取时自动递增地址数据返回有1字节延迟4. 验证与调试技巧4.1 Modelsim功能仿真建立测试平台验证读写时序initial begin // 发送Flash读ID指令(0x9F) spi_master_tb(8h9F); #100; // 模拟Flash返回ID: 0xEF 0x40 0x18 force uut.spi_miso 1b1; // 第一位MSB1 #200; release uut.spi_miso; end4.2 逻辑分析仪抓包使用Saleae Logic解析SPI信号设置解码器为SPI模式配置时钟极性/相位匹配硬件触发条件设为SS下降沿导出数据为CSV进行后期分析典型问题排查流程无响应检查SS信号是否有效数据错位确认CPOL/CPHA设置CRC错误降低SCK频率测试5. 性能优化进阶5.1 时钟域交叉处理当SPI时钟与系统时钟不同源时// 双触发器同步器 always (posedge sys_clk) begin spi_miso_sync {spi_miso_sync[0], spi_miso}; end5.2 DMA传输优化大数据量传输时采用DMA控制器配置源/目的地址和传输长度启动DMA后自动搬运数据通过中断通知完成dma_ctrl u_dma( .clk (sys_clk), .mem_addr (32h4000_0000), .spi_addr (24h00_1234), .length (1024), .start (dma_start), .done (dma_done) );在完成Flash和加速度计的联合调试后发现MPU6050对SCK噪声敏感通过以下改进稳定通信在SCK线上串联33Ω电阻缩短FPGA与传感器间走线至5cm在电源引脚添加0.1μF去耦电容

更多文章