SPI 与 I2C(裸机)
用途
为传感器和存储芯片实现 SPI 与 I2C 主模式驱动:时钟配置、相位/极性(SPI)、START/ACK 序列(I2C),以及常见的面向寄存器的读写事务模式。
适用场景
- 读取 I2C 传感器(WHO_AM_I 寄存器)
- SPI flash 或显示屏的点亮启动
- 调试 NACK 或 SCL 卡死
- 用最小代码替换 HAL_I2C/SPI
工作流程
- SPI 主模式(STM32)
模式 0:CPOL=0,CPHA=0 —— 需核对从机数据手册
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | (3 << SPI_CR1_BR_Pos); /* 波特率分频 */ SPI1->CR1 |= SPI_CR1_SPE;
uint8_t spi_xfer(SPI_TypeDef *spi, uint8_t tx) { while (!(spi->SR & SPI_SR_TXE)) ; *(volatile uint8_t *)&spi->DR = tx; while (!(spi->SR & SPI_SR_RXNE)) ; return *(volatile uint8_t *)&spi->DR; }
CS(GPIO 位操作):
GPIO_CS_LOW(); spi_xfer(SPI1, reg | 0x80); /* 读 */ uint8_t val = spi_xfer(SPI1, 0xFF); GPIO_CS_HIGH();
- I2C 主模式——寄存器读取
START → 地址+写 → 寄存器 → 重复 START → 地址+读 → 数据 → STOP
bool i2c_read_reg(I2C_TypeDef *i2c, uint8_t dev7, uint8_t reg, uint8_t *out) { if (!i2c_start(i2c)) return false; if (!i2c_tx(i2c, (dev7 << 1) | 0)) return false; if (!i2c_tx(i2c, reg)) return false; if (!i2c_restart(i2c)) return false; if (!i2c_tx(i2c, (dev7 << 1) | 1)) return false; out = i2c_rx(i2c, false); / 最后一字节 NACK */ i2c_stop(i2c); return true; }
按参考手册轮询 SB、ADDR、TXE、RXNE、BTF 标志位。
- 常见协议
模式 | 总线
寄存器 + 写数据 | I2C/SPI
0x80 | reg 读取(最高位置 1) | SPI
16 位大端长度前缀 | SPI flash
- 智能体用法
/spi-i2c-baremetal I2C read of register 0x0F from device 0x68
常见问题
现象 | 原因 | 修复
I2C NACK | 7 位地址错误(数据手册写的是 8 位) | 地址移位;检查 R/W 位
SPI 数据异常 | CPOL/CPHA 不匹配 | 对照从机模式表
总线 SCL 被拉低卡死 | 从机时钟拉伸/故障 | 总线恢复(发送时钟脉冲)
CS 毛刺 | CS 时序与时钟不匹配 | 首个 SCK 前拉低 CS
相关技能
skills/baremetal/gpio-baremetal —— CS、SDA、SCL 引脚
skills/baremetal/peripherals-from-datasheet —— 时序要求
skills/kernel-dev/bus-drivers-i2c-spi —— Linux 内核侧
限制
以上内容基于所提供资料;关于其他平台的具体支持、完整代码实现、收费或授权方式,资料暂未提供。