$npx -y skills add mohitmishra786/low-level-dev-skills --skill spi-i2c-baremetalBare-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.
| 1 | # SPI and I2C (Bare-Metal) |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | 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. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Reading an I2C sensor (WHO_AM_I register) |
| 10 | - SPI flash or display bring-up |
| 11 | - Debugging NACK or stuck SCL |
| 12 | - Replacing HAL_I2C/SPI with minimal code |
| 13 | |
| 14 | ## Workflow |
| 15 | |
| 16 | ### 1. SPI master (STM32) |
| 17 | |
| 18 | ```c |
| 19 | /* Mode 0: CPOL=0, CPHA=0 — check slave datasheet */ |
| 20 | SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI |
| 21 | | (3 << SPI_CR1_BR_Pos); /* baud divider */ |
| 22 | SPI1->CR1 |= SPI_CR1_SPE; |
| 23 | |
| 24 | uint8_t spi_xfer(SPI_TypeDef *spi, uint8_t tx) { |
| 25 | while (!(spi->SR & SPI_SR_TXE)) |
| 26 | ; |
| 27 | *(volatile uint8_t *)&spi->DR = tx; |
| 28 | while (!(spi->SR & SPI_SR_RXNE)) |
| 29 | ; |
| 30 | return *(volatile uint8_t *)&spi->DR; |
| 31 | } |
| 32 | ``` |
| 33 | |
| 34 | CS (GPIO bit-bang): |
| 35 | |
| 36 | ```c |
| 37 | GPIO_CS_LOW(); |
| 38 | spi_xfer(SPI1, reg | 0x80); /* read */ |
| 39 | uint8_t val = spi_xfer(SPI1, 0xFF); |
| 40 | GPIO_CS_HIGH(); |
| 41 | ``` |
| 42 | |
| 43 | ### 2. I2C master — register read |
| 44 | |
| 45 | ```c |
| 46 | /* START → addr+W → reg → repeated START → addr+R → data → STOP */ |
| 47 | bool i2c_read_reg(I2C_TypeDef *i2c, uint8_t dev7, uint8_t reg, uint8_t *out) { |
| 48 | if (!i2c_start(i2c)) return false; |
| 49 | if (!i2c_tx(i2c, (dev7 << 1) | 0)) return false; |
| 50 | if (!i2c_tx(i2c, reg)) return false; |
| 51 | if (!i2c_restart(i2c)) return false; |
| 52 | if (!i2c_tx(i2c, (dev7 << 1) | 1)) return false; |
| 53 | *out = i2c_rx(i2c, false); /* NACK last byte */ |
| 54 | i2c_stop(i2c); |
| 55 | return true; |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | Poll `SB`, `ADDR`, `TXE`, `RXNE`, `BTF` per reference manual. |
| 60 | |
| 61 | ### 3. Common protocols |
| 62 | |
| 63 | | Pattern | Bus | |
| 64 | |---------|-----| |
| 65 | | `reg + write data` | I2C/SPI | |
| 66 | | `0x80|reg` read (MSB set) | SPI sensors | |
| 67 | | 16-bit big-endian length prefix | SPI flash | |
| 68 | |
| 69 | ### 4. Agent usage |
| 70 | |
| 71 | ``` |
| 72 | /spi-i2c-baremetal I2C read of register 0x0F from device 0x68 |
| 73 | ``` |
| 74 | |
| 75 | ## Common Problems |
| 76 | |
| 77 | | Symptom | Cause | Fix | |
| 78 | |---------|-------|-----| |
| 79 | | I2C NACK | Wrong 7-bit addr (8-bit in datasheet) | Shift addr; check R/W bit | |
| 80 | | SPI garbage | CPOL/CPHA mismatch | Match slave mode table | |
| 81 | | Bus stuck SCL low | Slave clock stretch / fault | Bus recovery (clock pulses) | |
| 82 | | CS glitch | CS timing vs clock | Assert CS before first SCK | |
| 83 | |
| 84 | ## Related Skills |
| 85 | |
| 86 | - `skills/baremetal/gpio-baremetal` — CS, SDA, SCL pins |
| 87 | - `skills/baremetal/peripherals-from-datasheet` — timing requirements |
| 88 | - `skills/kernel-dev/bus-drivers-i2c-spi` — Linux kernel side |