spi-i2c-baremetal
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSPI and I2C (Bare-Metal)
SPI和I2C(裸机实现)
Purpose
用途
Implement SPI and I2C master drivers for sensor and memory chips: clock configuration, phase/polarity (SPI), START/ACK sequences (I2C), and common register-oriented transaction patterns.
为传感器和存储芯片实现SPI和I2C主模式驱动:时钟配置、相位/极性(SPI)、START/ACK序列(I2C)以及常见的面向寄存器的事务模式。
When to Use
使用场景
- Reading an I2C sensor (WHO_AM_I register)
- SPI flash or display bring-up
- Debugging NACK or stuck SCL
- Replacing HAL_I2C/SPI with minimal code
- 读取I2C传感器(WHO_AM_I寄存器)
- SPI闪存或显示屏启动
- 调试NACK或SCL引脚卡死问题
- 用极简代码替代HAL_I2C/SPI
Workflow
工作流程
1. SPI master (STM32)
1. SPI主模式(STM32)
c
/* Mode 0: CPOL=0, CPHA=0 — check slave datasheet */
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI
| (3 << SPI_CR1_BR_Pos); /* baud divider */
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 bit-bang):
c
GPIO_CS_LOW();
spi_xfer(SPI1, reg | 0x80); /* read */
uint8_t val = spi_xfer(SPI1, 0xFF);
GPIO_CS_HIGH();c
/* 模式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位操作):
c
GPIO_CS_LOW();
spi_xfer(SPI1, reg | 0x80); /* 读操作 */
uint8_t val = spi_xfer(SPI1, 0xFF);
GPIO_CS_HIGH();2. I2C master — register read
2. I2C主模式 — 寄存器读取
c
/* START → addr+W → reg → repeated START → addr+R → data → 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 last byte */
i2c_stop(i2c);
return true;
}Poll , , , , per reference manual.
SBADDRTXERXNEBTFc
/* 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;
}请参考手册轮询、、、、标志位。
SBADDRTXERXNEBTF3. Common protocols
3. 常见协议
| Pattern | Bus |
|---|---|
| I2C/SPI |
| `0x80 | reg` read (MSB set) |
| 16-bit big-endian length prefix | SPI flash |
| 模式 | 总线 |
|---|---|
| I2C/SPI |
| `0x80 | 寄存器` 读取(最高位设为1) |
| 16位大端长度前缀 | SPI闪存 |
4. Agent usage
4. Agent使用方式
/spi-i2c-baremetal I2C read of register 0x0F from device 0x68/spi-i2c-baremetal I2C read of register 0x0F from device 0x68Common Problems
常见问题
| Symptom | Cause | Fix |
|---|---|---|
| I2C NACK | Wrong 7-bit addr (8-bit in datasheet) | Shift addr; check R/W bit |
| SPI garbage | CPOL/CPHA mismatch | Match slave mode table |
| Bus stuck SCL low | Slave clock stretch / fault | Bus recovery (clock pulses) |
| CS glitch | CS timing vs clock | Assert CS before first SCK |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| I2C返回NACK | 7位地址错误(数据手册中为8位) | 对地址进行移位;检查读/写位 |
| SPI数据异常 | CPOL/CPHA不匹配 | 匹配从设备模式表 |
| SCL引脚持续低电平 | 从设备时钟拉伸/故障 | 总线恢复(发送时钟脉冲) |
| CS引脚出现毛刺 | CS时序与时钟不匹配 | 在第一个SCK脉冲前断言CS |
Related Skills
相关技能
- — CS, SDA, SCL pins
skills/baremetal/gpio-baremetal - — timing requirements
skills/baremetal/peripherals-from-datasheet - — Linux kernel side
skills/kernel-dev/bus-drivers-i2c-spi
- — CS、SDA、SCL引脚
skills/baremetal/gpio-baremetal - — 时序要求
skills/baremetal/peripherals-from-datasheet - — Linux内核端
skills/kernel-dev/bus-drivers-i2c-spi