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

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. neue SPI()-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.

0 Kommentare

Kommentieren

Bitte beachten Sie, dass Kommentare vor ihrer Veröffentlichung genehmigt werden müssen.