4. SPI接口IP设计:SPI四种模式、主从机架构、移位寄存器设计、片选逻辑、多从机仲裁
SPI,全称Serial Peripheral Interface,串行外设接口。这玩意儿在嵌入式世界里,可以说是最常用的接口之一了。我做了这么多年设计,几乎每个项目里都能见到它的身影。它简单、高效,但真要自己动手写一个SPI的IP核,里面门道其实不少。
今天我们就来聊聊SPI接口IP设计的核心要点。我会把我在项目中踩过的坑、积累的经验,都揉碎了讲给你听。
4.1 SPI的四种模式:时钟极性(CPOL)和时钟相位(CPHA)
SPI通信,说白了就是主设备发时钟,主从设备在时钟边沿交换数据。但这里有个关键问题:时钟空闲时是高电平还是低电平?数据是在时钟上升沿采样还是下降沿采样?
这就引出了SPI的四种模式。它们由两个参数决定:CPOL(时钟极性)和CPHA(时钟相位)。
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 |
|---|---|---|---|---|
| 模式0 | 0 | 0 | 低电平 | 上升沿 |
| 模式1 | 0 | 1 | 低电平 | 下降沿 |
| 模式2 | 1 | 0 | 高电平 | 下降沿 |
| 模式3 | 1 | 1 | 高电平 | 上升沿 |
我个人习惯把CPOL理解为“空闲时时钟的状态”。CPOL=0,空闲时时钟是低;CPOL=1,空闲时时钟是高。CPHA则决定了数据是在第一个时钟边沿采样,还是在第二个时钟边沿采样。
核心要点:主从设备的SPI模式必须一致,否则通信会直接失败。我在项目中遇到过好几次,明明连线没问题,就是不通,最后发现是模式没对上。
举个例子,模式0是最常用的。CPOL=0,CPHA=0,空闲时时钟低,数据在上升沿采样。很多ADC、DAC芯片都默认用这个模式。
4.2 主从机架构:谁发时钟谁就是老大
SPI总线是典型的主从架构。主设备(Master)负责产生时钟信号,并控制片选信号。从设备(Slave)只能被动响应。
你想想看,如果两个设备都想当主设备,同时发时钟,那总线就乱套了。所以,一个SPI总线上只能有一个主设备,但可以有多个从设备。
主设备内部通常包含一个波特率发生器,用来产生SCK时钟。从设备则不需要这个,它直接接收主设备发来的时钟。
设计小技巧:主设备的波特率发生器,我建议用计数器分频来实现。这样频率调整非常灵活。我曾经在一个项目中,需要SPI时钟频率精确到1Hz,就是用计数器加比较器搞定的。
4.3 移位寄存器设计:数据交换的核心
SPI的数据交换,本质上是主从设备各自的一个移位寄存器在“转圈圈”。主设备每发出一个时钟脉冲,两个移位寄存器就同时左移或右移一位。
以8位数据为例,主设备的移位寄存器里存着要发送的数据,从设备的移位寄存器里存着要返回的数据。8个时钟脉冲后,主设备的数据就移到了从设备,从设备的数据也移到了主设备。这就是所谓的“全双工”。
设计移位寄存器时,要注意以下几点:
- 移位方向:通常是MSB(最高位)先出,但有些芯片是LSB先出。设计时最好做成可配置的。
- 数据宽度:不一定是8位。很多SPI设备支持16位、24位甚至32位。我建议把数据宽度做成参数化,方便复用。
- 边沿对齐:发送数据在时钟的哪个边沿变化,采样在哪个边沿,要严格遵循SPI模式的定义。
// 一个简单的8位SPI移位寄存器Verilog示例
module spi_shift_reg (
input wire clk,
input wire rst_n,
input wire shift_en, // 移位使能
input wire sdi, // 串行数据输入
output wire sdo, // 串行数据输出
input wire [7:0] parallel_in, // 并行加载数据
output wire [7:0] parallel_out // 并行输出数据
);
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 8'h00;
else if (shift_en)
shift_reg <= {shift_reg[6:0], sdi}; // 左移,低位补入sdi
end
assign sdo = shift_reg[7]; // MSB先出
assign parallel_out = shift_reg;
endmodule
嗯,这里要注意,上面的代码只是一个最简化的模型。实际项目中,你还需要考虑加载并行数据、字节序转换等逻辑。
4.4 片选逻辑:谁被选中谁说话
片选信号(CS,Chip Select),也叫从机选择信号(SS,Slave Select)。它的作用就是告诉从设备:“嘿,我要跟你说话,准备好!”
片选逻辑的设计要点:
- 低电平有效:绝大多数SPI设备的片选都是低电平有效。CS拉低,从设备被选中;CS拉高,从设备释放总线。
- 片选建立时间:CS拉低后,不能立即发时钟。需要等一段时间,让从设备准备好。这个时间在芯片的数据手册里会有,通常是几十纳秒。
- 片选保持时间:最后一个时钟结束后,CS不能立即拉高。也需要等一段时间,确保数据被正确锁存。
- 帧间隔:连续传输多帧数据时,CS可以在帧间保持低电平,也可以拉高再拉低。这取决于从设备的协议要求。
避坑指南:我曾经在一个项目中,因为片选信号的建立时间没给够,导致从设备偶尔会误判第一个时钟边沿,数据总是错位。后来加了几个时钟周期的延时,问题就解决了。所以,时序裕量一定要留足。
4.5 多从机仲裁:谁先谁后?
一个SPI主设备带多个从设备,这是很常见的场景。多从机仲裁,说白了就是决定“先跟谁说话,后跟谁说话”。
SPI本身没有总线仲裁机制。它靠的是片选信号来区分从设备。主设备有几个从设备,就需要几个片选信号。同一时刻,只能有一个片选信号被拉低。
多从机连接方式有两种:
- 独立片选:每个从设备有自己的片选引脚。这是最常用的方式。主设备通过拉低某个从设备的片选,来选中它。
- 菊花链:所有从设备共用片选和时钟,数据从一个从设备串到下一个。这种方式节省引脚,但延迟大,且任何一个从设备出问题,整条链都断掉。我个人不太推荐,除非引脚实在不够用。
在IP设计层面,多从机仲裁的逻辑其实很简单:
- 主设备内部有一个从机地址译码器,根据软件配置的地址,产生对应的片选信号。
- 同一时刻,只能有一个片选信号有效。
- 当主设备要切换从设备时,必须先拉高当前从设备的片选,再拉低目标从设备的片选。中间最好留一个“死区时间”,防止两个从设备同时驱动MISO线。
重要提醒:MISO(主输入从输出)线是所有从设备共享的。当某个从设备未被选中时,它的MISO引脚必须处于高阻态(三态),否则多个从设备同时驱动MISO,会造成信号冲突,甚至烧坏芯片。这一点在设计从设备IP时尤其要注意。
好了,SPI接口IP设计的核心内容就这些。从四种模式到主从架构,从移位寄存器到片选逻辑,再到多从机仲裁,每一步都有它的设计考量。希望我的这些经验能帮你少走弯路。