spi-i2c-baremetal

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SPI 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
SB
,
ADDR
,
TXE
,
RXNE
,
BTF
per reference manual.
c
/* 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
标志位。

3. Common protocols

3. 常见协议

PatternBus
reg + write data
I2C/SPI
`0x80reg` read (MSB set)
16-bit big-endian length prefixSPI 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 0x68

Common Problems

常见问题

SymptomCauseFix
I2C NACKWrong 7-bit addr (8-bit in datasheet)Shift addr; check R/W bit
SPI garbageCPOL/CPHA mismatchMatch slave mode table
Bus stuck SCL lowSlave clock stretch / faultBus recovery (clock pulses)
CS glitchCS timing vs clockAssert CS before first SCK
症状原因解决方法
I2C返回NACK7位地址错误(数据手册中为8位)对地址进行移位;检查读/写位
SPI数据异常CPOL/CPHA不匹配匹配从设备模式表
SCL引脚持续低电平从设备时钟拉伸/故障总线恢复(发送时钟脉冲)
CS引脚出现毛刺CS时序与时钟不匹配在第一个SCK脉冲前断言CS

Related Skills

相关技能

  • skills/baremetal/gpio-baremetal
    — CS, SDA, SCL pins
  • skills/baremetal/peripherals-from-datasheet
    — timing requirements
  • skills/kernel-dev/bus-drivers-i2c-spi
    — Linux kernel side
  • skills/baremetal/gpio-baremetal
    — CS、SDA、SCL引脚
  • skills/baremetal/peripherals-from-datasheet
    — 时序要求
  • skills/kernel-dev/bus-drivers-i2c-spi
    — Linux内核端