Präzise PWM-Phasensteuerung auf STM32: Hardwaremethoden ohne Verluste
STM32-Mikrocontroller verfügen über kein direktes Register zur Anpassung der Phase von Hardware-PWM-Signalen. Dieses Problem ist entscheidend bei der Synchronisation mehrerer Kanäle in Aufgaben, die strenge Timing-Verschiebungen erfordern. Wir zeigen Ihnen, wie Sie eine präzise Phasensteuerung mit minimalem Einfluss auf die Leistung und ohne Software-Emulation umsetzen.
Warum PWM-Phase anpassen?
Hardware-PWM auf STM32 erleichtert die Einstellung von Frequenz und Tastverhältnis, doch Standardbibliotheken bieten keine direkte Möglichkeit, die Phase zu verschieben. Diese Einschränkung wird in folgenden Szenarien kritisch:
- Emulation eines Quadraturencoders mit zwei PWM-Signalen und fester Verschiebung
- Erzeugung von Sin/Cos-Paaren für Quadraturmischer (90°-Verschiebung)
- Steuerung von dreiphasigen BLDC-Motoren (120°-Verschiebung zwischen Kanälen)
- Synchronisation von Benzin-Einspritzdüsen oder Zündspulen in Verbrennungsmotoren
- Erzeugung von LO-Signalen in SDR-Empfängern
- Reduzierung von EMI durch künstliches Versetzen der Phasen in Stromkreisen
Ohne Hardware-Synchronisation bestimmen zufällige Faktoren die Signalphasen: Timer-Initialisierungszeit, Code-Ausführungsgeschwindigkeit, Bus-Frequenz. Das macht eine vorhersehbare Synchronisation unmöglich.
Theoretische Grundlage: Master-Slave-Architektur
Die zentrale Idee besteht darin, einen Timer (Master) als Referenz-Synchronisationsquelle für einen anderen (Slave) zu nutzen. Die Phase des Slave-Timers wird über den Vergleichswert des Master-Timers angepasst. Wenn dieser Wert erreicht wird, wird der Zähler des Slave-Timers zurückgesetzt und schafft so die gewünschte Timing-Verschiebung.

Wichtig zu verstehen: Die Phase wird in relativen Einheiten gemessen:
- 0° — in Phase
- 180° — antiphase
- 360° — volle Periode (äquivalent zu 0°)
Die Genauigkeit der Verschiebung hängt von der Auflösung des Timers ab. Bei einer Periode von 1 ms und 84 MHz Bus-Takt kann der Fehler auf 11,9 ns (1/84e6) sinken.
Praktische Umsetzungsmethoden
Methode 0: Polaritätsumkehrung (180°-Verschiebung)
Der einfachste Ansatz ist das Umschalten des CCxP-Bits im TIMx_CCER-Register. Dies ist eine atomare Operation ohne zusätzliche Ressourcen. Der Nachteil: Nur zwei feste Zustände (0° und 180°). Geeignet für BPSK-Modulation, löst aber nicht das Bedürfnis nach stufenloser Anpassung.
Methode 1: Software-Zähleranpassung
Der naive Ansatz schreibt direkt in das CNT-Register des Slave-Timers:
bool pwm_phase_set_counter_adjust(uint8_t num, int32_t phase_us) {
bool res = false;
PwmHandle_t *Node = PwmGetNode(num);
if(Node) {
int32_t compare_value = TimerPhaseUsToCompareValue(Node->PhaseComparator.timer, phase_us);
int32_t counter_base = (int32_t) timer_counter_get(Node->PhaseComparator.timer);
int32_t value = counter_base + compare_value;
res = timer_counter_set(Node->TimChan.timer, (uint32_t) value);
}
return res;
}
Diese Methode weist bei 1 kHz einen Fehler von bis zu 3 µs (0,29 %) aufgrund der Code-Ausführungszeit auf. Hauptprobleme:
- Erfordert Anhalten des Timers beim Schreiben
- Stört die Signalintegrität im Korrekturmoment
- Belastet die CPU mit Interrupts
Methode 2: Hardware-Synchronisation über Master-Slave
Die optimale Lösung nutzt den integrierten Timer-Synchronisationsmechanismus. Die Einrichtung umfasst:
- Master-Timer (TIM8) im Trigger-Generierungsmodus bei OC1-Vergleichsübereinstimmung konfigurieren (TIM_TRGO_OC1)
- Slave-Timer (TIM4) auf Zurücksetzen bei internem Trigger einstellen (TIM_TS_ITR3)
- Slave-Modus auf Zurücksetzen setzen (TIM_SLAVEMODE_RESET)
HAL-Konfiguration sieht so aus:
const TimerConfig_t TimerConfig[] = {
{
.num = TIMER_NUM_LO_BASE,
.role = TIMER_ROLE_MASTER,
.master_out_trigger = TIMER_MASTER_OUT_TRG_OC1,
},
{
.num = TIMER_NUM_LO,
.role = TIMER_ROLE_SLAVE,
.slave_input_trigger = TIMER_SLAVE_IN_TRIG_INTERNAL_TRIGGER_3,
.slave_mode = TIMER_SLAVE_MODE_RESET,
},
};
Vorteile der Methode:
- Vollständige Hardware-Umsetzung ohne Interrupts
- Verschiebegenauigkeit bis zum Bus-Taktzyklus (11,9 ns bei 84 MHz)
- Keine Glitches im Ausgangssignal bei dynamischer Anpassung
- Minimale CPU-Belastung (nur Schreiben in das Vergleichsregister des Master-Timers)
Einschränkungen:
- Erfordert ein Timer-Paar mit Master-Slave-Verbindung
- Maximal 4 Slave-Timer pro Master (aufgrund der Anzahl von Komparatoren)
- Einige Timer (6,7,10,11,13,14) unterstützen keinen Slave-Modus
Phasenfehlerdiagnose mit Logikanalysator
Die Überprüfung der korrekten Einrichtung erfolgt mit Oszilloskop oder Logikanalysator. Zum Testen:
- Master-Timer (TIM8_CH1) auf 1 kHz, 50 % Tastverhältnis einstellen
- Slave-Timer (TIM4_CH2) mit 90°-Phasenverschiebung einstellen
- Sonden an die entsprechenden Pins anschließen
Erwartetes Ergebnis:
- Bei null Verschiebung stimmt die steigende Flanke des Master-Signals mit dem Periodenstart des Slaves überein
- Bei 90°-Verschiebung für eine 1-ms-Periode ist das Slave-Signal um 250 µs versetzt

Wichtiger Punkt: Der Fehler wird in Bus-Taktzyklen gemessen. Für STM32F407 bei 84 MHz Bus beträgt der minimale Schritt 11,9 ns. In der Praxis bei 1 kHz ergibt das 0,012 % Genauigkeit.
Wichtige Erkenntnisse
- Methodenauswahl hängt von Genauigkeitsanforderungen ab: Für 0,01 % Fehler Hardware-Synchronisation nutzen; für 0,3 % ist Software-Anpassung akzeptabel
- Timer-Kompatibilität prüfen: Nicht alle Paare unterstützen Master-Slave-Verbindung (siehe Tabelle in RM0090)
- Timer-Anhalten vermeiden: Hardware-Methode unterbricht die Signalerzeugung bei Phasenänderungen nicht
- Grenzen des Slave-Geräts beachten: Ein Master kann maximal 4 Slave-Timer verbinden
- Phase mit Oszilloskop diagnostizieren: Visuelle Überprüfung ist für kritische Systeme obligatorisch
— Editorial Team
Noch keine Kommentare.