Ein Bluetooth-Modul ist nicht nur ein Funkteil. Unter dem Shield sitzt ein echtes MCU mit GPIO, I2C, SPI, UART, ADC, PWM und Timern. Wie du Sensoren und Peripherie an dieses MCU anschliesst – und wie die Treibersoftware strukturiert ist – entscheidet, ob dein Produkt zuverlaessig, stromsparend und wartbar ist. Dieser Artikel ist ein praktischer Feldleitfaden.
Die Busse im Vergleich
| Bus | Leitungen | Speed | Topologie | Adresse | Gut fuer |
|---|---|---|---|---|---|
| GPIO | 1-2 | n/a | Punkt | keine | Taster, LEDs, Enable |
| I2C | 2 (SDA/SCL) | 100 k-1 MHz | Multi-Drop | 7/10-bit | viele Sensoren, Config-Reg |
| SPI | 4 (MOSI/MISO/SCK/CS) | 1-32 MHz | Punkt (CS pro Dev) | CS-Pin | hoher Rate, Displays, Flash |
| UART | 2 (TX/RX) | bis wenige Mbps | Punkt | keine | GNSS, Debug, Legacy |
Faustregel: I2C fuer viele langsame Sensoren an wenigen Pins, SPI wenn Durchsatz oder Latenz zaehlen, UART um mit der seriellen Konsole eines anderen Chips zu reden.
I2C-Details, die beissen
- Pull-ups: 4,7 kOhm ist der klassische Startwert fuer 100 kHz bei mittlerer Buskapazitaet. Berechne R_min aus max. Senkstrom und R_max aus Anstiegszeit: R_max <= t_r / (0,847 * C_bus). Ein langer Bus mit 200 pF und 1 us Anstieg braucht R <= ~5,9 kOhm.
- Clock-Stretching: Slaves duerfen SCL tief halten. Dein Master muss das koennen, sonst haengt ein langsamer Sensor den Bus auf.
- Bus-Lock-Recovery: wird ein Slave mitten in der Uebertragung resettet, kann er SCL tief einfrieren. Recovery toggelt SCL (9 Pulse), bis er freigibt, dann STOP. Einbauen in den Treiber.
- Adresskonflikte: zwei Sensoren mit derselben fixen Adresse brauchen einen Mux (z.B. TCA9548A) oder Pin-Strap-Variante.
SPI-Details, die beissen
- CS-Timing: CS assert, Setup vor Takt, Hold nach letztem Bit. Viele Flashes brauchen CS hoch zwischen Kommandos, sonst bleiben sie in einem Zustand.
- Mode (CPOL/CPHA): falsch und jedes Byte ist verschoben. Pro Device dokumentieren.
- DMA: SPI bei 8 MHz bewegt 1 MB/s; mit CPU-gepokten Bytes verbrennst du beide Kerne. Nutze DMA mit Ringpuffer fuers Streaming (Sensor-Fusion, Audio).
- MISO-Konflikt: nur das gewaehlte Device treibt MISO; verdrahteter CS laesst zwei Devices kaempfen.
UART-Details, die beissen
- Baud-Abweichung: 2% ist die uebliche Toleranz; ein RC-Oszillator des Moduls bei 3% korrumpiert bei 115200. Kristall nutzen oder niedrigere Baud akzeptieren.
- Flusskontrolle: RTS/CTS aktivieren, bevor du hohen Durchsatz traust, sonst verlierst du Bytes unter Last.
- Overrun: leert die ISR die FIFO nicht schnell genug, erhoehe den FIFO-Trigger oder gehe zu DMA.
Interrupt-Latenz-Budget
Von einer Pin-Aenderung bis deine ISR laeuft:
- SoC-Wake aus Low-Power: 1-10 us (je nach Retention-State)
- ISR-Eintritt + Prolog: < 1 us
- Kritische Sektion: der Killer. Ein langer disable_irq()-Block verzoegert jede andere Interrupt. Kritische Sektionen auf Mikrosekunden halten; Arbeit an eine Task verlagern.
Auf einem nRF52840 mit 64 MHz feuert eine saubere ISR in wenigen Mikrosekunden. Eine 5-ms-kritische Sektion in einer Log-Funktion kann eine 1-kHz-Abtast-Deadline sprengen.
Clock-Gating und Peripherie-Leistung
Unbenutzte Peripherie zieht selbst im Idle uA. Ein UART bei 3 uA aktiv, ADC-Referenz 10 uA, uebriger Timer 2 uA – das sind 15 uA reine Verschwendung an einem Tag, der 5 uA sippt. Deaktiviere ungenutzte Peripherie und gate den HF-Takt, wenn die Radio idle ist.
Treiber-Architektur
Bevorzuge eine geschichtete, nicht-blockierende Struktur:
<h1>pseudo: nicht-blockierendes I2C-Lesen mit DMA + Timeout</h1>
def read_sensor(dev, reg, buf):
i2c.start_write(dev, [reg])
i2c.start_read_dma(dev, buf, done_cb)
return # nicht blockieren
def done_cb(buf):
queue.put(("sensor", buf)) # RTOS-Task verarbeitet spaeter
- HAL-Schicht: duenne Wrapper ueber Register, gleiche API ueber Chips.
- Treiber-Schicht: sensor-spezifisches Init, Kalibrierung, Einheitenwandel.
- Service-Schicht: eine RTOS-Task besitzt den Bus, serialisiert Zugriff, bietet Queue.
- Nie blockieren in einer Interrupt; nur signalisieren.
Das bewahrt den Radio-Stack (harte Echtzeit noetig) davor, von langsamem Sensor-Lesen ausgehungert zu werden.
Level-Shifting
Ein 1,8-V-Modul, das mit einem 3,3-V-Sensor redet, braucht Level-Shifter auf jeder Leitung (oder 1,8-V-toleranten Sensor). Vergessen hier verursacht intermitterende Korruption, die am Logik-Analysator verschwindet.
Tabelle haeufiger Fehler
| Symptom | Wahrscheinliche Ursache |
|---|---|
| Bus friert zufaellig ein | I2C-Slave tief gesperrt, keine Recovery |
| SPI-Lesung verschoben | falsches CPOL/CPHA |
| UART verliert Bytes | keine Flusskontrolle / kleine FIFO |
| Hoher Idle-Strom | Peripherie nicht gegated |
| Deadlines verfehlt | lange kritische Sektion |
| intermitterende Daten | Level-Shifter fehlt |
Fazit
Ein Bluetooth-Modul scheitert oder gelingt an den Teilen um die Radio herum. Waehle den Bus nach Speed und Pinzahl, berechne I2C-Pull-ups, achte auf SPI-CS-Timing, nutze DMA fuer Durchsatz, halte kritische Sektionen winzig und gate jede ungenutzte Peripherie. Eine saubere Treiber-Schichtung – HAL, Treiber, Service-Task, Queue – haelt den Radio-Stack echtzeitnah und deinen Firmware debugbar.