Skocz do zawartości

Problem: zegar na pinie kombinatorycznym


FlyingDutch

Pomocna odpowiedź

Cześć,

podczas realizacji mojego projektu opartego o układ FPGA Spartan3A, napotkałem problem przekazywania sygnału zegarowego na pinach kombinatorycznych co skutkuje ostrzeżeniami (układ syntetyzuje się i działa poprawnie zarówno podczas symulacji jak i w praktycznym układzie) o złych praktykach projektowych.

Może napiszę kilka zdań co robi ten układ: jest to sterownik rolet na drzwiach balkonowych (silnik DC 12V). Jest panel z przyciskami w pobliżu drzwi, oraz sterownik (Arduino) z wyświetlaczem 9komunikacja jednokierunkowa FPGA -> Arduino poprzez UART i konwerter UART-RS485). Silnik jest sterowany poprzez mostek MOSFET firmy Pololu (mostek ma wejścia PWM, SLEEP i DIR - kierunek obrotów) a sygnały sterujące mostkiem są z układu FPGA. Mostek ma też wyjście napięciowe proporcjonalne do prądu płynącego przez silnik DC 12 V. Sygnał napięciowy jest porównywany z napięciem odniesienia na komparatorze i generuje sygnał błędu binarny "OVERLOAD", gdy wartość prądu płynącego przez silnik jest za duża. Są też dwa czujniki krańcowe: jeden aktywny (LOW), gdy rolety są na początku drogi (całkiem otwarte) i na końcu (całkiem zamknięte).

Sterownik generuje sygnał PWM składający się z trzech faz:

1) miękki start - narastające wypełnienia przez klika sekund (entity: WEKTORY_WYPELKNIEN )

2) faza zamykania/otwierania - układ czeka na zmianę stanu czujników krańcowych na przeciwną (w tym czasie stałe wypełnienie 96 %)

3) faza domknięcia - malejące do zera wypełnienia przez kilka sekund (entity: WEKTORY_REVERSE)

W fazie drugiej zamykanie lub otwieranie układ czeka na zmianę stanu czujników krańcowych, gdy zmiana stanu w czasie odliczanym przez timer wewnętrzny nie nastąpi jest przejście do stanu awaryjnego (S6TooLongOper). Timer jest zlokalizowany w entity: WEKTORY_WYPELNIEN i WEKTORY_REVERSE. Układ obsługuje też kilka sytuacji awaryjnych: przeciążenie silnika, brak zasilania czujników krańcowych , błąd pozycjonowania czujników krańcowych - oba aktywne naraz, operacja trwa za długo.

W układzie są następujące moduły:

1) Dzielnik częstotliwości zegara (entity: divider) z 12 MHz na 1MHz - sygnał clk_1MHz który6 jest głównym zegarem dla większości układu

2) Debouncer'y dla przycisków wejściowych (b1 ib2)

3) Generyczny (wielofazowy ogólnie lecz w tym przypadku obsługuje jedną fazę) generator PWM (IPcore z opencores.org) - entity pwm (użyte 4 instancje)

4) WEKTORY_WYPELNIEN i WEKTORY_REVERSE generują ciąg zmiennych wartości PWM dla soft-startu i soft-stopu (32 wartości odczyt z ROM)

5) Entity: DMASM główny kontroler całego układu - maszyna stanowa

6) Multiplekser - przełącza sygnał PWM z 4-rech instancji generatora PWM na wejście mostka

Znaczenie portów i sygnałów jest opisane w komentarzach VHDL w kodzie.

Oto główny plik projektu (entity Project):

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 
          OVERLOAD : in  STD_LOGIC;--z komparatora (za duży prąd płynie przez silnik)
	     brakZasilaniaCz : in  STD_LOGIC;--Brak zasilania czujnikow (aktywne 0)
	     zdalneZamykanie : in  STD_LOGIC;--Zdalne zamykanie drzwi(aktywne 0)
          DIRPIN : inout  STD_LOGIC;
          SLPPIN : out  STD_LOGIC;
          AWARIA : out  STD_LOGIC;--Aktywne 1
	     STATUS : out STD_LOGIC_VECTOR (3 downto 0);--Opis stanu ukladu (Praca/Awaria)
          LEDOTWARTE : out  STD_LOGIC;
          LEDZAMKNIETE : out  STD_LOGIC;
          LEDPRACA : out  STD_LOGIC;
          LEDAWARIA : out  STD_LOGIC;
		  WyjPWM : 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 debounce 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
		  OVERLOAD : in  STD_LOGIC;--active 0 (przeciazenie silnika)
		  TIM2LONGZ : in  STD_LOGIC;--Timer operacja trwa za dlugo(zamykanie)
		  TIM2LONGO : in  STD_LOGIC;--Timer operacja trwa za dlugo(otwieranie)
		  NoPowerSensors : in  STD_LOGIC;--Brak zasilania czujnikow (aktywne 0)
		  RemoteZamykanie : in  STD_LOGIC;--Zdalne zamykanie drzwi(aktywne 0)
          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
		  blokada_Zam : out  STD_LOGIC;--gdy 0 blokada
          blokada_Otw : out  STD_LOGIC;--gdy 0 blokada
		  SELO : out STD_LOGIC_VECTOR (1 downto 0);--wybor pwm dla multiplexera
		  AWARIA : out  STD_LOGIC;--gdy 1 awaria ukladu
		  STATUSO : out STD_LOGIC_VECTOR (3 downto 0);--Opis stanu ukladu (Praca/Awaria)
		  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 WEKTORY_WYPELNIEN is
      port ( clk :in std_logic;
        pushB :in std_logic;
		blokada :in std_logic;
		rst : in  STD_LOGIC; --aktywne 0
		timerO : out std_logic;
        data : out std_logic_vector(7 downto 0) );
end component; 

component WEKTORY_REVERSE is
      port ( clk :in std_logic;
        pushB :in std_logic;
        data : out std_logic_vector(7 downto 0) );
end component;

  component pwm 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 mux4to1 is
		   Port ( SEL : in  STD_LOGIC_VECTOR (1 downto 0); -- select input
          A   : in  STD_LOGIC_VECTOR (0 downto 0);  -- inputs
		  B   : in  STD_LOGIC_VECTOR (0 downto 0);
		  C   : in  STD_LOGIC_VECTOR (0 downto 0);
		  D   : in  STD_LOGIC_VECTOR (0 downto 0);
          X   : out STD_LOGIC_VECTOR (0 downto 0)); -- output
end component;  


  signal data1_signal :STD_LOGIC_VECTOR (7 downto 0);
signal data2_signal :STD_LOGIC_VECTOR (7 downto 0);
signal data3_signal :STD_LOGIC_VECTOR (7 downto 0);
signal data4_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 pwm3_out :STD_LOGIC_VECTOR (0 downto 0);
signal pwm4_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 pwm3_n_out :STD_LOGIC_VECTOR (0 downto 0);
signal pwm4_n_out :STD_LOGIC_VECTOR (0 downto 0);
--signal WyjPWM :STD_LOGIC_VECTOR (0 downto 0);
signal pb1_Zam :STD_LOGIC;
signal pb2_Otw :STD_LOGIC;
signal blokada_Zam :STD_LOGIC;
signal blokada_Otw :STD_LOGIC;
signal SELO :STD_LOGIC_VECTOR (1 downto 0);
signal TIM2LONGZ :STD_LOGIC;
signal TIM2LONGO :STD_LOGIC;
--signal brakZasilaniaCz :STD_LOGIC;	
--signal zdalneZamykanie :STD_LOGIC;

begin
C1: divider port map (CLK, clk_1MHz);
C2: debounce port map (clk_1MHz, b1, b1_DB);
C3: debounce port map (clk_1MHz, b2, b2_DB);

C4: WEKTORY_WYPELNIEN port map (clk_1MHz, pb1_Zam, blokada_Zam, RST, TIM2LONGZ, data1_signal);
C5: WEKTORY_WYPELNIEN port map (clk_1MHz, pb2_Otw, blokada_Otw, RST, TIM2LONGO, data2_signal);
C6: DMASM  port map   (clk_1MHz,
							  RST,
							  b1_DB, 
							  b2_DB,
							  krancEND,
							  krancPOC,
							  OVERLOAD,
							  TIM2LONGZ,
							  TIM2LONGO,
							  brakZasilaniaCz,
							  zdalneZamykanie,
							  DIRPIN, 
							  SLPPIN, 
							  pb1_Zam, 
							  pb2_Otw,
							  blokada_Zam,
							  blokada_Otw,
							  SELO,
							  AWARIA,
							  STATUS,
							  LEDZAMKNIETE, 
							  LEDOTWARTE, 
							  LEDPRACA, 
							  LEDAWARIA);


C7: pwm port map (clk_1MHz, RST, '1', data1_signal, pwm1_out, pwm1_n_out);
  C8: pwm port map (clk_1MHz, RST, '1', data2_signal, pwm2_out, pwm2_n_out);

C9: WEKTORY_REVERSE port map (clk_1MHz, blokada_Zam, data3_signal);
C10: WEKTORY_REVERSE port map (clk_1MHz, blokada_Otw, data4_signal);
C11: pwm port map (clk_1MHz, RST, '1', data3_signal, pwm3_out, pwm3_n_out);
  C12: pwm port map (clk_1MHz, RST, '1', data4_signal, pwm4_out, pwm4_n_out);
C13: mux4to1 port map (SELO, pwm1_out, pwm2_out, pwm3_out, pwm4_out, WyjPWM);

end Behavioral;

Tutaj kod maszyny stanowej (entity: DMASM):

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.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
		  OVERLOAD : in  STD_LOGIC;--active 0 (przeciazenie silnika)
		  TIM2LONGZ : in  STD_LOGIC;--Timer operacja trwa za dlugo(zamykanie)
		  TIM2LONGO : in  STD_LOGIC;--Timer operacja trwa za dlugo(otwieranie)
		  NoPowerSensors : in  STD_LOGIC;--Brak zasilania czujnikow (aktywne 0)
		  RemoteZamykanie : in  STD_LOGIC;--Zdalne zamykanie drzwi(aktywne 0)
          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
		  blokada_Zam : out  STD_LOGIC;--gdy 0 blokada
          blokada_Otw : out  STD_LOGIC;--gdy 0 blokada
		  SELO : out STD_LOGIC_VECTOR (1 downto 0);--wybor pwm dla multiplexera
		  AWARIA : out  STD_LOGIC;--gdy 0 awaria ukladu
		  STATUSO : out STD_LOGIC_VECTOR (3 downto 0);--Opis stanu ukladu (Praca/Awaria)
		  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, S1ZamykanieLocal, S2Zamkniete, S3OtwieranieLocal, S4ZamykanieRemote, 
						  S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError,
						  S9UnknowError, S10Awaria, S11DomkZamykanie, S12DomkOtwieranie,
						  S13BetweenEdges);
      signal CURRENT_STATE, NEXT_STATE: STATE;

	 constant LICZNIK_LIMIT : integer := 2_000_000; -- 2s deklaracja stalej z max wart licznika

	 signal licznik : unsigned(24 downto 0); -- definicja syg lokalnego		  

begin

SEQ: process (RST, CLK, krancPOC, krancEND, OVERLOAD, NoPowerSensors, RemoteZamykanie)
begin
       if (RST = '0') then
		 licznik <= b"0000000000000000000000000";
	     if ((krancPOC = '0') and (krancEND = '1')) then
            CURRENT_STATE <= S0Otwarte; 
          else if ((krancPOC = '1') and (krancEND = '0')) then
            CURRENT_STATE <= S2Zamkniete;
			elsif ((krancPOC = '1') and (krancEND = '1')) then
            CURRENT_STATE <= S13BetweenEdges; 
			end if;   
          end if;     
       elsif (CLK' event and CLK = '1' ) then
			if (CURRENT_STATE = S11DomkZamykanie) and (NEXT_STATE = S11DomkZamykanie) then
			    licznik <= licznik + 1;
				 if licznik = LICZNIK_LIMIT then 
				    licznik <= b"0000000000000000000000000";
					 CURRENT_STATE <= S2Zamkniete;
				 end if;
			elsif (CURRENT_STATE = S12DomkOtwieranie) and (NEXT_STATE = S12DomkOtwieranie) then
				 licznik <= licznik + 1;
				 if licznik = LICZNIK_LIMIT then 
				    licznik <= b"0000000000000000000000000";
					 CURRENT_STATE <= S0Otwarte;
				 end if;
			elsif (OVERLOAD = '0') then--tu obsluga bledow dla all states
				 CURRENT_STATE <= S5Overload;
			elsif (NoPowerSensors = '0') then
				 CURRENT_STATE <= S7NoPowerSensors;
			elsif ((krancEND = '0') and (krancPOC = '0')) then
				 CURRENT_STATE <= S8PositionError;	  
			else	 
               CURRENT_STATE <= NEXT_STATE;
			end if;
       end if;
end process;

COMB: process (CURRENT_STATE, RST, bt1, bt2, krancEND, KrancPOC, RemoteZamykanie,
			   TIM2LONGZ, TIM2LONGO)
begin 
case CURRENT_STATE is
   when S0Otwarte => DIRPin <= '0';
		SLPPin <= '0';--mostek zablokowany
		pb1_Zam <= '1';
		pb2_Otw <= '1';--blokada ALL
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		SELO <= "11";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '1';
		LEDPRACA <= '0';
		LEDAWARIA  <= '0';
		STATUSO <= "0000";			
        if (bt1 = '0') then
		     NEXT_STATE <= S1ZamykanieLocal;
		  elsif  (RemoteZamykanie = '0') then 
			  NEXT_STATE <= S4ZamykanieRemote;
          elsif ((krancPOC = '0') and (krancEND = '1')) then
            NEXT_STATE <= S0Otwarte; 
          elsif ((krancPOC = '1') and (krancEND = '0')) then
            NEXT_STATE <= S2Zamkniete;
		  elsif ((krancPOC = '1') and (krancEND = '1')) then
		    NEXT_STATE <= S13BetweenEdges;
          end if;                                                    		 
   when S1ZamykanieLocal => DIRPin <= '0';
		SLPPin <= '1';--FORWARD,MOSTEK OTWARTY
		pb1_Zam <= '0';
		pb2_Otw <= '1';
		blokada_Zam <= '1';
		blokada_Otw <= '0';
		SELO <= "00";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '1';
		LEDPRACA <= '1';
		LEDAWARIA  <= '0';
		STATUSO <= "0001";
        if (bt2 = '0')	then
          NEXT_STATE <= S3OtwieranieLocal;						
	   else 
		  if ((krancEND = '0') and (krancPOC = '1')) then 
		      NEXT_STATE <= S11DomkZamykanie;		      	
	     elsif (TIM2LONGZ = '1') then
              NEXT_STATE <= S6TooLongOper;
          else
             NEXT_STATE <= S1ZamykanieLocal; 
          end if;                                                                    
	   end if;
   when S2Zamkniete => DIRPin <= '1';
		SLPPin <= '0';
		pb1_Zam <= '1';
		pb2_Otw <= '1';--blokada ALL
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		SELO <= "10";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '1';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '0'; 
		STATUSO <= "0010";
       if (bt2 = '0')then --Button otwieranie
		  NEXT_STATE <= S3OtwieranieLocal;
       else
		  if ((krancPOC = '0') and (krancEND = '1')) then
            NEXT_STATE <= S0Otwarte; 
          elsif ((krancPOC = '1') and (krancEND = '0')) then
            NEXT_STATE <= S2Zamkniete;
		  elsif ((krancPOC = '1') and (krancEND = '1')) then
		    NEXT_STATE <= S13BetweenEdges;
		  end if;	 
       end if;
   when S3OtwieranieLocal => DIRPin <= '1';
		SLPPin <= '1';
		pb1_Zam <= '1';
		pb2_Otw <= '0';--BACKWARD,MOSTEK OTWARTY
		blokada_Zam <= '0';
		blokada_Otw <= '1';
		SELO <= "01";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '1';
		LEDOTWARTE <= '0';
		LEDPRACA <= '1';
		LEDAWARIA  <= '0';
		STATUSO <= "0011";
	  if (bt1 = '0') then --Button zamykanie
		   NEXT_STATE <= S1ZamykanieLocal;
	  elsif ((krancPOC = '0') and (krancEND = '1')) then  -- zmiana stanu czuj. krancowych
	      NEXT_STATE <= S12DomkOtwieranie; 	
	  else -- gdy nie ma awarii
	     if (TIM2LONGO = '1') then  -- gdy jest awaria
              NEXT_STATE <= S6TooLongOper;
          else
             NEXT_STATE <= S3OtwieranieLocal; 
         end if;                                                                    
	  end if;			
   when S4ZamykanieRemote => DIRPin <= '0';
		SLPPin <= '1';--FORWARD,MOSTEK OTWARTY
		pb1_Zam <= '0';
		pb2_Otw <= '1';
		blokada_Zam <= '1';
		blokada_Otw <= '0';
		SELO <= "00";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '1';
		LEDPRACA <= '1';
		LEDAWARIA  <= '0';
		STATUSO <= "0100";

		if (bt2 = '0') then --klawisz otwieranie
		      NEXT_STATE <= S3OtwieranieLocal;
	   elsif ((krancEND = '0') and (krancPOC = '1')) then
		   NEXT_STATE <= S11DomkZamykanie; 								
	   else 
	     if (TIM2LONGZ = '1') then  -- gdy jest awaria
             NEXT_STATE <= S6TooLongOper; 
          else
             NEXT_STATE <= S4ZamykanieRemote;
          end if;                                                                    	
       end if;			
 when S5Overload => DIRPin <= '1';--stan S4Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
		STATUSO <= "1000";
		NEXT_STATE <= S10Awaria;
 when S6TooLongOper => DIRPin <= '1';--stan S4Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
		STATUSO <= "1010";
		NEXT_STATE <= S10Awaria;
 when S7NoPowerSensors => DIRPin <= '1';--stan S4Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
		STATUSO <= "1001";
		NEXT_STATE <= S10Awaria;
 when S8PositionError => DIRPin <= '1';--stan S4Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
		STATUSO <= "1011";
        NEXT_STATE <= S10Awaria;			
 when S9UnknowError => DIRPin <= '1';--stan S4Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
		STATUSO <= "1100";
        NEXT_STATE <= S10Awaria;			
 when S10Awaria => DIRPin <= '1';--stan S10Awaria
		SLPPin <= '0';--blokada mostka
		pb1_Zam <= '1';
		pb2_Otw <= '1';--klawisze nieaktywne
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		AWARIA <= '1'; --sygnal aktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '1';
  when S11DomkZamykanie => DIRPin <= '0';
		SLPPin <= '1';
		pb1_Zam <= '1';
		pb2_Otw <= '1';--blokada ALL
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		SELO <= "10";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '1';
		LEDPRACA <= '1';
		LEDAWARIA  <= '0'; 
		STATUSO <= "0101";
		if (bt2 = '0') then --klawisz otwieranie
		    NEXT_STATE <= S3OtwieranieLocal;
		else		
		    NEXT_STATE <= S11DomkZamykanie;
		end if;	 
 when S12DomkOtwieranie => DIRPin <= '1';
		SLPPin <= '1';
		pb1_Zam <= '1';
		pb2_Otw <= '1';--blokada ALL
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		SELO <= "11";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '1';
		LEDOTWARTE <= '0';
		LEDPRACA <= '1';
		LEDAWARIA  <= '0'; 
		STATUSO <= "0110";
		if (bt1 = '0') then --Button zamykanie
		    NEXT_STATE <= S1ZamykanieLocal;
		else	
		    NEXT_STATE <= S12DomkOtwieranie;
		end if;	 
  when S13BetweenEdges => DIRPin <= '0';
		SLPPin <= '0';--mostek zablokowany
		pb1_Zam <= '1';
		pb2_Otw <= '1';--blokada ALL
		blokada_Zam <= '0';
		blokada_Otw <= '0';
		SELO <= "11";
		AWARIA <= '0'; --klawisz nieaktywny
		LEDZAMKNIETE <= '0';
		LEDOTWARTE <= '0';
		LEDPRACA <= '0';
		LEDAWARIA  <= '0';
		STATUSO <= "0111";			
        if (bt2 = '0') then --Button otwieranie
		     NEXT_STATE <= S3OtwieranieLocal;		     
		  elsif (bt1 = '0') then --Button zamykanie
		     NEXT_STATE <= S1ZamykanieLocal;
		  elsif  (RemoteZamykanie = '0') then 
			  NEXT_STATE <= S4ZamykanieRemote;
          else
            if ((krancPOC = '0') and (krancEND = '1')) then
               NEXT_STATE <= S0Otwarte; 
            elsif ((krancPOC = '1') and (krancEND = '0')) then
               NEXT_STATE <= S2Zamkniete;
		    elsif ((krancPOC = '1') and (krancEND = '1')) then
		       NEXT_STATE <= S13BetweenEdges;
		  end if;	 
          end if;			  
when others => STATUSO <= "1010";--sygnalizacja TooLongOper
      NEXT_STATE <= S10Awaria;
   end case;
 end process;
end BEHAVE;

Kod generatora PWM - phase correct (entity: pwm):

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY pwm 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 pwm;

ARCHITECTURE logic OF pwm 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;

Kod multipleksera (entity: mux4to1):

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity mux4to1 is
	   Port ( SEL : in  STD_LOGIC_VECTOR (1 downto 0);     -- select input
          A   : in  STD_LOGIC_VECTOR (0 downto 0);  -- inputs
		  B   : in  STD_LOGIC_VECTOR (0 downto 0);
		  C   : in  STD_LOGIC_VECTOR (0 downto 0);
		  D   : in  STD_LOGIC_VECTOR (0 downto 0);
          X   : out STD_LOGIC_VECTOR (0 downto 0)); -- output
end mux4to1;

architecture Behavioral of mux4to1 is
begin
with SEL select
    X <= A when "00",
        B when "01",
        C when "10",
        D when "11",
        "0"  when others;

end Behavioral;

Poniżej załączam podgląd RTL układu, aby można było lepiej rozumieć wzajemne powiązania komponentów w projekcie:

Myślę, że te źródła powinny wystarczyć, aby zilustrować mój problem. Zacznę od najprostszego przypadku: na entity divider wchodzi sygnał zegarowy z zegara układu FPGA (12 Mhz) a na wyjściu jest sygnał o częstotliwości 1MHz - clk_1MHz. Ten sygnał jest wejściowym zegarem do prawie wszystkich komponentów układu (generatorów PWM, maszyny stanowej DMASM, WEKTORY_WYPELNIEN i WEKTORY_REVERSE oraz debouncerów.

I tutaj mamy warning podczas syntezy układu FPGA (map):


=========================================================================
*                            Final Report                               *
=========================================================================

Clock Information:
------------------
---------------------------------------------------+--------------------------+-------+
Clock Signal                                       | Clock buffer(FF name)    | Load  |
---------------------------------------------------+--------------------------+-------+
CLK                                                | BUFGP                    | 4     |
C1/clk_out1                                        | BUFG                     | 412   |
C6/NEXT_STATE_not0001(C6/NEXT_STATE_not000158_f5:O)| NONE(*)(C6/NEXT_STATE_13)| 10    |
C6/SELO_or0000(C6/SELO_or00001:O)                  | NONE(*)(C6/SELO_1)       | 2     |
C6/CURRENT_STATE_10                                | NONE(C6/STATUSO_3)       | 4     |
---------------------------------------------------+--------------------------+-------+
(*) These 2 clock signal(s) are generated by combinatorial logic,
and XST is not able to identify which are the primary clock signals.
Please use the CLOCK_SIGNAL constraint to specify the clock signal(s) generated by combinatorial logic.
INFO:Xst:2169 - HDL ADVISOR - Some clock signals were not automatically buffered by XST with BUFG/BUFR resources. Please use the buffer_type constraint in order to insert these buffers to the clock signals to help prevent skew problems.

Asynchronous Control Signals Information:
----------------------------------------
-------------------------------------------------------------+--------------------------+-------+
Control Signal                                               | Buffer(FF name)          | Load  |
-------------------------------------------------------------+--------------------------+-------+
C11/reset_n_inv(C8/reset_n_inv1_INV_0:O)                     | NONE(C11/count_0_0)      | 45    |
C6/CURRENT_STATE_10__or0000(C6/CURRENT_STATE_10__or000021:O) | NONE(C6/CURRENT_STATE_1) | 10    |
N0(XST_GND:G)                                                | NONE(C6/CURRENT_STATE_1) | 10    |
C6/CURRENT_STATE_0__and0000(C6/CURRENT_STATE_0__and00001:O)  | NONE(C6/CURRENT_STATE_0) | 1     |
C6/CURRENT_STATE_0__or0000(C6/CURRENT_STATE_13__or000011:O)  | NONE(C6/CURRENT_STATE_0) | 1     |
C6/CURRENT_STATE_13__and0000(C6/CURRENT_STATE_mux0007<0>15:O)| NONE(C6/CURRENT_STATE_13)| 1     |
C6/CURRENT_STATE_13__or0000(C6/CURRENT_STATE_13__or00002:O)  | NONE(C6/CURRENT_STATE_13)| 1     |
C6/CURRENT_STATE_2__and0000(C6/CURRENT_STATE_2__and00001:O)  | NONE(C6/CURRENT_STATE_2) | 1     |
C6/CURRENT_STATE_2__or0000(C6/CURRENT_STATE_2__or00001:O)    | NONE(C6/CURRENT_STATE_2) | 1     |
-------------------------------------------------------------+--------------------------+-------+

Ten problem próbowałem rozwiązać za pomocą atrybutów sygnałów w kodzie VHDL:

signal clk_1MHz :STD_LOGIC;

attribute clock_signal : string; 
ATTRIBUTE buffer_type : string;  --" {bufgdll | ibufg | bufgp | ibuf | bufr | none}"; 

   attribute clock_signal of clk_1MHz : signal is "yes";
ATTRIBUTE buffer_type OF clk_1MHz : SIGNAL IS "BUFG";

i chyba się udało. Jest natomiast poważniejszy problem: multiplekser mux4to1 jest asynchroniczny (w tym sensie, że nie posiada wejścia sygnału clok) i sygnał

signal SELO :STD_LOGIC_VECTOR (1 downto 0);

oraz

signal CURRENT_STATE, NEXT_STATE: STATE;

z DMASM (maszyna stanowa) są traktowane przez ISE jako sygnały zegarowe, które nie są prawidłowo buforowane.

Próbowałem problem rozwiązać, za pomocą atrybutów (sygnał zegarowy i typ bufora) w entity DMASM:

architecture BEHAVE of DMASM is
       type STATE is (S0Otwarte, S1ZamykanieLocal, S2Zamkniete, S3OtwieranieLocal, S4ZamykanieRemote, 
						  S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError,
						  S9UnknowError, S10Awaria, S11DomkZamykanie, S12DomkOtwieranie,
						  S13BetweenEdges);

      signal CURRENT_STATE, NEXT_STATE: STATE := S0Otwarte;

	 attribute clock_signal : string;
      ATTRIBUTE buffer_type : string; 

      --attribute clock_signal of CURRENT_STATE : signal is "yes";
	 --attribute clock_signal of NEXT_STATE : signal is "yes";

	 ATTRIBUTE buffer_type OF CURRENT_STATE : SIGNAL IS "BUFG";
	 ATTRIBUTE buffer_type OF NEXT_STATE : SIGNAL IS "BUFG";

	 attribute safe_implementation : string; 
	 attribute safe_implementation of CURRENT_STATE : signal is "yes";
	 --attribute safe_implementation of NEXT_STATE : signal is "yes";

	 constant LICZNIK_LIMIT : integer := 2_000_000; -- 2s deklaracja stalej z max wart licznika

	 signal licznik : unsigned(24 downto 0); -- definicja syg lokalnego		  

A nawet zrobić multiplekser "synchorniczny" "na siłę":

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity mux4to1 is
	   Port ( CLK : in  STD_LOGIC; --Zegar 
		  SEL : in  STD_LOGIC_VECTOR (1 downto 0);     -- select input
          A   : in  STD_LOGIC_VECTOR (0 downto 0);  -- inputs
		  B   : in  STD_LOGIC_VECTOR (0 downto 0);
		  C   : in  STD_LOGIC_VECTOR (0 downto 0);
		  D   : in  STD_LOGIC_VECTOR (0 downto 0);
          X   : out STD_LOGIC_VECTOR (0 downto 0)); -- output
end mux4to1;

architecture Behavioral of mux4to1 is
begin
  process(CLK)
begin
	if (CLK'event and CLK='1') then
	  case SEL is
        when "00" => X <= A ;
		when "01" => X <= B ;
		when "10" => X <= C ;
		when "11" => X <= D ;
		when others => X <= "0" ;
	  end case;
	end if;
  end process;	

end Behavioral;

ale nie przyniosło to rozwiązania problemu. Patrz wyjście z syntezy:

Running delay-based LUT packing...
Running related packing...
Updating timing models...
WARNING:PhysDesignRules:372 - Gated clock. Clock net C6/blokada_Otw_not0001 is
  sourced by a combinatorial pin. This is not good design practice. Use the CE
  pin to control the loading of data into the flip-flop.
WARNING:PhysDesignRules:372 - Gated clock. Clock net C6/NEXT_STATE_not0001 is
  sourced by a combinatorial pin. This is not good design practice. Use the CE
  pin to control the loading of data into the flip-flop.
WARNING:PhysDesignRules:372 - Gated clock. Clock net C6/SELO_or0000 is sourced
  by a combinatorial pin. This is not good design practice. Use the CE pin to
  control the loading of data into the flip-flop.

.....

Generating "PAR" statistics.

**************************
Generating Clock Report
**************************

+---------------------+--------------+------+------+------------+-------------+
|        Clock Net    |   Resource   |Locked|Fanout|Net Skew(ns)|Max Delay(ns)|
+---------------------+--------------+------+------+------------+-------------+
|            clk_1MHz |  BUFGMUX_X1Y0| No   |  234 |  0.142      |
+---------------------+--------------+------+------+------------+-------------+
    |  0.609 |              |      |      |            |             |
|C6/CURRENT_STATE<10> | BUFGMUX_X1Y10| No   |    4 |  0.008     |  0.501      |
+---------------------+--------------+------+------+------------+-------------+
|           CLK_BUFGP | BUFGMUX_X2Y10| No   |    3 |  0.013     |  0.471      |
+---------------------+--------------+------+------+------------+-------------+
|C6/blokada_Otw_not00 |              |      |      |            |             |
|                  01 |         Local|      |   10 |  0.231     |  1.742      |
+---------------------+--------------+------+------+------------+-------------+
|C6/NEXT_STATE_not000 |              |      |      |            |             |
|                   1 |         Local|      |    9 |  0.130     |  1.352      |
+---------------------+--------------+------+------+------------+-------------+
|      C6/SELO_or0000 |         Local|      |    1 |  0.000     |  0.954      |
+---------------------+--------------+------+------+------------+-------------+

* Net Skew is the difference between the minimum and maximum routing
only delays for the net. Note this is different from Clock Skew which
is reported in TRCE timing report. Clock Skew is the difference between
the minimum and maximum path delays which includes logic delays.

* The fanout is the number of component pins not the individual BEL loads,
for example SLICE loads not FF loads.

Moje pytanie brzmi:

Jak prawidłowo rozwiązać problem kilku sygnałów zegarowych (ich prawidłowego buforowania) i dystrybucji. Czy należy zmienić projekt (kod VHDL) a jesli tak to jak wykonać zmiany, czy można to zrobić w inny sposób (np. tak jak ja próbowałem dodatkowymi atrybutami sygnałów)?

Pozdrawiam

Link do komentarza
Share on other sites

Na początek dwa małe wyjaśnienia:

- Pojęcie "clock signal" nie oznacza dosłownie sygnału zegarowego (czy też skrótowo: zegara) tj. takiego, które pochodzi ze źródła go generującego (czyli np: generatora kwarcowego, generatora zbudowanego w oparciu o bramki NAND czy jakiegokolwiek innego) i tym samym nie należy tego dosłownie z angielskiego tłumaczyć. A nie należy bo obejmuje ono wszystkie sygnały jakie mogą propagować się wewnątrz i na zewnątrz układu i jak już to odnosi się do możliwych zmian tegoż sygnału (środowisko zakłada, że każdy dowolny sygnał może być regularnym ciągiem impulsów prostokątnych o danym wypełnieniu, czasie trwania, okresu i częstotliwości powtarzania, czyli może być właściwie rozumianym sygnałem zegarowym - oczywiście ty wiesz, że tak być nie musi, ale układ nie wie o tym i musi takie założenia czynić, szczególnie, że nawet jakbyś chciał to mu nie powiesz, że tak nie będzie, bo nie ma jak, zwłaszcza z poziomu języka opisu sprzętu tj. takiego VHDL-a, Verilog-a itp. Niemniej właśnie z faktu, że takie założenie czynione wynika wspomniany skrót, a tym samym stąd wynika nieintuicyjne pojecie "clock signal"-a). To jest taki fakt, o którym nikt praktycznie nie mówi (ja w praktyce sam się dopiero dowiedziałem na bazie własnego doświadczenia).

- Nie ma czegoś takiego jak piny "kombinatoryczne" - kolejny przykład, że się nie tłumaczy dosłownie pewnych rzeczy z angielskiego na "pałę" czy z "automatu" - są bowiem tylko albo po prostu piny albo po prostu po polsku wyprowadzenia jako zbiorcze określenie wejść i wyjść (nie ma tu znaczenia czy logika jest kombinacyjna czy sekwencyjna czy może ma charakter pamięciowy lub mieszany). Poza tym po polsku "kombinatoryczne" to mogą być rachunki w matematyce, gdzie masz właśnie dział zwany "kombinatoryką", w której liczysz kombinacje, wariancje, permutacje itp. (wiedza ze szkoły średniej, a przynajmniej ja jeszcze miałem) - Innymi słowy: angielskie "combinatorial" to nie to samo co polskie "kombinatoryczne", a po polsku w elektronice cyfrowej cokolwiek może być tylko i wyłącznie "kombinacyjne".

Co do problemu natomiast: chodzi o to, że ISE tam gdzie możliwe próbuje wszystko przełożyć na logikę sekwencyjną tj. na przerzutniki D (wszak układy FPGA przewidziane są do pracy głównie jako układy sekwencyjne czyli synchroniczne, a rzadziej jako układy kombinacyjne czyli asynchroniczne). W jaki sposób? Otóż taki, że próbuje to czynić np: w stosunku do tego rodzaju warunków:

if (warunek_1) to
 jakis_sygnal<=wartosc_1;
elsif (warunek_2) to
 jakis_sygnal<=wartosc_2;
elsif (warunek_3) to
 jakis_sygnal<=wartosc_3;
end if;

Można zapytać, a co ma to wspólnego z przerzutnikiem D? Ano to ma, że w tym warunku środowisko potraktuje, że warunek_1 i warunek_2 to resety lub wpisania asynchroniczne, natomiast warunek_3 to sygnał zegarowy - i o ten warunek właśnie sapie się środowisko, bo według niego zamiast warunku_3 dosłownie powinno być: rising_edge(coś_tam) lub falling_edge(coś_tam) lub (coś_tam'event and coś_tam='1') lub (coś_tam'event and coś_tam='0'). Krótko mówiąc: ISE tak usilnie chciałoby potraktować ten warunek jako przerzutnik D (a nie może bo właśnie nie ma tych instrukcji, które przedstawiłem). I ponieważ nie może tego zrobić to przyjmuje, że "jakis_sygnał" nie jest tworzony synchronicznie, a asynchronicznie, a co za tym idzie tworzony jest przez logikę kombinacyjną (czyli wymienione w logach "combinatorial logic", które stało się źródłem błędu przy tłumaczeniu). To samo zachodzi dla tego rodzaju warunków:

if (warunek_1) to:
  if (warunek_1_1) to:
     jakis_sygnal<=wartosc_1_1; 
  elsif (warunek_1_2) to:
      jakis_sygnal<=wartosc_1_2;
  elsif (warunek_1_3) to:
      jakis_sygnal<=wartosc_1_3;
  end if;
end if;

W tym przypadku środowisko uzna warunek_1 od razu jako sygnał zegarowy, a tym samym spróbuje ten warunek potraktować jako przerzutnik D bez kasowań czy wpisów synchronicznych (i się znów przyczepi, że zamiast warunek_1 powinno być:

rising_edge(cos_tam) lub falling_edge(cos_tam) lub (cos_tam'event and cos_tam='1') lub (cos_tam'event and cos_tam='0'))

Można przy tym wszystkim zapytać, a czemu w tego rodzaju warunki próbuje się "wpychać" środowisko i próbuje je sprowadzić do przerzutników? Bo po prostu po pierwsze w VHDL-u przyjęte jest nieformalnie (czy też w drodze praktyki), że przerzutnik D opisany jest kodem:

if (reset_lub_wpis = jakas_wartosc) to:
  sygnał_1<=jakas_wartość_1;
elsif (rising_edge(cos_tam)) to: --lub falling_edge lub cos_tam'event and cos_tam='1' lub 
                                                cos_tam'event and cos_tam='0'
  sygnał_1<=jakas_wartosc_2;
  -- przypisania w ewentualnych innych warunkach
end if;

lub też kodem:

if (rising_edge(cos_tam)) to: --lub falling_edge lub cos_tam'event and cos_tam='1' lub 
                                                   cos_tam'event and cos_tam='0'
  sygnał_1<=jakas_wartosc_2;
  -- przypisania w ewentualnych innych warunkach
end if;

Jak można zauważyć jest gigantyczne podobieństwo między tymi warunkami, a tamtymi - i tylko dlatego to środowisko tak uparcie próbuje "wpychać się" w tamte wcześniejsze warunki i próbuje je sprowadzić do przerzutników D. Natomiast jest jeszcze drugi powód: bo generalnie można by to odpuścić - ale z drugiej strony nawet dobrze, że to nie jest odpuszczane, bo jednak w dzisiejszym świecie układy generalnie są sekwencyjne tj. synchroniczne i tylko w takiej formie się je wykonuje. A dlaczego? Bo nie trzeba się martwić o zmienność opóźnień (szczególnie, gdy chcemy się uniezależnić od nich - ot to jest właśnie wada układów FPGA), a także można precyzyjnie w tej samej chwili zmienić wartości wielu sygnałów (coś, co jest niemożliwe w przypadku układów kombinacyjnych, czy też asynchronicznych). I z racji tego środowisko właśnie próbuje ci wskazać te elementy układu (a właściwie jego designu), które można przerobić właśnie na synchroniczne.

Niemniej przekładając to wszystko teraz na twój kod: jak można zauważyć na podstawie logów ISE czepia się wyłącznie o maszynę stanów czyli komponent C6 lub też DSASM jak go nazwałeś (multiplekser C4 nie ma z tym nic wspólnego, dlatego pozostaw go w spokoju). I jak widać chodzi mu o sygnały: SELO i NEXT_STATE, przy czym w pierwszym przypadku widać, że sygnał tworzony jest docelowo z użyciem bramki OR, a w drugim z użyciem bramki NOT. Czemu mu o te sygnały chodzi? Ano dlatego, że jak można zauważyć w różnych stanach SELO ma różne wartości, przy czym w niektórych te wartości powtarzają się. Co więcej sygnał ten nie występuje w stanach: S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError, S9UnknowError i S10Awaria. Tym samym kompilator środowiska traktuje, że całość to nic innego jak poniższy warunek:

if (stan1 zaszedł LUB stan2 zaszedł LUB stan3 zaszedł itd.) to:
  SELO<= wartosc_1;
elsif (stan4 zaszedł LUB stan5 zaszedł itd.) to:
  SELO<= wartosc_2;
elsif (stan6 zaszedł LUB stan7 zaszedł itd.) to:
  SELO<= wartosc_3;
end if;

A skoro tak właśnie zachodzi ta wspomniana wcześniej kołomyja, że "if" i pierwszy "elsif" to resety lub wpisy asychroniczne, a ostatni "elsif" to sygnał zegarowy tworzony poprzez wielowejściową bramkę OR i środowisko chce w to wepchać przerzutnik D (no ale bidny nie może, bo nie jest wspomniane, że to ma reagować na zbocze narastające lub opadające, a zamiast tego jest powiedziane, że występuje tu bramka OR). Poza tym z racji tego, że nie we wszystkich stanach występuje SELO (nie ma go w stanach: S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError, S9UnknowError i S10Awaria), a tym samym kompilator nie używa "else" dla wspomnianych stanów to i środowisko próbuje wciskać przerzutniki D (bo jednak na samym końcu jest "elsif" - gdyby był "else" to i by nie próbował). Z kolei w przypadku NEXT_STATE kompilator przyjmie w skrócie taki warunek:

if (not(stan1)) to:
  if (stan2 zaszedł itd.) to:
     NEXT_STATE<=JAKIS_STAN_1;
  elsif (stan3 zaszedł lub stan4 zaszedł itd.) to:
     NEXT_STATE<=JAKIS_STAN_2;
  end if;
end if;

A czemu tak? Bo w stanie: S10Awaria nie masz napisanego co ma się dziać z NEXT_STATE i co więcej, jest to jedyny stan, w którym nie ma tego sygnału (a tym samym znów odpada "else", żeby ten stan uwzględnić i znów na końcu będzie "elsif", przez którego środowisko będzie próbowało wciskać przerzutnik D). A skoro tak to kompilator podejdzie właśnie tak, że jeśli nie zachodzi ten stan (czyli spełniona jest NEGACJA) to wtedy jeśli są pozostałe dane stany to przypisze taką,a taką wartość (innymi słowy: powstanie sygnał zegarowy w oparciu o bramkę NOT i opcjonalne bramki ze względu na zagnieżdzony warunek - ale to dla środowiska się nie liczy - ważne, że widzi NOT-a w warunku po prostu i już próbuje robić to co próbuje). I tyle 🙂

Jak mogłeś zauważyć przy okazji, w obydwu warunkach środowisko czepia się przy okazji, że zegary są "bramkowane" bo np: używane są bramki OR czy NOT (praktyka, która jest zła, bo wprowadza opóźnienia i "zniekształca sygnał zegarowy" - coś co zresztą pojawiło ci się po próbie zmiany multipleksera C4 tj, że masz "Gated Clock" - najlepiej ten problem ilustruje ten obrazek: http://4.bp.blogspot.com/_Se0VANaI9uM/SAbOzKBXwVI/AAAAAAAAATU/XFaTeFp0f84/s1600/latch_free_clock_gating.jpeg)

  • Lubię! 1
Link do komentarza
Share on other sites

[quote="JTyburski"

Niemniej przekładając to wszystko teraz na twój kod: jak można zauważyć na podstawie logów ISE czepia się wyłącznie o maszynę stanów czyli komponent C6 lub też DSASM jak go nazwałeś (multiplekser C4 nie ma z tym nic wspólnego, dlatego pozostaw go w spokoju). I jak widać chodzi mu o sygnały: SELO i NEXT_STATE, przy czym w pierwszym przypadku widać, że sygnał tworzony jest docelowo z użyciem bramki OR, a w drugim z użyciem bramki NOT. Czemu mu o te sygnały chodzi? Ano dlatego, że jak można zauważyć w różnych stanach SELO ma różne wartości, przy czym w niektórych te wartości powtarzają się. Co więcej sygnał ten nie występuje w stanach: S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError, S9UnknowError i S10Awaria. Tym samym kompilator środowiska traktuje, że całość to nic innego jak poniższy warunek:

if (stan1 zaszedł LUB stan2 zaszedł LUB stan3 zaszedł itd.) to:
  SELO<= wartosc_1;
elsif (stan4 zaszedł LUB stan5 zaszedł itd.) to:
  SELO<= wartosc_2;
elsif (stan6 zaszedł LUB stan7 zaszedł itd.) to:
  SELO<= wartosc_3;
end if;

A skoro tak właśnie zachodzi ta wspomniana wcześniej kołomyja, że "if" i pierwszy "elsif" to resety lub wpisy asychroniczne, a ostatni "elsif" to sygnał zegarowy tworzony poprzez wielowejściową bramkę OR i środowisko chce w to wepchać przerzutnik D (no ale bidny nie może, bo nie jest wspomniane, że to ma reagować na zbocze narastające lub opadające, a zamiast tego jest powiedziane, że występuje tu bramka OR). Poza tym z racji tego, że nie we wszystkich stanach występuje SELO (nie ma go w stanach: S5Overload, S6TooLongOper, S7NoPowerSensors, S8PositionError, S9UnknowError i S10Awaria), a tym samym kompilator nie używa "else" dla wspomnianych stanów to i środowisko próbuje wciskać przerzutniki D (bo jednak na samym końcu jest "elsif" - gdyby był "else" to i by nie próbował). Z kolei w przypadku NEXT_STATE kompilator przyjmie w skrócie taki warunek:

if (not(stan1)) to:
  if (stan2 zaszedł itd.) to:
     NEXT_STATE<=JAKIS_STAN_1;
  elsif (stan3 zaszedł lub stan4 zaszedł itd.) to:
     NEXT_STATE<=JAKIS_STAN_2;
  end if;
end if;

A czemu tak? Bo w stanie: S10Awaria nie masz napisanego co ma się dziać z NEXT_STATE i co więcej, jest to jedyny stan, w którym nie ma tego sygnału (a tym samym znów odpada "else", żeby ten stan uwzględnić i znów na końcu będzie "elsif", przez którego środowisko będzie próbowało wciskać przerzutnik D). A skoro tak to kompilator podejdzie właśnie tak, że jeśli nie zachodzi ten stan (czyli spełniona jest NEGACJA) to wtedy jeśli są pozostałe dane stany to przypisze taką,a taką wartość (innymi słowy: powstanie sygnał zegarowy w oparciu o bramkę NOT i opcjonalne bramki ze względu na zagnieżdzony warunek - ale to dla środowiska się nie liczy - ważne, że widzi NOT-a w warunku po prostu i już próbuje robić to co próbuje). I tyle 🙂

Jak mogłeś zauważyć przy okazji, w obydwu warunkach środowisko czepia się przy okazji, że zegary są "bramkowane" bo np: używane są bramki OR czy NOT (praktyka, która jest zła, bo wprowadza opóźnienia i "zniekształca sygnał zegarowy" - coś co zresztą pojawiło ci się po próbie zmiany multipleksera C4 tj, że masz "Gated Clock" - najlepiej ten problem ilustruje ten obrazek: http://4.bp.blogspot.com/_Se0VANaI9uM/SAbOzKBXwVI/AAAAAAAAATU/XFaTeFp0f84/s1600/latch_free_clock_gating.jpeg)

Jakub,

bardzo Ci dziękuję za tak wyczerpującą odpowiedź. Nareszcie wszystko stało się dla mnie jasne 😃 . Stawiam piwo - bardzo mi pomogłeś.

Pozdrawiam

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Drobiazg 😃

Jakub,

dla mnie to nie był drobiazg, tylko problem z którym borykałem się już od dłuższego czasu. Dobrze, że są osoby takie jak Ty i Elvis, które chcą się dzielić swoją wiedzą 😃

Dzięki twojej odpowiedzi zmodyfikowałem kod mojego projektu, tak, że opisany problem już nie występuje.

Pozdrawiam

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.