Wenn ein Bluetooth-Modul im Feld Verbindungen verliert, im Sleep-Modus 3 mA ueber Spezifikation verbraucht oder bei der Zertifizierung auf dem 2. Kanal des 40-Kanal-DTM-Sweeps scheitert, ist der Unterschied zwischen einer einstuendigen Reparatur und einer zweiwoechigen Sackgasse, ob Sie das Modul waehrend der Entwicklung richtig instrumentiert haben. Dieser Artikel behandelt die physischen Debug-Schnittstellen, Echtzeit-Tracing-Methoden, RF-Verifizierungspfade und Post-Mortem-Tools, die ab dem ersten Schaltplan-Tag eingeplant werden sollten — nicht nach dem ersten Feldfehler nachgeruestet.

## 1. Debug-Schnittstellenuebersicht: JTAG vs SWD vs cJTAG

Die meisten modernen BLE-SoCs (nRF52/53, CC2640, ESP32-C3/H2, DA1469x, BGMxx) exponieren entweder ein volles 5-Pin-JTAG (TCK, TMS, TDI, TDO, nTRST) oder das ARM-spezifische 2-Pin-SWD (SWCLK, SWDIO) plus nRESET. Die folgende Tabelle fasst die Kompromisse fuer das BLE-Moduldesign zusammen:

Parameter JTAG (5-Pin) SWD (2-Pin + RESET) cJTAG (2-Pin)
Pin-Anzahl 5 (oder 4 ohne nTRST) 2-3 2
Max. Takt 10-50 MHz 1-50 MHz bis 50 MHz
Trace-Unterstuetzung ETM (4-Pin-Trace-Bus) ITM (SWO, 1-Pin) ITM (SWO)
Flash-Download-Geschw. (256 KB) ~8-12 s ~6-10 s ~6-10 s
Kabellaengenbegrenzung ~15 cm (ungepuffert) ~30 cm (ungepuffert) ~20 cm
SoC-Unterstuetzung Universell (ARM + RISC-V) Nur ARM Cortex-M ARM Cortex-M33/55
Typische Stromaufnahme (aktives Debug) 2-5 mA 1-3 mA 1-3 mA

Fuer BLE-Module, bei denen die PCB-Flaeche in Quadratmillimetern gemessen wird, ist SWD die Standardwahl. Die nRF52/53-Serie erlaubt SWD sogar auf denselben Pins wie GPIO P0.00/P0.01 waehrend der Entwicklung. Diese werden auf einen 0,05-Zoll-Raster-Mikro-Header (Samtec FTSH-105 oder aequivalent) gefuehrt und entweder fuer die Entwicklung bestueckt oder als nackte PCB-Pads fuer die Produktion belassen. Der Nur-Pad-Ansatz ist vorzuziehen, da ein bestueckter Header auf einem Produktionsmodul unautorisierten Zugriff einlaedt.

### SWD-Signalintegritaetsueberlegungen

SWDIO ist bidirektional und Open-Drain mit Pull-up (typisch 10 kΩ intern, 4,7 kΩ extern). Der Pull-up-Wert ist wichtiger, als die meisten Ingenieure erwarten:

Pull-up SWDIO-Anstiegszeit (tr) Max. SWCLK Hinweise
100 kΩ 220 ns 1 MHz Grenzwertig — gelegentlicher Sync-Verlust
47 kΩ 104 ns 4 MHz OK fuer kurze Kabel (<15 cm)
10 kΩ 22 ns 25 MHz Zuverlaessig fuer die meisten Setups
4,7 kΩ 10 ns 50 MHz Bevorzugt fuer J-Link bei hoher Geschwindigkeit
1 kΩ 2,2 ns >50 MHz Uebertrieben, verschwendet 3,3 mA bei Low

Die Formel ist einfach RC-Verzoegerung: tr ≈ 2.2 × R × C, wobei C die Gesamt-Leiterbahn- + Tastkopfkapazitaet ist (typisch 10-20 pF bei einem Modul mit 15 cm Flachbandkabel). Wenn Sie intermitierende „SWD DP read failed“-Fehler auf Ihrem J-Link sehen, sollten Sie zuerst pruefen, ob der externe Pull-up fehlt und der interne 10 kΩ gegen ein langes Kabel kaempft.

## 2. UART-Debug-Konsole: Design fuer reales Debugging

Eine UART-Debug-Konsole ist die wertvollste Debug-Schnittstelle in Produktionsfirmware, wird aber routinemaessig schlecht implementiert. Die haeufigsten Fehler:

1. Baudrate zu hoch fuer die BLE-Stack-Prioritaet. Bei 1 Mbps UART mit 16-Byte-FIFO wird der Interrupt alle 128 μs ausgeloest. Wenn der BLE-Stack Interrupts waehrend 150 μs der Verbindungsereignis-Vorbereitung sperrt, gehen Zeichen verloren. Loesung: 460800 bps oder 921600 bps mit DMA-TX und Ringpuffer fuer RX verwenden.

2. printf blockiert die Hauptschleife. Ein blockierendes printf, das 200 Bytes bei 115200 bps schreibt, dauert 17,4 ms — laenger als ein 7,5 ms BLE-Verbindungsintervall. Verwenden Sie einen lockfreien Ringpuffer mit DMA-Flush im Idle:

// Lockfreier UART-Debug-Ringpuffer (einzelner Produzent, einzelner Konsument)
#define DBG_BUF_SIZE 2048
static volatile uint16_t dbg_head = 0, dbg_tail = 0;
static char dbg_buf[DBG_BUF_SIZE];

void dbg_printf(const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    char tmp[256];
    int len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
    va_end(ap);
    for (int i = 0; i < len; i++) {
        uint16_t next = (dbg_head + 1) & (DBG_BUF_SIZE - 1);
        if (next == dbg_tail) break;  // Puffer voll, Zeichen verwerfen
        dbg_buf[dbg_head] = tmp[i];
        dbg_head = next;
    }
    // DMA-Flush ausloesen, wenn TX idle
    if (!(UART0->STAT & UART_STAT_TXBUSY)) {
        uart_dma_flush();
    }
}

3. Keine Log-Level-Filterung. Ein Produktionsmodul, das VERBOSE-Level-Logs bei 460800 bps waehrend eines Verbindungsereignisses ausgibt, verursacht Timing-Jitter. Implementieren Sie Kompilierzeit- und Laufzeit-Filterung:

Level Kompilier-Flag Runtime Typische Verwendung
ERROR DBG_ERROR Immer an Hard Faults, Assert-Fehler
WARN DBG_WARN Immer an Wiederversuche, degradierte Leistung
INFO DBG_INFO Konfigurierbar Verbindung/Trennung, Zustaendsaenderungen
DEBUG DBG_DEBUG Off in Produktion Pro-Event-Timing, Paket-Dumps
VERBOSE DBG_VERBOSE Off in Produktion Pro-Slot-Scheduling, RSSI pro Event

4. Keine Binaer-Crash-Dump-Faehigkeit. Wenn das Modul einen Hard Fault hat, ist UART Ihre einzige Lebensader. Reservieren Sie einen 1 KB Crash-Dump-Handler, der die gestapelten Register (R0-R3, R12, LR, PC, xPSR) und die ersten 16 Worte des Stacks vor dem Watchdog-Reset ausgibt:

void HardFault_Handler(void) {
    uint32_t *stk;
    __asm volatile("tst lr, #4 
"
                   "ite eq 
"
                   "mrseq %0, msp 
"
                   "mrsne %0, psp 
" : "=r"(stk));
    dbg_printf("
*** HARD FAULT ***
");
    dbg_printf("R0:  0x%08X  R1:  0x%08X  R2:  0x%08X  R3:  0x%08X
",
               stk[0], stk[1], stk[2], stk[3]);
    dbg_printf("R12: 0x%08X  LR:  0x%08X  PC:  0x%08X  PSR: 0x%08X
",
               stk[4], stk[5], stk[6], stk[7]);
    dbg_printf("BFAR: 0x%08X  CFSR: 0x%08X  HFSR: 0x%08X
",
               SCB->BFAR, SCB->CFSR, SCB->HFSR);
    for (int i = 0; i < 16; i++) {
        dbg_printf("SP+%02d: 0x%08X
", i*4, stk[i]);
    }
    while(1);  // Auf Watchdog warten
}

### UART-Pin-Auswahl bei BLE-Modulen

Vermeiden Sie P0.00/P0.01 (fuer SWD oder 32-kHz-Kristall reserviert), P0.02/P0.03 (oft ADC oder Analog) und alle Pins, die vom BLE-Stack fuer Radio-Timing verwendet werden. Sichere UART-Pins bei haeufigen SoCs:

SoC Sicheres TX Sicheres RX Vermeiden
nRF52832 P0.06 P0.08 P0.00/01 (XL1/XL2), P0.09 (NFC)
nRF52840 P1.08 P1.10 P0.00/01, P0.09/10 (NFC), P0.24-25 (USB)
ESP32-C3 GPIO2 GPIO3 GPIO0 (Boot), GPIO2 (Strapping)
CC2640R2 DIO2 DIO3 DIO0-1 (Boot), DIO7-8 (JTAG)
DA1469x P0_06 P0_07 P0_00 (XTAL32M), P0_01-03 (SWD)

## 3. Echtzeit-Tracing: RTT vs ITM/SWO vs ETM

printf-basiertes UART-Debug ist fuer niederfrequente Ereignisse geeignet, aber die BLE-Stack-Timing-Analyse erfordert Submikrosekunden-Aufloesung. Drei Optionen mit unterschiedlichen Kompromissen:

### Segger RTT (Real-Time Transfer)

RTT verwendet einen Ringpuffer im Ziel-RAM, den der Debugger ueber SWD mit hoher Geschwindigkeit abfragt. Es erfordert null Ziel-CPU-Zeit pro Log-Eintrag (der Debugger liest RAM direkt), was es ideal fuer timing-kritischen Code macht:

Metrik UART @ 460800 RTT ITM/SWO @ 2 MHz
CPU-Zeit pro 100-Zeichen-Log ~2,2 ms ~5 us ~50 us
Durchsatz 46 KB/s ~500 KB/s ~200 KB/s
Latenz (Log → Debugger) 2,2 ms ~10 us ~25 us
Benoetigte Pins 2 (TX/RX) 0 (nutzt SWD) 1 (SWO) + SWD
Puffer im RAM 0 1-4 KB 0 (Hardware-FIFO)
Debugger-Unterstuetzung Beliebiges Terminal Nur J-Link J-Link, ST-Link, CMSIS-DAP

RTTs Hauptvorteil ist, dass es ueber die vorhandene SWD-Schnittstelle ohne zusaetzliche Pins funktioniert. Die Hauptbeschraenkung ist, dass es einen Segger J-Link erfordert. Fuer Entwicklung ist das akzeptabel; fuer Felddiagnose haben Sie wahrscheinlich keinen J-Link.

RTT unterstuetzt auch bidirektionale Kommunikation — der Debugger kann Befehle in das Ziel injizieren, ohne einen UART-Pin zu verwenden:

#include "SEGGER_RTT.h"

void rtt_command_loop(void) {
    char cmd[64];
    int len = SEGGER_RTT_Read(0, cmd, sizeof(cmd) - 1);
    if (len > 0) {
        cmd[len] = '';
        if (strcmp(cmd, "stats") == 0) {
            print_ble_stats();
        } else if (strcmp(cmd, "scan") == 0) {
            start_debug_scan(100);
        } else if (strcmp(cmd, "conn") == 0) {
            print_connection_info();
        }
    }
}

### ITM/SWO-Tracing

ITM (Instrumentation Trace Macrocell) ist ein ARM Cortex-M3/4/7/33-Feature, das 32 Stimulus-Ports fuer anwendungslevel-Tracing plus Zeitstempelung und Exception-Tracing bietet. Der SWO-Pin (Serial Wire Output) traegt ITM-Daten als Ein-Draht-UART bis zur CPU-Taktgeschwindigkeit:

// ITM-Stimulus-Port 0 fuer Debug-Nachrichten
#define ITM_Port8(n)  (*((volatile uint8_t *)(0xE0000000 + 4*n)))
#define ITM_Port32(n) (*((volatile uint32_t *)(0xE0000000 + 4*n)))

void itm_printf(char *s) {
    while (*s) {
        while (ITM_Port8(0) == 0);  // Warten bis Port bereit
        ITM_Port8(0) = *s++;
    }
}

SWO kann in zwei Modi konfiguriert werden:

Modus SWO-Baudrate Taktquelle Vorteile Nachteile
UART-Modus 2-50 MHz HCLK / Prescaler Funktioniert mit jeder SWO-faehigen Sonde Baud muss exakt passen
Manchester-Modus Bis CPU-Takt HCLK direkt Selbsttaktend, keine Baud-Anpassung Nur J-Link, nicht ST-Link

Fuer BLE-Timing-Analyse eignet sich ITM hervorragend fuer Pro-Event-Zeitstempel-Logging. Die ITM-Hardware stempelt jeden Schreibvorgang mit einem Zaehler mit 1-Zyklus-Aufloesung, sodass Sie Verbindungsereignis-Timing ohne CPU-Overhead messen koennen:

// Verbindungsereignis-Timing auf ITM-Port 1 protokollieren
void on_conn_event(uint16_t handle, int8_t rssi, uint32_t elapsed_us) {
    ITM_Port32(1) = handle;
    ITM_Port32(1) = (uint32_t)rssi;
    ITM_Port32(1) = elapsed_us;
}

J-Link SWO Viewer oder SystemView koennen diese Ereignisse auf einer Zeitachse mit nanosekunden-genuen Zeitstempeln anzeigen.

### ETM (Embedded Trace Macrocell)

ETM bietet vollstaendiges Instruktionsebene-Tracing ueber einen 4-Bit-parallelen Trace-Bus. Es ist auf Cortex-M7 (und einigen M4) verfuegbar, erfordert aber 4-7 zusaetzliche Pins. Fuer BLE-Modul-Arbeiten ist ETM selten gerechtfertigt — die Pin-Kosten sind zu hoch und Instruktionsebene-Tracing produziert zu viele Daten, um fuer Protokollebene-Debugging nuetzlich zu sein.

## 4. Logikanalysator-Techniken fuer BLE-Timing

Ein Logikanalysator ist unabdingbar fuer das Debuggen von BLE-Timing-Problemen, die fuer softwarebasierte Instrumentierung unsichtbar sind. Die wichtigsten Anwendungsfälle:

### 4.1 BLE-Stack-Ereignisverifizierung

Die meisten BLE-Stacks exponieren ein „Radio-Event“- oder „Timer-Compare“-GPIO, das am Anfang und Ende jeder Radioaktivitaet schaltet. Auf nRF52 ist dies RADIO_SHORTS oder TIMER0-Compare; auf ESP32 das BT_CONTROLLER-Event-Signal. Konfigurieren eines Debug-GPIOs zum Schalten bei Radio-Events erlaubt die Messung von:

Messung Methode Was es offenbart
Verbindungsereignis-Start-Jitter Radio-GPIO zu GPIO-PPS-Offset messen Kristallgenauigkeit, Sleep-Timer-Drift
Verbindungsereignis-Dauer Pulsbreite des Radio-GPIO Payload-Groesse vs. Intervall-Mismatch
Scan-Window-Timing Pulsbreite des Scan-GPIO Tatsaechlicher Scan vs. konfigurierter Scan
Advertising-Intervall-Genauigkeit Periodenmessung Drift, Randomisierungskorrektheit
Inter-Event-Luecke Zeit zwischen fallender und naechster steigender Flanke Stack-Overhead, Verarbeitungszeit

### 4.2 Protokolldekodierung mit SWIRE/HCI-Sniffing

Die meisten BLE-Module routen HCI-Traffic zwischen Host und Controller intern, aber einige exponieren ihn auf einer UART- oder SPI-Schnittstelle. Das Sniffen dieses Traffics mit einem Logikanalysator-Protokolldecoder ist der schnellste Weg, um Host-Controller-Interaktionsprobleme zu debuggen:

UART HCI: Saleae Logic 2 enthaelt einen HCI-UART-Decoder, der Command Complete, Command Status, ACL-Daten und Events parst.

SPI HCI: Einige Module (CC26xx mit externem Host) verwenden 4-Draht-SPI fuer HCI.

Proprietaer: Nordics proprietaeres SWIRE ist ein Ein-Draht-Bidirektional-Protokoll.

### 4.3 Leistungsprofilerstellung mit Logikanalysator + Oszilloskop

Das haeufigste BLE-Debug-Szenario: Das Modul verbraucht mehr Strom als erwartet. Verbinden Sie einen Logikanalysator mit Schluessel-GPIOs alongside einer Strommessung (Shunt-Widerstand + Oszilloskop oder Power Profiler Kit), um Software-Events mit Stromspitzen zu korrelieren:

GPIO-Signal Was im Stromprofil zu suchen ist
Radio aktiv 4-15 mA-Spitze, sollte 1-5 ms sein
CPU aktiv 2-8 mA, sollte zwischen Events auf <10 uA fallen
Flash loeschen/schreiben 8-15 mA-Spitze, 20-50 ms pro Seite
UART TX 1-3 mA fuer die Dauer der Uebertragung
ADC-Sample 0,5-1,5 mA, kurze Spitzen bei Samplerate
Externe Sensor-Lesung (I2C/SPI) 1-5 mA je nach Sensor

Ein haeufiger Befund: Das app_timer-Modul des BLE-Stacks auf nRF52 feuert einen Software-Timer 200 μs vor dem Radio-Event und weckt die CPU fuer 1,5 ms zur Vorbereitung. Wenn die Anwendung ebenfalls einen Timer zur gleichen Zeit geplant hat, bleibt die CPU laenger wach und addiert 2-4 mA mittleren Strom.

## 5. RF-Debug: Direct Test Mode (DTM)

DTM ist die standardisierte (BT 4.2+ Vol 6, Part F) Methode zum Testen des BLE-Radios ohne den vollstaendigen Stack. Es ermoeglicht:

1. Senden eines konstanten Traegers (CW) bei spezifischer Frequenz und Leistung

2. Senden eines modulierten Signals mit PRBS9/PRBS15-Payload

3. Empfangen und Zaehlen von Paketen mit konfigurierbaren Parametern

4. Messen der Paketfehlerrate (PER) vs. RSSI

### DTM-Zugriffsmethoden

Methode Schnittstelle Befehle Typische Verwendung
2-Draht-UART RX/TX-Pins HCI herstellerspezifisch Produktionstest, Zertifizierung
3-Draht-UART RX/TX/RTS Wie 2-Draht Flusssteuerung fuer Hochratentests
HCI ueber USB USB HCI-Befehle USB-Dongle-Test
Proprietaer SWD/JTAG SoC-spezifisch SoC-Level-Debug (keine Firmware)

### DTM-Befehlsstruktur (2-Draht-UART)

DTM verwendet ein einfaches 16-Bit-Befehlswort bei 19200 bps (8N1):

Bit Feld Wert Beschreibung
15 Typ 0 Pakettyp
14-6 Laenge 0-37 Anzahl Bytes im Paket (RX) oder TX-Laenge
5-2 RF-Kanal 0-39 BLE-Kanal 0-39 (2402-2480 MHz)
1-0 Testtyp 0-3 0=PRBS9 TX, 1=PRBS15 TX, 2=PRBS9 RX, 3=CW TX

Beispiel: PRBS9 auf Kanal 19 (2440 MHz) senden, 32 Bytes:

– Befehlswort = 0b0_00001000_010011_00 = 0x044C

– Als 2 Bytes senden: 0x4C, 0x04 (Little-Endian)

// DTM-Testsequenz fuer RF-Verifizierung
void dtm_verify_rf(void) {
    // 1. TX PRBS9 auf Kanal 19, 32 Bytes
    dtm_send(0x044C);
    delay_ms(100);
    dtm_send(0x0000);  // Test beenden, Event lesen

    // 2. RX-Test auf Kanal 19
    dtm_send(0x044E);
    delay_ms(500);
    dtm_send(0x0000);
    uint16_t event = dtm_read_event();
    uint16_t pkt_count = event & 0x7FFF;
    dbg_printf("DTM RX: %d packets in 500ms
", pkt_count);
}

### DTM fuer Zertifizierungs-Pre-Compliance

Bevor Sie ein Modul an ein Zertifizierungslabor senden, verifizieren Sie, dass folgende DTM-Tests bestanden werden:

Test DTM-Befehl Bestehenskriterium Benoetigte Ausruestung
TX-Leistung (alle 40 Kan.) CW TX pro Kanal ±2 dB der Spezifikation Spektrumanalysator oder Leistungsmesser
Modulationscharakteristika PRBS15 TX Δf1avg = 225-275 kHz, Δf2avg/Δf1avg ≥ 0.8 Spektrumanalysator + Firmware
Traegerfrequenz-Offset CW TX ±50 kHz vom Nennwert Spektrumanalysator (Zaehlermodus)
In-Band-Emissionen PRBS9 TX, 1 Kan. < -20 dBm am Nachbar kanal Spektrumanalysator
20-dB-Bandbreite PRBS15 TX < 2,0 MHz Spektrumanalysator (RBW 100 kHz)
PER-Empfindlichkeit RX-Test < 30,8% PER bei -93 dBm (LE 1M) Signalgenerator + DTM RX
PER-Maximal-Eingang RX-Test < 30,8% PER bei -20 dBm Signalgenerator + DTM RX
Co-Channel-Unterdrueckung RX + Stoerer < 30,8% PER bei gewuenscht/Stoerer = +3 dB 2 Signalgeneratoren

## 6. Debug-GPIO-Strategie: Von Entwicklung zu Produktion

Ein gut entworfenes BLE-Modul sollte 2-4 GPIOs speziell fuer Debugging reservieren, deren Funktion zwischen Entwicklungs- und Produktions-Builds wechselt:

### Debug-GPIO-Zuweisungsbeispiel (nRF52832-Modul)

GPIO Entwicklungsfunktion Produktionsfunktion Hinweise
P0.31 Radio-Event-Toggle Unbenutzt (Eingang, Pull-Down) Toggle bei Radio-Start/Stopp
P0.30 Timer-Event-Toggle Unbenutzt (Eingang, Pull-Down) Toggle bei App-Timer-Feuer
P0.29 BLE-Zustandsmaschine-Zustand Unbenutzt (Eingang, Pull-Down) 3-Bit-Zustandscode (2 GPIOs)
P0.28 BLE-Zustandsmaschine-Zustand Unbenutzt (Eingang, Pull-Down) 3-Bit-Zustandscode (2 GPIOs)

Die Zustandsmaschinen-GPIOs kodieren den aktuellen BLE-Zustand als Binaerwert:

Zustandscode Bedeutung Typische Dauer
000 IDLE/Sleep 90-99% der Zeit
001 Advertising-Vorbereitung 50-100 us
010 Advertising-TX 80-376 us
011 Advertising-RX (Scan-Response) 100-200 us
100 Verbindungs-Vorbereitung 100-200 us
101 Verbindungsereignis-TX 80-200 us
110 Verbindungsereignis-RX 100-300 us
111 Flash/Verarbeitung Variabel

Dies gibt Ihnen eine Echtzeit-Zustandsmaschinen-Ansicht auf einem Logikanalysator ohne Software-Overhead — die GPIO-Schreibvorgaenge erfolgen im Interrupt-Kontext und dauern jeweils 2-3 Zyklen.

### Produktions-Debug-Pin-Strapping

In der Produktion koennen Sie sich oft keine bestueckten Debug-Header leisten. Eine haeufige Strategie ist die Verwendung von Pruefpads, die ueber Pogo-Pin-Fixture zuganglich sind:

Pad Signal Pogo-Pin-Durchmesser Hinweise
1 SWDIO 0,68 mm 0,05″-Raster, 2×5-Muster
2 SWCLK 0,68 mm
3 GND 0,68 mm 2x GND-Pads
4 VDD 0,68 mm Target-Power-Sense
5 nRESET 0,68 mm Optional
6 UART TX 0,68 mm Produktionskonsole
7 UART RX 0,68 mm Produktionskonsole
8 RF_OUT 0,68 mm Leitungsgebundener Test (ohne Antenne)

Bei Modulen mit integrierter Antenne erfordern RF-Tests entweder einen RF-Stecker (U.FL oder aehnlich) waehrend der Entwicklung oder eine Koppelungs-Vorrichtung (TEM-Zelle oder Nahfeldsonde) in der Produktion. Der Koppelungsansatz addiert ±3-5 dB Unsicherheit, was fuer Go/No-Go-Produktionstests akzeptabel ist, aber nicht fuer die Zertifizierung.

## 7. Crash-Dump und Post-Mortem-Analyse

Wenn ein BLE-Modul im Feld abstuerzt, sind die bisher besprochenen Debug-Schnittstellen nicht verfuegbar. Das Modul benoetigt einen in sich geschlossenen Crash-Dump-Mechanismus, der einen Reset ueberlebt:

### 7.1 Retained-RAM-Crash-Dump (ohne Reset)

ARM Cortex-M behaelt RAM ueber einen Soft-Reset (NVIC_SystemReset). Durch Platzieren einer Magic Number an einer bekannten RAM-Adresse kann der Bootloader einen Absturz erkennen und den gespeicherten Kontext ausgeben:

// In bekanntem RAM-Abschnitt platzieren, der Soft-Reset ueberlebt
#define CRASH_MAGIC_ADDR  0x20007FF0  // Letzte 16 Bytes RAM
#define CRASH_MAGIC       0xDEAD5F70

typedef struct {
    uint32_t magic;
    uint32_t r0, r1, r2, r3, r12, lr, pc, psr;
    uint32_t cfsr, hfsr, bfar;
    uint32_t uptime_ms;
    uint16_t conn_handle;
    uint8_t  ble_state;
    uint8_t  reserved;
} crash_dump_t;

// Im Bootloader (vor Haupt-App):
crash_dump_t *cd = (crash_dump_t *)CRASH_MAGIC_ADDR;
if (cd->magic == CRASH_MAGIC) {
    uart_dump_crash(cd);
    flash_store_crash(cd);
    cd->magic = 0;  // Loeschen, damit nicht erneut ausgegeben wird
}

### 7.2 Flash-basiertes Crash-Log

Fuer Module, die die Stromversorgung verlieren koennen, bevor der Crash-Dump abgerufen wird, speichern Sie Crash-Daten auf einer dedizierten Flash-Seite. Verwenden Sie ein zirkulaeres Log mit einem Eintrag pro Absturz:

Feld Groesse Beschreibung
Magic 4 B 0xDEAD5F70
Reset-Ursache 4 B RCU-Reset-Register
Gestapelte Register 32 B R0-R3, R12, LR, PC, xPSR
CFSR/HFSR/BFAR 12 B Fault-Status-Register
Uptime 4 B ms seit Boot
Verbindungs-Handle 2 B Aktives Handle (0xFFFF = keins)
BLE-Zustand 1 B Zustand bei Absturz
Reserviert 1 B Ausrichtung
CRC16 2 B Integritaetspruefung
Total 62 B Passt in eine Flash-Schreibeinheit

Mit einer 4-KB-Flash-Seite koennen Sie 65 Crash-Eintraege speichern. In der Praxis reichen 10-20 Eintraege.

### 7.3 Watchdog-Timeout-Analyse

Der frustrierendste Absturztyp: Der Watchdog feuert, aber es gibt keinen HardFault, sodass der Crash-Dump leer ist. Zur Diagnose von Watchdog-Timeouts:

1. Timer-ISR-Snapshot: In der Watchdog-Feed-Funktion den aktuellen Call-Stack (LR-Wert) an einer Retained-RAM-Stelle speichern.

2. Periodisches Heartbeat-Log: Schreiben Sie alle 30 Sekunden einen mit Zeitstempel versehenen Heartbeat auf Flash.

3. Watchdog-Vorwarnung: Konfigurieren Sie den Watchdog so, dass er 500 ms vor dem tatsaechlichen Reset einen Fruehwarn-Interrupt ausloest:

void WDT_IRQHandler(void) {
    // Fruehwarnung — 500ms vor Reset
    uint32_t *sp;
    __asm volatile("mrs %0, psp" : "=r"(sp));
    crash_dump_t *cd = (crash_dump_t *)CRASH_MAGIC_ADDR;
    cd->magic = CRASH_MAGIC;
    cd->pc = sp[6];
    cd->lr = sp[5];
    cd->cfsr = SCB->CFSR;
    cd->uptime_ms = system_uptime();
    cd->ble_state = ble_get_state();
    while(1);
}

## 8. Debug-Sicherheit: Lock Bits, Secure Debug und Produktions-Hardening

Debug-Schnittstellen sind ein Sicherheitsrisiko. Ein bestueckter SWD-Header auf einem Produktionsmodul bedeutet, dass jeder mit einer 10-Dollar-CMSIS-DAP-Sonde Ihre Firmware lesen, Schluessel extrahieren und Ihr Modul klonen kann. Defense-in-Depth-Ansatz:

### 8.1 Lock-Bit-Level

Schutzlevel Mechanismus Was blockiert wird Wiederherstellung
Level 0 (offen) Keiner Nichts N/A
Level 1 (Flash gesperrt) APPROTECT-Register SWD-Lesen/Schreiben von Flash/RAM Voll-Loeschen zum Entsperren
Level 2 (permanent) Fuse/OTP-Bit Alle Debug-Zugriffe, permanent Keine — irreversibel

Fuer nRF52 aktiviert UICR.APPROTECT = 0xFFFFFF00 Level 1. Die Debug-Sonde kann verbinden, aber Flash nicht lesen — nur Voll-Loeschen. Level 2 ist auf einigen SoCs verfuegbar (ESP32-C3 efuse brennen, STM32 RDP Level 2) und deaktiviert Debug-Zugriff permanent.

### 8.2 Secure Debug (authentifiziertes Debuggen)

Einige SoCs (nRF5340, CC2640R2 mit Secure Bootloader) unterstuetzen authentifiziertes Debuggen, bei dem die Debug-Sonde eine kryptografische Challenge-Response praesentieren muss:

// nRF5340 Network Core: Secure-Debug-Challenge
typedef struct {
    uint8_t  challenge[16];   // Zufaellige Nonce vom Target
    uint8_t  signature[64];   // ECDSA-P256-Signatur vom Debug-Zertifikat
    uint32_t cert_id;         // Welches Debug-Zertifikat verwenden
} secure_debug_auth_t;

Dies ermoeglicht Debug-Zugriff im Feld (fuer autorisiertes Servicepersonal), ohne die Modulsicherheit permanent zu kompromittieren.

### 8.3 Produktions-Debug-Strategie

Phase APPROTECT UART-Konsole Debug-GPIOs DTM
Bring-up (EVT) Off On, 460800 Alle bestueckt Ueber SWD
Verifizierung (DVT) Off On, 115200 Alle bestueckt Ueber SWD
Pilot (PVT) Level 1 On, 115200 (Pruefpad) Nur 2 Signal-Pads Ueber Fixture
Massenproduktion Level 1 Off (Pruefpad fuer Fehler) Keine Nur Fixture
Feld-Rueckgabe Level 1 Rework zum Aktivieren Rework Rework

Schlussprinzip: Jede nicht in der Produktion benoetigte Schnittstelle sollte entweder unbestueckt (Header), deaktiviert (UART via Kompilier-Flag) oder geschuetzt (SWD via APPROTECT) sein.

## 9. Haeufige Debug-Architekturfehler

Fehler Auswirkung Korrektur
Kein SWD-Pull-up auf SWDIO Intermittierende Sondenverbindung, zufaelliges „DP read failed“ Externen 4,7-10 kΩ Pull-up hinzufuegen
UART TX auf gleichem Pin wie BLE-Stack-DCX Verkorrupte Radio-Konfiguration, zufaellige Verbindungsabbrueche UART auf sicheren Pin verschieben
RTT-Puffer in nicht-retained RAM RTT-Daten nach Sleep/Wake verloren RTT-Puffer in Retained-RAM-Abschnitt
printf in Radio-ISR 2+ ms ISR-Latenz, Paketverlust RTT verwenden oder auf Idle-Task verschieben
Kein Crash-Dump in Retained RAM Keine Diagnosedaten nach Reset Crash-Dump aus Abschnitt 7.1 implementieren
Debug-GPIOs in Produktion aktiv Zusaetzlicher Strom, 50-200 uA pro floatendem Eingang In Produktions-Build als Pull-Down-Eingang konfigurieren
DTM nicht ohne vollstaendiges Firmware-Flash zugaenglich RF-Test ohne App-Loeschung nicht moeglich Bootloader prueft DTM-Pin-Strap beim Boot
APPROTECT in Versand-Firmware nicht gesetzt Firmware mit 10-Dollar-Sonde extrahierbar UICR.APPROTECT im Produktions-Flash-Skript setzen
UART-Baud zu hoch fuer BLE-Stack Zeichenverlust waehrend Verbindungsereignissen DMA-TX verwenden oder auf 115200 mit 16-Byte-FIFO beschraenken
Keine Watchdog-Vorwarnung-ISR WDT-Timeouts nicht diagnostizierbar WDT-Fruehwarn-Interrupt 500ms vor Reset aktivieren

## 10. Debug-Schnittstellen-Checkliste fuer neues Moduldesign

Bevor Sie ein BLE-Modul-PCB fertigen, verifizieren Sie:

– [ ] SWD-Pads (SWDIO, SWCLK, nRESET, VDD, GND) als 0,05″-Mikro-Header oder Pruefpads zugaenglich

– [ ] SWDIO hat 4,7-10 kΩ externen Pull-up (nicht auf internen vertrauen)

– [ ] UART TX/RX auf sicheren Pins (kein Konflikt mit Kristall, NFC, BLE-Stack)

– [ ] UART DMA-TX konfiguriert, Ringpuffer RX

– [ ] Kompilierzeit-Log-Level-Flags (DBG_ERROR/WARN/INFO/DEBUG/VERBOSE)

– [ ] 2-4 Debug-GPIOs zugewiesen, via Kompilier-Flag konfigurierbar

– [ ] HardFault-Handler gibt gestapelte Register auf Retained RAM + UART aus

– [ ] Crash-Dump-Magic-Number in Retained RAM, Bootloader prueft beim Boot

– [ ] Flash-Crash-Log (zirkulaer, 10-20 Eintraege)

– [ ] Watchdog-Vorwarnung-ISR mit Stack-Snapshot

– [ ] DTM ueber 2-Draht-UART zugaenglich (Pruefpads in Produktion)

– [ ] RF-Testpad oder U.FL-Stecker fuer leitungsgebundene DTM-Tests

– [ ] APPROTECT-Einstellung im Produktions-Flash-Skript

– [ ] Produktions-Firmware kompiliert nur mit DBG_INFO (kein DEBUG/VERBOSE)

– [ ] Debug-GPIOs als Pull-Down-Eingang in Produktions-Build konfiguriert

## Zusammenfassung

Debug-Schnittstellen-Design ist kein Nachgedanke — es ist eine erstklassige Engineering-Disziplin, die bestimmt, wie schnell Sie Feldfehler diagnostizieren, Zertifizierungen bestehen und Firmware iterieren koennen. Die Investition ist bescheiden: 2-4 zusaetzliche GPIOs, eine 5-Pad-SWD-Flaeche, ein Retained-RAM-Crash-Dump-Handler und ein DTM-Boot-Modus. Die Rendkehr misst sich in Wochen, die beim Bring-up gespart werden, und Tausenden von Dollar, die durch Vermeidung von Feldrueckgabe-Raterei gespart werden. Bei Ihrem naechsten Bluetooth-Modul-Design sollten Sie diese Schnittstellen ab dem Schaltplan-Review budgetieren, nicht ab dem ersten Fehlerbericht.