1. 项目概述与核心特性
这个SPI控制器模块是我在最近一个FPGA项目中开发的,主要用于与各种SPI外设通信。当时项目需要同时管理多个SPI接口的传感器,市面上现成的IP核要么功能太简单,要么过于复杂,于是决定自己开发一个兼顾灵活性和易用性的解决方案。
模块的核心设计理念是"配置即用"——通过AXI4-Lite接口提供完整的配置和状态监控能力。实测在Xilinx KC705开发板上可以稳定运行在50MHz时钟频率,这个性能对于大多数SPI设备应用已经绰绰有余。
1.1 架构设计亮点
模块采用分层设计:
- 顶层是AXI4-Lite接口封装层
- 中间是配置寄存器和状态机控制层
- 底层是SPI协议引擎
这种设计使得模块既保持了SPI通信的实时性要求,又通过标准总线接口简化了系统集成。特别值得一提的是,我们实现了单控制器管理32个SPI总线的能力,这在多传感器系统中特别实用。
2. SPI协议实现细节
2.1 四种工作模式配置
SPI的四种工作模式由CPOL(时钟极性)和CPHA(时钟相位)组合决定。在Verilog实现中,我们使用两个寄存器位来控制:
verilog复制reg CPOL; // 时钟极性:0=空闲时低电平,1=空闲时高电平
reg CPHA; // 时钟相位:0=第一个边沿采样,1=第二个边沿采样
实际使用时需要注意:
配置模式时务必参考外设datasheet的要求,错误的CPOL/CPHA设置会导致通信完全失败。我在调试ADS131M08 ADC时就遇到过这个问题。
2.2 数据传输格式实现
模块支持MSB和LSB两种传输格式,通过配置寄存器的第2位控制:
verilog复制always @(posedge clk) begin
if(config_en)
MSB_first <= config_reg[2]; // 1=MSB, 0=LSB
end
在数据移位处理部分:
verilog复制// MSB优先传输
if(MSB_first) begin
tx_shift <= {tx_data[30:0], 1'b0};
rx_data <= {rx_data[30:0], SDI};
end
// LSB优先传输
else begin
tx_shift <= {1'b0, tx_data[31:1]};
rx_data <= {SDI, rx_data[31:1]};
end
3. 总线接口与工作模式
3.1 3线与4线模式选择
模块支持两种物理接口配置:
- 3线模式(SCLK, SDIO, CSn):半双工,节省引脚
- 4线模式(SCLK, SDI, SDO, CSn):全双工,性能更好
实现关键点:
verilog复制// 总线类型选择逻辑
assign SDIO = (bus_type == 3'WIRE) ?
(tx_en ? tx_data[31] : 1'bz) : 1'bz;
assign SDO = (bus_type == 4'WIRE) ? tx_data[31] : 1'bz;
assign SDI = (bus_type == 4'WIRE) ? SDI_pin : SDIO;
实际布线时要注意:3线模式下SDIO信号需要外部上拉电阻,否则空闲时可能产生浮空问题。
3.2 单次与连续传输模式
单次传输模式流程:
- 写入指令寄存器(32bit)
- 写入数据寄存器(64bit)
- 触发START位
- 等待DONE中断或轮询状态寄存器
连续传输模式配置:
verilog复制// 连续模式控制逻辑
always @(posedge clk) begin
if(continuous_mode) begin
if(!fifo_empty && ready) begin
tx_data <= fifo_out;
start <= 1'b1;
end
end
end
4. AXI4-Lite接口实现
4.1 寄存器映射设计
我们设计了精简的寄存器集:
| 地址偏移 | 寄存器名称 | 功能描述 |
|---|---|---|
| 0x00 | CTRL_REG | 控制寄存器 |
| 0x04 | STAT_REG | 状态寄存器 |
| 0x08 | TX_DATA | 发送数据 |
| 0x0C | RX_DATA | 接收数据 |
控制寄存器各位定义:
4.2 接口时序优化
为提高AXI接口效率,我们采用寄存器缓冲设计:
verilog复制// AXI写数据处理
always @(posedge clk) begin
if(awvalid && wvalid) begin
case(awaddr[7:0])
8'h00: ctrl_reg <= wdata;
8'h08: tx_buf <= wdata;
endcase
end
end
调试发现:AXI时钟域到SPI时钟域的信号需要双重同步,否则可能产生亚稳态问题。
5. 实测性能与优化建议
在KC705开发板上的测试结果:
- 最大稳定SCLK频率:50MHz
- 32bit数据传输延迟:约700ns
- 多从机切换时间:约100ns
性能优化技巧:
- 对时序关键路径添加寄存器流水
- 使用IOBUF原语处理双向信号
- 对跨时钟域信号进行适当约束
verilog复制// 时序优化示例:插入流水寄存器
always @(posedge clk) begin
tx_data_ff <= tx_data;
tx_valid_ff <= tx_valid;
end
6. 常见问题排查
6.1 通信失败排查步骤
- 确认电源和复位正常
- 检查SCLK是否有输出
- 验证CPOL/CPHA设置
- 检查CSn信号是否有效
- 用逻辑分析仪抓取波形
6.2 典型错误与解决
问题:数据错位
原因:MSB/LSB设置与外设不匹配
解决:检查配置寄存器bit2
问题:连续模式数据丢失
原因:AXI接口速率跟不上SPI时钟
解决:增加FIFO深度或降低SCLK频率
这个SPI控制器模块已经在多个项目中验证过稳定性,特别适合需要灵活配置SPI参数的场合。对于想自己实现SPI控制器的开发者,建议先从单从机、单模式开始,逐步扩展功能。