SPI: Der schnelle Vierleiter-Bus (MOSI/MISO/SCK/CS) für Displays, Speicher & ADCs

SPI – Der schnelle Vierleiter-Bus
SPI (Serial Peripheral Interface) ist ein synchrones Busprotokoll mit den Signalen MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (Takt) und CS/SS (Chip-Select). Es eignet sich für Displays, SD-Karten, schnelle ADCs/DACs und Speicher, wenn hohe Datenraten gefragt sind.
Warum SPI?
- Hohe Geschwindigkeit: typisch einige MHz bis zehner MHz (board-/gerätabhängig).
- Vollduplex: Daten können gleichzeitig in beide Richtungen fließen.
- Einfach skalierbar: Mehrere Geräte teilen sich MOSI/MISO/SCK; jedes Gerät bekommt seine eigene CS-Leitung.
Pinbelegung & Pegel
- Arduino Uno: MOSI=11, MISO=12, SCK=13, CS z. B. 10 (oder ICSP-Header).
- ESP32 (VSPI Standard): MOSI=23, MISO=19, SCK=18, CS=5 (Pins frei konfigurierbar).
- Pegel: viele Boards arbeiten mit 3,3 V; bei 5-V-Modulen Level-Shifter beachten.
- Modi: SPI-Mode 0/1/2/3 (Kombination aus CPOL/CPHA) – laut Datenblatt des Geräts wählen.
Beispiel 1: Generischer SPI-Transfer (Arduino)
Demonstriert das Senden/Lesen eines Registers über SPI.transfer()
. Ersetze READ_REG
, WRITE_REG
und Registeradresse laut Datenblatt deines Bausteins.
#include <SPI.h>
const uint8_t PIN_CS = 10;
const uint8_t READ_REG = 0x80; // Beispiel: MSB=1 für Read
const uint8_t WRITE_REG = 0x00;
uint8_t spiRead(uint8_t reg){
digitalWrite(PIN_CS, LOW);
SPI.transfer(READ_REG | reg);
uint8_t val = SPI.transfer(0x00);
digitalWrite(PIN_CS, HIGH);
return val;
}
void spiWrite(uint8_t reg, uint8_t val){
digitalWrite(PIN_CS, LOW);
SPI.transfer(WRITE_REG | reg);
SPI.transfer(val);
digitalWrite(PIN_CS, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(PIN_CS, OUTPUT);
digitalWrite(PIN_CS, HIGH);
SPI.begin(); // Init Bus
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); // 8 MHz, Mode 0
spiWrite(0x20, 0x0F); // Beispiel: Gerät einschalten
uint8_t id = spiRead(0x0F); // Beispiel: WHO_AM_I
Serial.print("ID: 0x"); Serial.println(id, HEX);
}
void loop() {
// ... Hauptlogik ...
}
Beispiel 2: MCP3008 (10-Bit-ADC) auslesen – MicroPython (ESP32)
Der MCP3008 liefert 10-Bit-Werte über SPI. Chip-Select (cs
) pro Gerät separat.
from machine import SPI, Pin
sck = Pin(18)
mosi = Pin(23)
miso = Pin(19)
cs = Pin(5, Pin.OUT, value=1)
spi = SPI(2, baudrate=1000000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
# Kanal 0 lesen (Startbit=1, Single-Ended, CH=0)
def read_ch0():
cs.value(0)
resp = spi.readinto(bytearray(3), 0) # Dummy, um RAM anzulegen
cs.value(1)
def read_mcp3008(ch=0):
cmd = bytearray([0x01, (8|ch)<<4, 0x00])
buf = bytearray(3)
cs.value(0)
spi.write_readinto(cmd, buf)
cs.value(1)
val = ((buf[1] & 0x03) << 8) | buf[2]
return val
print("ADC CH0:", read_mcp3008(0))
Mehrere Geräte am SPI-Bus
- CS pro Gerät: Jedes Gerät erhält seinen eigenen Chip-Select-Pin.
-
Parameter je Gerät: Manche Bausteine brauchen anderen Modus/Takt –
beginTransaction()
bzw. neueSPI()
-Konfiguration nutzen. - Leitungsführung: Kurze SPI-Leitungen, gemeinsame Masse, ggf. terminieren/abschirmen bei sehr hohen Takten.
Troubleshooting (Kurz)
- Nur Nullen/0xFF: CS/Mode/Takt prüfen; MISO/MOSI verwechselt; Pull-Ups/-Downs laut Datenblatt.
- Instabil bei höherem Takt: Kabellänge reduzieren, Takt senken, saubere Masse/Versorgung.
- Mehrere Geräte stören sich: CS-Leitungen korrekt? Manche Geräte brauchen zusätzlichen Pull-Up auf CS.
- Pegelproblem: 3,3-V-Controller nicht direkt an 5-V-SPI ohne Level-Shifter betreiben.
Weiterführend: I²C, UART, DMA-SPI, SD-Karten, OLED/ILI9341, MCP3008/23K256, Level-Shifter.
- Tags: ADC Arduino Bus Chip Select CS Display Einsteiger Elektronik ESP32 MCP3008 MicroPython MISO MOSI OLED Pegel SCK SD SPI Tutorial
0 Kommentare