Maciej
G.
Projektant /
Programista, Famor
S.A.
Temat: Sterownik rolet na CPLD/FPGA
Witam wszystkich,czy mógłbym prosić o sprawdzenie poprawności całego projektu (pewnie skończy się tym, iż odpowie mi Jakub). Wrzucam ten projekt w całości bo może się przyda w przyszłości komuś, kto będzie próbował zbudować coś podobnego (czyli sterowanie silnikiem DC do np. otwierania rolet).
Oto główny plik - projekt (opis sygnałów najlepiej zobaczyć w pliku DASM.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Project is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
b1 : in STD_LOGIC;--button zamykaj
b2 : in STD_LOGIC;--button otwieraj
krancEND : in STD_LOGIC;--wyłącznik krancow
krancPOC : in STD_LOGIC;--wyłącznik krancow
OVVERIDE : in STD_LOGIC;--z komparatora (za duży prąd płynie przez silnik)
DIRPIN : inout STD_LOGIC;
SLPPIN : out STD_LOGIC;
SAWARIA : out STD_LOGIC;
LEDOTWARTE : out STD_LOGIC;
LEDZAMKNIETE : out STD_LOGIC;
LEDPRACA : out STD_LOGIC;
LEDAWARIA : out STD_LOGIC;
pwm : out STD_LOGIC_VECTOR (0 downto 0));--wyjscie pwm na mostek MOSFET
end Project;
architecture Behavioral of Project is
component divider is
Port ( clk : in STD_LOGIC;
clk_out : inout STD_LOGIC := '0');--clk_out 1MHZ
end component;
component debounce1 is
port ( clk : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
end component;
component debounce2 is
port ( clk : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
end component;
component DMASM is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
bt1 : in STD_LOGIC;--btn zamykanie
bt2 : in STD_LOGIC;--btn otwieranie
krancEND : in STD_LOGIC;--active 0
krancPOC : in STD_LOGIC;--active 0
OVERRIDE : in STD_LOGIC;--active 0 (przeciazenie silnika)
DIRPIN : out STD_LOGIC;--Direction Motor ( 0 - FORWARD)
SLPPIN : out STD_LOGIC;--SLEEP PIN Mostek (0 - mostek zablokowany)
pb1_Zam : out STD_LOGIC;--gdy 0 zamykanie
pb2_Otw : out STD_LOGIC;--gdy 0 otwieranie
AWARIA : out STD_LOGIC;--gdy 0 awaria ukladu
LEDZAMKNIETE : out STD_LOGIC;--gdy 1 LED zamkniete
LEDOTWARTE : out STD_LOGIC;--gdy 1 LED otwarte
LEDPRACA : out STD_LOGIC;--gdy 1 LED Zamykanie/otwieranie
LEDAWARIA : out STD_LOGIC);--gdy 1 LED awaria;
end component;
component WEKTORY1_WYPELNIEN is
port ( clk :in std_logic;
pushB :in std_logic;
data : out std_logic_vector(7 downto 0) );
end component;
component WEKTORY2_WYPELNIEN is
port ( clk :in std_logic;
pushB :in std_logic;
data : out std_logic_vector(7 downto 0) );
end component;
component pwm1 is
Port ( clk : in STD_LOGIC;
reset_n : in STD_LOGIC;
ena : in STD_LOGIC;
duty : in STD_LOGIC_VECTOR (7 downto 0);
pwm_out : out STD_LOGIC_VECTOR (0 downto 0);
pwm_n_out : out STD_LOGIC_VECTOR (0 downto 0));
end component;
component pwm2 is
Port ( clk : in STD_LOGIC;
reset_n : in STD_LOGIC;
ena : in STD_LOGIC;
duty : in STD_LOGIC_VECTOR (7 downto 0);
pwm_out : out STD_LOGIC_VECTOR (0 downto 0);
pwm_n_out : out STD_LOGIC_VECTOR (0 downto 0));
end component;
component multiplexer1 is
Port ( SEL : in STD_LOGIC;--tu sygnal DIRPIN
pwm1 : in STD_LOGIC_VECTOR (0 downto 0);
pwm2 : in STD_LOGIC_VECTOR (0 downto 0);
pwm : out STD_LOGIC_VECTOR (0 downto 0));
end component;
signal data1_signal :STD_LOGIC_VECTOR (7 downto 0);
signal data2_signal :STD_LOGIC_VECTOR (7 downto 0);
signal b1_DB :STD_LOGIC;
signal b2_DB :STD_LOGIC;
signal clk_1MHz :STD_LOGIC;
signal pwm1_out :STD_LOGIC_VECTOR (0 downto 0);
signal pwm2_out :STD_LOGIC_VECTOR (0 downto 0);
signal pwm1_n_out :STD_LOGIC_VECTOR (0 downto 0);
signal pwm2_n_out :STD_LOGIC_VECTOR (0 downto 0);
--signal pwm :STD_LOGIC_VECTOR (0 downto 0);
signal OVERRIDE :STD_LOGIC;
signal pb1_Zam :STD_LOGIC;
signal pb2_Otw :STD_LOGIC;
signal AWARIA :STD_LOGIC;
begin
C1: divider port map (CLK, clk_1MHz);
C2: debounce1 port map (clk_1MHz, b1, b1_DB);
C3: debounce2 port map (clk_1MHz, b2, b2_DB);
C4: DMASM port map (clk_1MHz,
RST,
b1_DB,
b2_DB,
krancEND,
krancPOC,
OVERRIDE,
DIRPIN,
SLPPIN,
pb1_Zam,
pb2_Otw,
AWARIA,
LEDZAMKNIETE,
LEDOTWARTE,
LEDPRACA,
LEDAWARIA);
C5: WEKTORY1_WYPELNIEN port map (clk_1MHz, pb1_Zam, data1_signal);
C6: WEKTORY2_WYPELNIEN port map (clk_1MHz, pb2_Otw, data2_signal);
C7: pwm1 port map (clk_1MHz, RST, '1', data1_signal, pwm1_out, pwm1_n_out);
C8: pwm2 port map (clk_1MHz, RST, '1', data2_signal, pwm2_out, pwm2_n_out);
C9: multiplexer1 port map (DIRPIN, pwm1_out, pwm2_out, pwm);end Behavioral;
Plik divider.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity divider is
generic (
NBit : natural := 3;
Div : natural := 6
);
Port ( clk : in STD_LOGIC;
clk_out : inout STD_LOGIC := '0');
end divider;
architecture divider_arch of divider is
signal cnt: std_logic_vector(Nbit -1 downto 0) := (others=>'0');
begin
process(clk)
begin
if (clk'event and clk='1') then
if cnt < Div then
cnt <= cnt+1;
else
cnt <= (others=>'0');
clk_out <= not clk_out;
end if;
end if;
end process; end divider_arch;
Maszyna stanów DMASM.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity DMASM is
Port ( CLK : in STD_LOGIC;--Zegar
RST : in STD_LOGIC;--Reset
bt1 : in STD_LOGIC;--btn zamykanie
bt2 : in STD_LOGIC;--btn otwieranie
krancEND : in STD_LOGIC;--active 0
krancPOC : in STD_LOGIC;--active 0
OVERRIDE : in STD_LOGIC;--active 0 (przeciazenie silnika)
DIRPIN : out STD_LOGIC;--Direction Motor ( 0 - FORWARD)
SLPPIN : out STD_LOGIC;--SLEEP PIN Mostek (0 - mostek zablokowany)
pb1_Zam : out STD_LOGIC;--gdy 0 zamykanie
pb2_Otw : out STD_LOGIC;--gdy 0 otwieranie
AWARIA : out STD_LOGIC;--gdy 0 awaria ukladu
LEDZAMKNIETE : out STD_LOGIC;--gdy 1 LED zamkniete
LEDOTWARTE : out STD_LOGIC;--gdy 1 LED otwarte
LEDPRACA : out STD_LOGIC;--gdy 1 LED Zamykanie/otwieranie
LEDAWARIA : out STD_LOGIC);--gdy 1 LED awaria;
end DMASM;
architecture BEHAVE of DMASM is
type STATE is (S0Otwarte, S1Zamykanie, S2Zamkniete, S3Otwieranie, S4Awaria);
signal CURRENT_STATE, NEXT_STATE: STATE;
begin
SEQ: process (RST, CLK)
begin
if (RST = '0') then
CURRENT_STATE <= S0Otwarte;
elsif (CLK' event and CLK = '1' ) then
CURRENT_STATE <= NEXT_STATE;
end if;
end process;
COMB: process (CURRENT_STATE, RST, bt1, bt2, krancEND, KrancPOC, OVERRIDE)
begin
DIRPin <= '0'; --Kierunek: FORWARD
SLPPin <= '0'; --Blokada mostka
pb1_Zam <= '1'; --klawisz nieaktywny
pb2_Otw <= '1'; --klawisz nieaktywny
AWARIA <= '1'; --klawisz nieaktywny
LEDZAMKNIETE <= '0';
LEDOTWARTE <= '1';
LEDPRACA <= '0';
LEDAWARIA <= '0';
NEXT_STATE <= S0Otwarte;
case CURRENT_STATE is
when S0Otwarte => DIRPin <= '0';
SLPPin <= '0';--mostek zablokowany
pb1_Zam <= '1';
pb2_Otw <= '1';--blokada ALL
AWARIA <= '1'; --klawisz nieaktywny
LEDZAMKNIETE <= '0';
LEDOTWARTE <= '1';
LEDPRACA <= '0';
LEDAWARIA <= '0';
if ((bt1 = '0') and (krancPOC = '0')) then
NEXT_STATE <= S1Zamykanie;
else
NEXT_STATE <= S0Otwarte;
end if;
when S1Zamykanie => DIRPin <= '0';
SLPPin <= '1';--FORWARD,MOSTEK OTWARTY
pb1_Zam <= '0';
pb2_Otw <= '1';
AWARIA <= '1'; --klawisz nieaktywny
LEDZAMKNIETE <= '0';
LEDOTWARTE <= '1';
LEDPRACA <= '1';
LEDAWARIA <= '0';
if (OVERRIDE = '0') then -- gdy jest awaria
NEXT_STATE <= S4Awaria;
else -- gdy nie ma awarii
if ((krancEND = '0') and (krancPOC = '1')) then
NEXT_STATE <= S2Zamkniete;
else
NEXT_STATE <= S1Zamykanie;
end if;
end if;
when S2Zamkniete => DIRPin <= '1';
SLPPin <= '0';
pb1_Zam <= '1';
pb2_Otw <= '1';--blokada ALL
AWARIA <= '1'; --klawisz nieaktywny
LEDZAMKNIETE <= '1';
LEDOTWARTE <= '0';
LEDPRACA <= '0';
LEDAWARIA <= '0';
if ((bt2 = '0') and (krancEND = '0'))then
NEXT_STATE <= S3Otwieranie;
else
NEXT_STATE <= S2Zamkniete;
end if;
when S3Otwieranie => DIRPin <= '1';
SLPPin <= '1';
pb1_Zam <= '1';
pb2_Otw <= '0';--BACKWARD,MOSTEK OTWARTY
AWARIA <= '1'; --klawisz nieaktywny
LEDZAMKNIETE <= '1';
LEDOTWARTE <= '0';
LEDPRACA <= '1';
LEDAWARIA <= '0'; if (OVERRIDE = '0') then -- gdy jest awaria
NEXT_STATE <= S4Awaria;
else -- gdy nie ma awarii
if ((krancPOC = '0') and (krancEND = '1')) then
NEXT_STATE <= S0Otwarte;
else
NEXT_STATE <= S3Otwieranie;
end if;
end if;
when S4Awaria => DIRPin <= '1';--stan S4Awaria
SLPPin <= '0';--blokada mostka
pb1_Zam <= '1';
pb2_Otw <= '1';--klawisze nieaktywne
AWARIA <= '0'; --sygnal aktywny
LEDZAMKNIETE <= '0';
LEDOTWARTE <= '0';
LEDPRACA <= '0';
LEDAWARIA <= '1';
when others => DIRPin <= '1';--stan S4Awaria
SLPPin <= '0';--blokada mostka
pb1_Zam <= '1';
pb2_Otw <= '1';--klawisze nieaktywne
AWARIA <= '0'; --sygnal aktywny
LEDZAMKNIETE <= '0';
LEDOTWARTE <= '0';
LEDPRACA <= '0';
LEDAWARIA <= '1'; end case;
end process;
end BEHAVE;
debounce1:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY debounce1 IS
GENERIC(
counter_size : INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
PORT(
clk : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
END debounce1;
ARCHITECTURE logic OF debounce1 IS
SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops
SIGNAL counter_set : STD_LOGIC; --sync reset to zero
SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output
BEGIN
counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter
PROCESS(clk)
BEGIN
IF(clk'EVENT and clk = '1') THEN
flipflops(0) <= button;
flipflops(1) <= flipflops(0);
If(counter_set = '1') THEN --reset counter because input is changing
counter_out <= (OTHERS => '0');
ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met
counter_out <= counter_out + 1;
ELSE --stable input time is met
result <= flipflops(1);
END IF;
END IF;
END PROCESS;
END logic;
debounce2.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY debounce2 IS
GENERIC(
counter_size : INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
PORT(
clk : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
END debounce2;
ARCHITECTURE logic OF debounce2 IS
SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops
SIGNAL counter_set : STD_LOGIC; --sync reset to zero
SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output
BEGIN
counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter
PROCESS(clk)
BEGIN
IF(clk'EVENT and clk = '1') THEN
flipflops(0) <= button;
flipflops(1) <= flipflops(0);
If(counter_set = '1') THEN --reset counter because input is changing
counter_out <= (OTHERS => '0');
ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met
counter_out <= counter_out + 1;
ELSE --stable input time is met
result <= flipflops(1);
END IF;
END IF;
END PROCESS;
END logic;
WEKTORY1_WYPELNIEN.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity WEKTORY1_WYPELNIEN is
port ( clk :in std_logic;
pushB :in std_logic;
data : out std_logic_vector(7 downto 0) );
end WEKTORY1_WYPELNIEN;
architecture BEHAVE of WEKTORY1_WYPELNIEN is
signal ADDRESS :integer range 0 to 32 :=0;
signal TEMP :integer range 0 to 10000000 :=0; -- liczba impulsów
-- jaka ma minąć zanim dojdzie do zmiany adresu
signal GENERACJA_SERII_WEKTOROW : std_logic :='0';
-- okreslanie kiedy ma sie zaczac generacja serii wektorow
signal KONIEC_GENERACJI_WEKTOROW : std_logic :='0';
-- okreslenie kiedy koniec generacji serii wektorow
signal OPOZNIENIE_BUTTONA :integer range 0 to 1000000 :=0;
type mem is array ( 0 to 2**5 - 1) of std_logic_vector(7 downto 0);
constant my_Rom : mem := (
0 => "00000000",
1 => "00000111",
2 => "00001110",
3 => "00001111",
4 => "00010101",
5 => "00011100",
6 => "00100011",
7 => "00010000",
8 => "00101010",
9 => "00110001",
10 => "00111000",
11 => "00111111",
12 => "01000110",
13 => "01001101",
14 => "01010100",
15 => "01011011",
16 => "01100010",
17 => "01101001",
18 => "01110000",
19 => "01110111",
20 => "01111110",
21 => "10000101",
22 => "10001100",
23 => "10010011",
24 => "10011010",
25 => "10100001",
26 => "10101000",
27 => "10010111",
28 => "10110110",
29 => "11011001",
30 => "11100000",
31 => "11111111"
);
begin
-- ZWIEKSZANIE ADRESU KOLEJNYCH WEKTOROW WYPELNIEN
process (CLK)
begin
if rising_edge(CLK) then
-- SPRAWDZENIE CZY PRZYCISK JEST NACISNIETY CZY NIE
if (pushB = '0') then -- lub '0' gdy po nacisnieciu
-- przycisku generowane jest przerwanie
if (OPOZNIENIE_BUTTONA < 10000) then
-- opoznienie dzialania przycisku, aby za szybko
-- nie szla generacja po nacisnieciu
OPOZNIENIE_BUTTONA <= OPOZNIENIE_BUTTONA + 1;
else
if (KONIEC_GENERACJI_WEKTOROW = '0') then
-- jesli jest koniec to nie wznawiaj generacji
GENERACJA_SERII_WEKTOROW <= '1';
end if;
end if;
else
KONIEC_GENERACJI_WEKTOROW <= '0';
OPOZNIENIE_BUTTONA <= 0;
-- zeruj koniec, gdy przycisk jest puszczony
-- zeruj opoznienie przycisku
end if;
-- GENERACJA SERII WEKTOROW PO NACISNIECIU PRZYCISKU
-- ORAZ OKRESLENIE JEJ KONCA PO JEJ WYKONANIU
if (GENERACJA_SERII_WEKTOROW = '1') then
if (TEMP < 1000000) then
TEMP <= TEMP + 1;
else
TEMP <= 0;
if (ADDRESS < 31) then
ADDRESS <= ADDRESS + 1;
else
KONIEC_GENERACJI_WEKTOROW <= '1';
GENERACJA_SERII_WEKTOROW <= '0';
ADDRESS <= 0;
end if;
end if;
else
TEMP <= 0;
end if;
end if;
end process;
-- GENEROWANIE WEKTOROW WYPELNIEN
process (CLK)
begin
if rising_edge(CLK) then
if (GENERACJA_SERII_WEKTOROW = '1') then-- gdy trwa generacja -- wektorow
DATA <= my_rom(ADDRESS);
else -- gdy generacja nie trwa
DATA <= "00000000";
end if;
end if;
end process;
end BEHAVE;
WEKTORY2_WYPELNIEN.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity WEKTORY2_WYPELNIEN is
port ( clk :in std_logic;
pushB :in std_logic;
data : out std_logic_vector(7 downto 0) );
end WEKTORY2_WYPELNIEN;
architecture BEHAVE of WEKTORY2_WYPELNIEN is
signal ADDRESS :integer range 0 to 32 :=0;
signal TEMP :integer range 0 to 10000000 :=0; -- liczba impulsów
-- jaka ma minąć zanim dojdzie do zmiany adresu
signal GENERACJA_SERII_WEKTOROW : std_logic :='0';
-- okreslanie kiedy ma sie zaczac generacja serii wektorow
signal KONIEC_GENERACJI_WEKTOROW : std_logic :='0';
-- okreslenie kiedy koniec generacji serii wektorow
signal OPOZNIENIE_BUTTONA :integer range 0 to 1000000 :=0;
type mem is array ( 0 to 2**5 - 1) of std_logic_vector(7 downto 0);
constant my_Rom : mem := (
0 => "00000000",
1 => "00000111",
2 => "00001110",
3 => "00001111",
4 => "00010101",
5 => "00011100",
6 => "00100011",
7 => "00010000",
8 => "00101010",
9 => "00110001",
10 => "00111000",
11 => "00111111",
12 => "01000110",
13 => "01001101",
14 => "01010100",
15 => "01011011",
16 => "01100010",
17 => "01101001",
18 => "01110000",
19 => "01110111",
20 => "01111110",
21 => "10000101",
22 => "10001100",
23 => "10010011",
24 => "10011010",
25 => "10100001",
26 => "10101000",
27 => "10010111",
28 => "10110110",
29 => "11011001",
30 => "11100000",
31 => "11111111"
);
begin
-- ZWIEKSZANIE ADRESU KOLEJNYCH WEKTOROW WYPELNIEN
process (CLK)
begin
if rising_edge(CLK) then
-- SPRAWDZENIE CZY PRZYCISK JEST NACISNIETY CZY NIE
if (pushB = '0') then -- lub '0' gdy po nacisnieciu
-- przycisku generowane jest przerwanie
if (OPOZNIENIE_BUTTONA < 10000) then
-- opoznienie dzialania przycisku, aby za szybko
-- nie szla generacja po nacisnieciu
OPOZNIENIE_BUTTONA <= OPOZNIENIE_BUTTONA + 1;
else
if (KONIEC_GENERACJI_WEKTOROW = '0') then
-- jesli jest koniec to nie wznawiaj generacji
GENERACJA_SERII_WEKTOROW <= '1';
end if;
end if;
else
KONIEC_GENERACJI_WEKTOROW <= '0';
OPOZNIENIE_BUTTONA <= 0;
-- zeruj koniec, gdy przycisk jest puszczony
-- zeruj opoznienie przycisku
end if;
-- GENERACJA SERII WEKTOROW PO NACISNIECIU PRZYCISKU
-- ORAZ OKRESLENIE JEJ KONCA PO JEJ WYKONANIU
if (GENERACJA_SERII_WEKTOROW = '1') then
if (TEMP < 1000000) then
TEMP <= TEMP + 1;
else
TEMP <= 0;
if (ADDRESS < 31) then
ADDRESS <= ADDRESS + 1;
else
KONIEC_GENERACJI_WEKTOROW <= '1';
GENERACJA_SERII_WEKTOROW <= '0';
ADDRESS <= 0;
end if;
end if;
else
TEMP <= 0;
end if;
end if;
end process;
-- GENEROWANIE WEKTOROW WYPELNIEN
process (CLK)
begin
if rising_edge(CLK) then
if (GENERACJA_SERII_WEKTOROW = '1') then-- gdy trwa generacja -- wektorow
DATA <= my_rom(ADDRESS);
else -- gdy generacja nie trwa
DATA <= "00000000";
end if;
end if;
end process;
end BEHAVE;
pwm1.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY pwm1 IS
GENERIC(
sys_clk : INTEGER := 1_000_000; --system clock frequency in Hz
pwm_freq : INTEGER := 60_000; --PWM switching frequency in Hz
bits_resolution : INTEGER := 8; --bits of resolution setting the duty cycle
phases : INTEGER := 1); --number of output pwms and phases
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --asynchronous reset
ena : IN STD_LOGIC; --latches in new duty cycle
duty : IN STD_LOGIC_VECTOR(bits_resolution-1 DOWNTO 0); --duty cycle
pwm_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0); --pwm outputs
pwm_n_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0)); --pwm inverse outputs
END pwm1;
ARCHITECTURE logic OF pwm1 IS
CONSTANT period : INTEGER := sys_clk/pwm_freq; --number of clocks in one pwm period
TYPE counters IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period - 1; --data type for array of period counters
SIGNAL count : counters := (OTHERS => 0); --array of period counters
SIGNAL half_duty_new : INTEGER RANGE 0 TO period/2 := 0; --number of clocks in 1/2 duty cycle
TYPE half_duties IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period/2; --data type for array of half duty values
SIGNAL half_duty : half_duties := (OTHERS => 0); --array of half duty values (for each phase)
BEGIN
PROCESS(clk, reset_n)
BEGIN
IF(reset_n = '0') THEN --asynchronous reset
count <= (OTHERS => 0); --clear counter
pwm_out <= (OTHERS => '0'); --clear pwm outputs
pwm_n_out <= (OTHERS => '0'); --clear pwm inverse outputs
ELSIF(clk'EVENT AND clk = '1') THEN --rising system clock edge
IF(ena = '1') THEN --latch in new duty cycle
half_duty_new <= conv_integer(duty)*period/(2**bits_resolution)/2; --determine clocks in 1/2 duty cycle
END IF;
FOR i IN 0 to phases-1 LOOP --create a counter for each phase
IF(count(0) = period - 1 - i*period/phases) THEN --end of period reached
count(i) <= 0; --reset counter
half_duty(i) <= half_duty_new; --set most recent duty cycle value
ELSE --end of period not reached
count(i) <= count(i) + 1; --increment counter
END IF;
END LOOP;
FOR i IN 0 to phases-1 LOOP --control outputs for each phase
IF(count(i) = half_duty(i)) THEN --phase's falling edge reached
pwm_out(i) <= '0'; --deassert the pwm output
pwm_n_out(i) <= '1'; --assert the pwm inverse output
ELSIF(count(i) = period - half_duty(i)) THEN --phase's rising edge reached
pwm_out(i) <= '1'; --assert the pwm output
pwm_n_out(i) <= '0'; --deassert the pwm inverse output
END IF;
END LOOP;
END IF;
END PROCESS;
END logic;
pwm2.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY pwm2 IS
GENERIC(
sys_clk : INTEGER := 1_000_000; --system clock frequency in Hz
pwm_freq : INTEGER := 60_000; --PWM switching frequency in Hz
bits_resolution : INTEGER := 8; --bits of resolution setting the duty cycle
phases : INTEGER := 1); --number of output pwms and phases
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --asynchronous reset
ena : IN STD_LOGIC; --latches in new duty cycle
duty : IN STD_LOGIC_VECTOR(bits_resolution-1 DOWNTO 0); --duty cycle
pwm_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0); --pwm outputs
pwm_n_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0)); --pwm inverse outputs
END pwm2;
ARCHITECTURE logic OF pwm2 IS
CONSTANT period : INTEGER := sys_clk/pwm_freq; --number of clocks in one pwm period
TYPE counters IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period - 1; --data type for array of period counters
SIGNAL count : counters := (OTHERS => 0); --array of period counters
SIGNAL half_duty_new : INTEGER RANGE 0 TO period/2 := 0; --number of clocks in 1/2 duty cycle
TYPE half_duties IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period/2; --data type for array of half duty values
SIGNAL half_duty : half_duties := (OTHERS => 0); --array of half duty values (for each phase)
BEGIN
PROCESS(clk, reset_n)
BEGIN
IF(reset_n = '0') THEN --asynchronous reset
count <= (OTHERS => 0); --clear counter
pwm_out <= (OTHERS => '0'); --clear pwm outputs
pwm_n_out <= (OTHERS => '0'); --clear pwm inverse outputs
ELSIF(clk'EVENT AND clk = '1') THEN --rising system clock edge
IF(ena = '1') THEN --latch in new duty cycle
half_duty_new <= conv_integer(duty)*period/(2**bits_resolution)/2; --determine clocks in 1/2 duty cycle
END IF;
FOR i IN 0 to phases-1 LOOP --create a counter for each phase
IF(count(0) = period - 1 - i*period/phases) THEN --end of period reached
count(i) <= 0; --reset counter
half_duty(i) <= half_duty_new; --set most recent duty cycle value
ELSE --end of period not reached
count(i) <= count(i) + 1; --increment counter
END IF;
END LOOP;
FOR i IN 0 to phases-1 LOOP --control outputs for each phase
IF(count(i) = half_duty(i)) THEN --phase's falling edge reached
pwm_out(i) <= '0'; --deassert the pwm output
pwm_n_out(i) <= '1'; --assert the pwm inverse output
ELSIF(count(i) = period - half_duty(i)) THEN --phase's rising edge reached
pwm_out(i) <= '1'; --assert the pwm output
pwm_n_out(i) <= '0'; --deassert the pwm inverse output
END IF;
END LOOP;
END IF;
END PROCESS;
END logic;
multiplekser1.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity multiplexer1 is
Port ( SEL : in STD_LOGIC;--tu sygnal DIRPIN
pwm1 : in STD_LOGIC_VECTOR (0 downto 0);
pwm2 : in STD_LOGIC_VECTOR (0 downto 0);
pwm : out STD_LOGIC_VECTOR (0 downto 0));
end multiplexer1;
architecture Behavioral of multiplexer1 is
begin
pwm <= pwm1 when (SEL = '0') else pwm2;
end Behavioral;
i ostatni plik - ProjektUCF.ucf (dla płytki FPGA ElbertV2):
NET "CLK" LOC = P129;
NET "CLK" PERIOD = 10MHz;
NET "RST" PULLUP;
NET "RST" LOC = "P76";
NET "bt1" PULLUP;
NET "bt1" LOC = "P80";
NET "bt2" PULLUP;
NET "bt2" LOC = "P79";
NET "krancEND" PULLUP;
NET "krancEND" LOC = "P58";
NET "krancPOC" PULLUP;
NET "krancPOC" LOC = "P59";
NET "OVERRIDE" PULLUP;
NET "OVERRIDE" LOC = "P78";
NET "DIRPIN" LOC = "P19";
NET "SLPPIN" LOC = "P21";
NET "AWARIA" LOC = "P15";
NET "LEDZAMKNIETE" LOC = "P55"; //LED1
NET "LEDOTWARTE" LOC = "P54"; //LED2
NET "LEDPRACA" LOC = "P51"; //LED3
NET "LEDAWARIA" LOC = "P46"; //LED8
Projekt się syntetyzuje i wygląda OK na podglądzie RTL (nie ma błędów ale ma sporo ostrzeżeń.
PozdrawiamTen post został edytowany przez Autora dnia 20.09.17 o godzinie 13:20