FPGA ile PWM Sinyali Üretimi

PWM (Pulse Witdh Modulation) yani Darbe Genişlik Modülasyonu, \(\frac{\mathbf{t}_\mathbf{h}}{\mathbf{T}}\) oranının değiştirilebildiği sinyal modülasyondur. \(\frac{\mathbf{t}_\mathbf{h}}{\mathbf{T}}\) oranı Duty Cycle olarak adlandırılır ve \(\%\) ile ifade edilir. Aşağıda bir PWM sinyali görülmektedir.

\(M\) ortalama değer olmak üzere duty cycle oranının değişmesi ile sinyalin ortalama değeri değişir:

\(\begin{align*}M=\frac{1}{\mathit{T}}\int_0^\mathit{T}f(t)\,dt\end{align*}\)

\(\begin{align*}M=\frac{1}{\mathit{T}}\bigg[\int_0^\mathit{D}f(t)\,dt+\int_\mathit{D}^\mathit{T}f(t)\,dt\bigg]\end{align*}\)

\(\begin{align*}M=\frac{1}{\mathit{T}}\bigg[\int_0^\mathit{D}(0)\,dt+\int_\mathit{D}^\mathit{T}(1)\,dt\bigg]\end{align*}\)

\(\begin{align*}M=\frac{1}{\mathit{T}}\bigg[\mathit{T}-\mathit{D}\bigg]\end{align*}\)

\(\begin{align*}M=1-\frac{\mathit{D}}{\mathit{T}}=\mathit{Duty}\end{align*}\)

Bu sayede sinyalin gerilimini değiştirmeden yük üzerinde harcanan ortalama güç ayarlanmış olur.

FPGA üzerinde PWM sinyal üretebilmek için \(A\) ve \(B\) kontrol değişkenlerimiz olsun. Bu \(A\) ve \(B\) değişkenleri aşağıdaki gibi tanımlanmış olsun:

Tasarımın VHDL kodu:


--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity PWM_Module is
    port(Clk : in std_logic;                        --Clk Girişi
        A, B : in std_logic_vector(15 downto 0);     --Kontrol Girişleri
                                                     --PWM Frekansı = Clk / A
                                                                    --Duty Cycle = 1 - B / A
        PWMOut : out std_logic);                     --PWM Çıkışı
end PWM_Module;

architecture Behavioral of PWM_Module is
    
begin

    --PWM Sinyalinin Üretildiği Process
    process(Clk, A, B)
    variable ClkCnt : unsigned(15 downto 0) := (others => '0');
    begin
        if rising_edge(Clk) then
            --ClkCnt, A'dan küçük ise ClkCnt değerini 1 arttır
            if ClkCnt < unsigned(A) then                 ClkCnt := ClkCnt + 1;             --Değil ise sıfırla             else                 ClkCnt := (others => '0');
            end if;
        end if;
        
        --ClkCnt, B'den küçük ise PWMOut'a '0' ata
        if ClkCnt < unsigned(B) then
            PWMOut <= '0';
        --Değil ise '1' ata
        else
            PWMOut <= '1';
        end if;
    end process;

end Behavioral;

Quartus II programı tarafından oluşturulan RTL şeması:

PWM ile Led Parlaklık Kontrolü

VHDL kodu:

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity PWM_Led is
    port(Clk : in std_logic;                        --Clk Girişi
        Led : out std_logic_vector(15 downto 0));    --Led çıkışı
end PWM_Led;

architecture Behavioral of PWM_Led is
    
--PWM komponentinin çağrılması
component PWM_Module
    port(Clk : in std_logic;                        --Clk Girişi
        A, B : in std_logic_vector(15 downto 0);     --Kontrol Girişleri
                                                     --PWM Frekansı = Clk / A
                                                                    --Duty Cycle = 1 - B / A
        PWMOut : out std_logic);                     --PWM Çıkışı
end component;    

    signal PWMOut : std_logic;
    signal B : std_logic_vector(15 downto 0) := (others => '0');
    
begin

    --PWM komponenti
    --PWM freknası 50Mhz / 0x01F4 = 100khz
    PWM : PWM_Module
        port map(Clk, X"01F4", B, PWMOut);
        
    process(Clk)
    variable ClkCnt : integer range 0 to 250000 := 0;
    variable YukariAsagi : boolean := true;
    begin
    
        --100khz çıkışlı clock bölücü
        if rising_edge(Clk) then
            if ClkCnt < 249999 then
                ClkCnt := ClkCnt + 1;
            else
                ClkCnt := 0;
                
                --YukarıAsagi değişkeni true ise B sinyalinin değerini 1 arttır
                if YukariAsagi then
                    B <= std_logic_vector(unsigned(B) + 1);
                
                --False ise 1 azalt
                else
                    B <= std_logic_vector(unsigned(B) - 1);                 end if;             end if;                          --Duty cycle %10 ile %80 arasında değişmekte             if unsigned(B) > 449 then
                YukariAsagi := false;
            elsif unsigned(B) < 101 then
                YukariAsagi := true;
            end if;
            
        end if;
    end process;
    
    --Bütün ledleri PWMOut sinyaline bağla
    Leds : for i in 0 to 15 generate
        Led(i) <= PWMOut;
    end generate;
    

end Behavioral;

Video:

2 thoughts on “FPGA ile PWM Sinyali Üretimi

  1. Sanırım bölümün elektronik haberleme 🙂 FPGA eğitimine nereden nasık başladın bu konuda bilgi verebilir misin ?

    1. Bölümüm Elektrik-Elektronik. FPGA'ya uzun zamandır başlamak istemişimdir. Kitlerin fiyatlarında dolayı bu yılın başında ilk FPGA kitimi alabildim. Kiti aldığımdan beri çeşitli projeler yaparak kendimi geliştiriyorum.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir