# Spi I2c Baremetal

> Bare-metal SPI and I2C skill for serial peripheral buses. Use when implementing master-mode transfers, register read/write protocols, or debugging bus stalls. Activates on queries about SPI bare-metal, I2C START/STOP, sensor register read, or clock phase/polarity.

- Skill: `mohitmishra786/spi-i2c-baremetal` (Agent Skill)
- Install (CLI): `npx skillmds add mohitmishra786/spi-i2c-baremetal`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mohitmishra786/spi-i2c-baremetal/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: mohitmishra786 (https://skillmd.com/u/mohitmishra786)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/mohitmishra786/spi-i2c-baremetal

---


# SPI and I2C (Bare-Metal)

## 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.

## 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

## Workflow

### 1. SPI master (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();
```

### 2. I2C master — register read

```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.

### 3. Common protocols

| Pattern | Bus |
|---------|-----|
| `reg + write data` | I2C/SPI |
| `0x80|reg` read (MSB set) | SPI sensors |
| 16-bit big-endian length prefix | SPI flash |

### 4. Agent usage

```
/spi-i2c-baremetal I2C read of register 0x0F from device 0x68
```

## Common 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 |

## 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
