四线同步协议 + CPOL/CPHA模式
🏆 成就:SPI骑士 ✅ Verilator验证
SCLK(时钟)+MOSI(主出从入)+MISO(主入从出)+CS_N(片选)。Mode 0最常用:SCLK空闲低,上升沿采样,MSB first。
localparam SPI_DIV=25; // 50MHz→1MHz SPI
always @(posedge clk) case(state)
0: if(spi_start) begin cs_n<=0; tx_shift<=tx_data; state<=1; end
1: if(clk_div==SPI_DIV-1) begin
clk_div<=0; sclk_reg<=~sclk_reg; sclk<=~sclk_reg;
if(sclk_reg) begin mosi<=tx_shift[7]; tx_shift<=tx_shift<<1; end
else begin // 上升沿采样MISO
rx_shift<={rx_shift[6:0],miso};
if(bit_cnt==7) state<=2; else bit_cnt<=bit_cnt+1;
end
end else clk_div<=clk_div+1;
2: begin cs_n<=1; done_pulse<=1; state<=0; end
endcase| 协议 | 线数 | 时钟 | 双工 | 速率 |
|---|---|---|---|---|
| SPI | 4 | 同步 | 全双工 | 高 |
| UART | 2 | 异步 | 全双工 | 中 |
| I2C | 2 | 同步 | 半双工 | 低 |
| 模式 | CPOL | CPHA | SCLK空闲 | 采样边沿 | 常用设备 |
|---|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低 | 上升沿 | SPI Flash |
| Mode 1 | 0 | 1 | 低 | 下降沿 | 部分ADC |
| Mode 2 | 1 | 0 | 高 | 下降沿 | 少数 |
| Mode 3 | 1 | 1 | 高 | 上升沿 | SD卡 |
module spi_master_tb;
logic clk,rst_n; logic [7:0] tx_data,rx_data;
logic spi_start,spi_busy,spi_done;
logic sclk,mosi,miso,cs_n;
spi_master uut(.*);
initial clk=0; always #10 clk=~clk;
// 从机回环
reg [7:0] slave_shift;
always @(posedge sclk) slave_shift<={slave_shift[6:0],mosi};
assign miso=slave_shift[7];
task spi_transfer(input [7:0] data);
@(posedge clk); tx_data=data; spi_start=1;
@(posedge clk); spi_start=0;
wait(spi_done);
$display(" 发送:0x%02H, 接收:0x%02H",data,rx_data);
#1000;
endtask
initial begin
rst_n=0;#500;rst_n=1; slave_shift=8'hAB;
$display("========== SPI主机验证 ==========");
spi_transfer(8'hA5);
spi_transfer(8'h3C);
spi_transfer(8'hFF);
$display("==========================================");
$finish;
end
initial #10_000_000 $finish;
endmodule| 特性 | SPI | UART | I2C |
|---|---|---|---|
| 线数 | 4 | 2 | 2 |
| 时钟 | 同步 | 异步 | 同步 |
| 双工 | 全双工 | 全双工 | 半双工 |
| 速率 | 高(10MHz+) | 中(~1Mbps) | 低(~3.4Mbps) |
| 多从机 | 每从机1CS | 点对点 | 7/10位地址 |
| 适用 | Flash/ADC | 调试/蓝牙 | 传感器/EEPROM |
1. SPI Flash — W25Q系列,存储固件/数据
2. ADC/DAC — MCP3008(ADC), MCP4922(DAC)
3. OLED显示 — SSD1306 SPI模式
4. SD卡 — SPI模式初始化
5. 无线模块 — nRF24L01
verilator --binary -j 0 --trace spi_master.v spi_master_tb.sv ./obj_dir/Vspi_master_tb # 预期输出: # ========== SPI主机验证 ========== # 发送:0xA5, 接收:0x?? (从机回环数据) # 发送:0x3C, 接收:0x?? # 发送:0xFF, 接收:0x?? # ========================================== # 提示:在GTKWave中查看SCLK, MOSI, MISO, CS_N四条信号线 # 可以清楚看到SPI Mode 0的完整时序
✅ SPI的四根信号线分别起什么作用?
✅ CPOL和CPHA如何影响时钟极性和采样边沿?
✅ Mode 0的空闲SCLK状态和采样边沿?
✅ SPI是MSB first而UART是LSB first——为什么?
✅ CS_N片选信号的作用?
✅ SPI vs UART vs I2C各自适用场景?
✅ 为什么SPI速度最快?
下一课学习I2C通信——只需要2根线!开漏输出+上拉电阻=线与逻辑,7位地址寻址,ACK握手。
Q: 从机无响应? 检查CS_N是否为低(选中),SCLK频率是否在从机支持范围内。
Q: 数据移位方向错误? SPI是MSB first!tx_shift[7]先发,左移。和UART的LSB first相反。
Q: Mode不对? 确认设备数据手册指定CPOL/CPHA。Mode 0最常见。
| 参数 | 值 | 说明 |
|---|---|---|
| 信号线 | 4根 | SCLK+MOSI+MISO+CS |
| 数据顺序 | MSB first | 最高位先发 |
| 双工方式 | 全双工 | 同时收发 |
| 常见速率 | 1~50MHz | 远快于I2C |
| CS极性 | 低有效 | CS=0选中 |
| 空闲SCLK(Mode0) | 低 | CPOL=0 |
| 采样边沿(Mode0) | 上升沿 | CPHA=0 |
💡 SPI为什么最快?:①全双工——同时收发数据 ②推挽输出驱动——比I2C开漏快得多 ③无需地址/ACK开销——CS直接选设备 ④时钟可达50MHz+。代价是线多——每加一个从设备就要多一根CS线。
| 模式 | CPOL | CPHA | SCLK空闲 | 采样边沿 |
|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低 | 上升沿 |
| Mode 1 | 0 | 1 | 低 | 下降沿 |
| Mode 2 | 1 | 0 | 高 | 下降沿 |
| Mode 3 | 1 | 1 | 高 | 上升沿 |
// 简单SPI从机回环
reg [7:0] slave_shift;
always @(posedge sclk) slave_shift<={slave_shift[6:0],mosi};
assign miso=slave_shift[7];
task spi_transfer(input [7:0] data);
@(posedge clk); tx_data=data; spi_start=1;
@(posedge clk); spi_start=0;
wait(spi_done);
$display("发送:0x%02H, 接收:0x%02H",data,rx_data);
endtask