Verilog: PWM z korekcją fazy

W poprzednim artykule przedstawiłem generator PWM prosty. Prostota jest bez wątpienia jego największą zaletą, jednak ma pewną bardzo istotną wadę, która wyklucza jego zastosowanie w wielu przypadkach.

Wyobraźmy sobie, że mamy trzy odbiorniki (co wcale nie jest dużą liczbą) sterowane PWM-em prostym, tak jak na rysunku poniżej. Niech to będą silniki DC sterowane tranzystorami MOSFET. Wszystkie trzy tranzystory otwierają się w tej samej chwili, co powoduje przepływ prądu przez uzwojenia silników, a następnie po upływie pewnego czasu tranzystory się zamykają i prąd przestaje płynąć. Gdzie jest haczyk? Problem jest w tym, że wszystkie MOSFET-y otwierają się jednocześnie, co powoduje bardzo duży i nagły pobór prądu. To z kolei może powodować chwilowe spadki napięcia zasilającego, co zakłóci działanie pozostałych układów. Nie bez powodu mówi się, że PWM "sieje zakłóceniami".

PWM bez korekcji fazy

Zakłócenia można znacznie zredukować, jeżeli wyjściowe przebiegi PWM poprzesuwamy w taki sposób, by w jednej chwili można było otworzyć tylko jeden tranzystor.

PWM z korekcją fazy

W generatorze PWM z korekcją fazy, licznik sterujący liczy naprzemiennie w górę i w dół. Gdy wartość graniczna (ustalająca wypełnienie) zrówna się z wartością licznika, wtedy następuje przełączenie stanu wyjścia PWM na przeciwny.

Implementacja w FPGA

W przykładowym projekcie zrobimy cztery generatory PWM zgodnofazowe, sterowane jednym licznikiem. Powstaną zatem dwa pliki z modułami. Pierwszy zawiera sam generator PWM. Drugi z nich zawiera licznik sterujący oraz cztery instancje generatorów z pierwszego pliku. 

 
// PLIK PWM.V
 
module pwm(
    input clk,
    input dir,
    input [7:0] licznik,
    input [7:0] granica,
    output reg wyjscie = 0
);

    // generator pwm
    always @(posedge clk)    
        if(licznik == granica)
            if(!dir)
                wyjscie = 1;
            else
                wyjscie = 0;
            
endmodule 
 

Oto drugi plik z modułem nadrzędnym:

 
// PLIK TOP.V
 
module generatory(
    input clk,
    input [7:0] granica1, granica2, granica3, granica4,
    output wyjscie1, wyjscie2, wyjscie3, wyjscie4
);
    
    // licznik sterujący 
    reg [7:0] licznik = 0;       // licznik sterujący
    reg dir = 0;                 // kierunek liczenia
    always @(posedge clk)
        begin
        
        // zliczanie w górę lub w dół
        if(!dir)
            licznik = licznik + 1;
        else
            licznik = licznik - 1;
            
        // zmiana kierunku liczenia
        if(licznik == 8'hFF || licznik == 8'h00)
            dir = ~dir;
        
        end
    
    // instancje generatorów
    pwm generator1(clk, dir, licznik, granica1, wyjscie1);
    pwm generator2(clk, dir, licznik, granica2, wyjscie2);
    pwm generator3(clk, dir, licznik, granica3, wyjscie3);
    pwm generator4(clk, dir, licznik, granica4, wyjscie4);

endmodule 
 

I na koniec prosta procedura testowa:

 
// PLIK TOP_TB.V
  
`timescale 1 us / 1 ns

module top_tb;
    
    reg clk;
    reg [7:0] we1, we2, we3, we4;
    wire wy1, wy2, wy3, wy4;
    
    // instancja
    generatory generatory_tb(
        clk,
        we1, we2, we3, we4,
        wy1, wy2, wy3, wy4
    );
    
    always
        begin
        #1 clk = ~clk;
        end
        
    initial
        begin
        clk = 0;
        we1 = 8'h20;
        we2 = 8'h40;
        we3 = 8'h80;
        we4 = 8'hE0;  
        #150000 $finish;
        end
    
endmodule 
 

Po przeprowadzeniu symulacji powinniśmy uzyskać taki obrazek.

PWM korekta fazy symulacja

I na koniec jeszcze zdjęcie z osculoskopu, na dowód, że to rzeczywiście działa :)

PWM zgodnofazowy wykresy z oscyloskopu