---
name: SPI and I2C Bare Metal
slug: spi-and-i2c-bare-metal
category: Automation
description: SPI and I2C Bare Metal shows how to implement master-mode SPI and I2C transactions without a HAL. Use it for sensor register reads, flash/display bring-up, and debugging NACKs, CPOL/CPHA mismatches, or stuck bus lines.
github: "https://github.com/mohitmishra786/low-level-dev-skills/tree/main/skills/baremetal/spi-i2c-baremetal"
language: JavaScript
stars: 194
forks: 27
install: "npx degit https://github.com/mohitmishra786/low-level-dev-skills/tree/main/skills/baremetal/spi-i2c-baremetal ~/.claude/skills/spi-i2c-baremetal"
installs_to: ~/.claude/skills/spi-i2c-baremetal
source_path: skills/baremetal/spi-i2c-baremetal/SKILL.md
collection_size: 25
category_size: 1956
collection_url: "https://dirskills.com/collections/mohitmishra786/low-level-dev-skills"
added: 2026-09-05T05:31:28.327Z
last_synced: 2026-09-05T05:31:28.327Z
canonical_url: "https://dirskills.com/skills/spi-and-i2c-bare-metal"
---

# SPI and I2C Bare Metal

SPI and I2C Bare Metal shows how to implement master-mode SPI and I2C transactions without a HAL. Use it for sensor register reads, flash/display bring-up, and debugging NACKs, CPOL/CPHA mismatches, or stuck bus lines.

**Install:**

```bash
npx degit https://github.com/mohitmishra786/low-level-dev-skills/tree/main/skills/baremetal/spi-i2c-baremetal ~/.claude/skills/spi-i2c-baremetal
```

## README

# 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
