# Precyzyjna kontrola fazy PWM na STM32: sprzętowe metody bez strat
Na mikrokontrolerach STM32 brakuje bezpośredniego rejestru do regulacji fazy sprzętowego sygnału PWM. Ten problem jest krytyczny przy synchronizacji wielu kanałów w zadaniach wymagających ścisłego przesunięcia czasowego. Wyjaśniamy, jak zaimplementować precyzyjną kontrolę fazy z minimalnym wpływem na wydajność i bez programowej emulacji.
Po co regulować fazę PWM?
Sprzętowy PWM na STM32 pozwala łatwo konfigurować częstotliwość i wypełnienie, ale standardowe biblioteki nie oferują bezpośredniego sposobu przesuwania fazy. To ograniczenie staje się krytyczne w następujących scenariuszach:
- Emulacja enkodera kwadraturowego za pomocą dwóch sygnałów PWM z ustalonym przesunięciem
- Generowanie pary sin/cos dla mikserów kwadraturowych (przesunięcie 90°)
- Sterowanie trójfazowymi silnikami BLDC (przesunięcie 120° między kanałami)
- Synchronizacja wtryskiwaczy benzynowych lub świec zapłonowych w silnikach spalinowych
- Generowanie sygnału LO w odbiornikach SDR
- Redukcja EMI dzięki sztucznemu rozstrojeniu faz w obwodach mocy
Bez sprzętowej synchronizacji faza sygnałów zależy od losowych czynników: czasu inicjalizacji timerów, szybkości wykonywania kodu, częstotliwości magistrali. To uniemożliwia przewidywalną synchronizację.
Podstawa teoretyczna: architektura master-slave
Kluczowy pomysł polega na użyciu jednego timera (master) jako źródła synchronizacji dla drugiego (slave). Faza slave-timera jest regulowana poprzez wartość komparatora master-timera. Po osiągnięciu tej wartości licznik slave-timera jest resetowany, tworząc zadane przesunięcie czasowe.

Ważne jest zrozumienie, że faza jest mierzona w jednostkach względnych:
- 0° — sygnały w fazie
- 180° — antyfaza
- 360° — pełny okres (równoważny 0°)
Dokładność przesunięcia zależy od rozdzielczości timera. Dla okresu 1 ms i taktowania magistrali 84 MHz błąd może wynosić 11,9 ns (1/84e6).
Praktyczne metody implementacji
Metoda 0: Odwrócenie polaryzności (przesunięcie 180°)
Najprostszy sposób to zmiana bitu CCxP w rejestrze TIMx_CCER. Jest to operacja atomowa, nie wymagająca dodatkowych zasobów. Wadą jest tylko dwa stałe stany (0° i 180°). Nadaje się do modulacji BPSK, ale nie rozwiązuje problemu płynnej regulacji.
Metoda 1: Programowa korekta licznika
Naiwne podejście zakłada bezpośredni zapis do rejestru CNT slave-timera:
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;
}
Ta metoda daje błąd do 3 µs przy częstotliwości 1 kHz (0,29%) z powodu czasu wykonywania kodu. Główne wady:
- Wymaga zatrzymania timera podczas zapisu
- Narusza ciągłość sygnału w momencie korekty
- Obciąża CPU przerwaniem
Metoda 2: Sprzętowa synchronizacja przez master-slave
Optymalne rozwiązanie to wykorzystanie wbudowanego mechanizmu synchronizacji timerów. Konfiguracja obejmuje:
- Konfigurację master-timera (TIM8) w trybie generowania wyzwalacza po zgodzie komparatora OC1 (TIM_TRGO_OC1)
- Ustawienie slave-timera (TIM4) na reset po wewnętrznym wyzwalaczu (TIM_TS_ITR3)
- Ustawienie trybu slave na reset (TIM_SLAVEMODE_RESET)
Konfiguracja przez HAL wygląda następująco:
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,
},
};
Zalety metody:
- Całkowicie sprzętowa realizacja bez przerwań
- Dokładność przesunięcia do taktu magistrali (11,9 ns przy 84 MHz)
- Brak zakłóceń w sygnale wyjściowym przy dynamicznej konfiguracji
- Minimalne obciążenie CPU (tylko zapis do rejestru komparatora master-timera)
Ograniczenia:
- Wymaga pary timerów z obsługą połączenia master-slave
- Maksymalnie 4 slave-timery na jeden master (ze względu na liczbę komparatorów)
- Niektóre timery (6,7,10,11,13,14) nie obsługują trybu slave
Diagnostyka fazy za pomocą analizatora logicznego
Sprawdzanie poprawności konfiguracji przeprowadza się oscyloskopem lub analizatorem logicznym. Do testu:
- Ustaw master-timer (TIM8_CH1) na 1 kHz, 50% wypełnienia
- Ustaw slave-timer (TIM4_CH2) z przesunięciem fazy 90°
- Podłącz sondy do odpowiednich pinów
Oczekiwany rezultat:
- Przy zerowym przesunięciu front sygnału master pokrywa się z początkiem okresu slave
- Przy przesunięciu 90° dla okresu 1 ms sygnał slave jest przesunięty o 250 µs

Kluczowy aspekt: błąd mierzy się w taktach magistrali. Dla STM32F407 z magistralą 84 MHz minimalny krok wynosi 11,9 ns. W praktyce przy 1 kHz daje to dokładność 0,012%.
Co ważne
- Wybór metody zależy od wymagań dokładności: dla błędu 0,01% używaj synchronizacji sprzętowej, dla 0,3% wystarczy programowa korekta
- Sprawdzaj kompatybilność timerów: nie wszystkie pary obsługują połączenie master-slave (zob. tabela w RM0090)
- Unikaj zatrzymywania timerów: metoda sprzętowa nie przerywa generacji sygnału przy zmianie fazy
- Pamiętaj o ograniczeniu slave-urządzeń: do jednego mastera można podłączyć maksymalnie 4 slave-timery
- Diagnostykuj fazę oscyloskopem: wizualna weryfikacja jest obowiązkowa przy konfiguracji systemów krytycznych
— Editorial Team
Brak komentarzy.