Maciej G.

Maciej G. Projektant /
Programista, Famor
S.A.

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Cześć,

rozszerzyłem działanie sterownika rolet na FPGA o obsługę kilku dodatkowych sytuacji awaryjnych (przeciążenie silnika, brak zasilania czujników krańcowych , błąd pozycjonowania czujników krańcowych - oba aktywne naraz).

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.

Dodałem rejestr statusu - STATUSO (4 bity) wyprowadzone na 4 LEDy z płytki Elbert V2.
Obsługa błędów, które mogą wystąpić we wszystkich stanach dodałem do cżęści sekwencyjnej maszyny stanów
        
elsif ((krancEND = '0') and (krancPOC = '0')) then--tu obsluga bledow dla all states
CURRENT_STATE <= S8PositionError; --Blad czujnikow krancowych
elsif (NoPowerSensors = '0') then
CURRENT_STATE <= S7NoPowerSensors;-- Brak zasilania czujnikow
elsif (OVERLOAD = '0') then
CURRENT_STATE <= S5Overload;-- Przeciazenie silnika (za duzy prad plynie przez mostek)
else


Maszyna stanów działa w większości przypadków poprawnie - poza wejściem w stan awaryjny S6TooLongOper

Po odliczeniu czasu przez timer (czekanie na zmianę stanów czujników krańcowych) następuje zmiana stanu, lecz nie są zapalane żadne diody w rejestrze statusu (nie świeci się nic).
Przed rozbudową maszyny stanów przejście w ten stan awaryjny było poprawne (z timerów wewnętrznych) - "popsuło" się po dodaniu obsługi stanów awaryjnych wspólnych.

Plik źródłowy maszyny stanów - DMASM.vhd



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 zamykania
blokada_Otw : out STD_LOGIC;--gdy 0 blokada otwierania
SELO : out STD_LOGIC_VECTOR (1 downto 0);--wybor pwm dla multiplexera (jeden z czterech PWM)
AWARIA : out STD_LOGIC;--gdy 0 awaria ukladu
STATUSO : out STD_LOGIC_VECTOR (3 downto 0);--Opis stanu ukladu (Praca/Awaria): MSB = 0 praca, MSB = 1 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);
signal CURRENT_STATE, NEXT_STATE : STATE;

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

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;
end if;
end if;
elsif (CLK' event and CLK = '1') then
if (CURRENT_STATE = S11DomkZamykanie) and (NEXT_STATE = S11DomkZamykanie) then
licznik <= licznik + 1; --Odliczanie czasu domkniecia zamykanie
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; --Odliczanie czasu domkniecia otwieranie
if licznik = LICZNIK_LIMIT then
licznik <= b"0000000000000000000000000";
CURRENT_STATE <= S0Otwarte;
end if;
elsif ((krancEND = '0') and (krancPOC = '0')) then--tu obsluga bledow dla all states
CURRENT_STATE <= S8PositionError; --Blad czujnikow krancowych
elsif (NoPowerSensors = '0') then
CURRENT_STATE <= S7NoPowerSensors;-- Brak zasilania czujnikow
elsif (OVERLOAD = '0') then
CURRENT_STATE <= S5Overload;-- Przeciazenie silnika (za duzy prad plynie przez mostek)
else
CURRENT_STATE <= NEXT_STATE;
end if;
end if;
end process;

COMB : process (CURRENT_STATE, RST, OVERLOAD, bt1, bt2, krancEND, KrancPOC,
NoPowerSensors, 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') and (krancPOC = '0')) then
NEXT_STATE <= S1ZamykanieLocal;
elsif (RemoteZamykanie = '0') then
NEXT_STATE <= S4ZamykanieRemote;
else
NEXT_STATE <= S0Otwarte;
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 (TIM2LONGZ = '1') then -- gdy jest awaria(Timer z entity WEKTORY_WYPELNIEN)
STATUSO <= "1010";
NEXT_STATE <= S6TooLongOper;
else -- gdy nie ma awarii
if ((krancEND = '0') and (krancPOC = '1')) then
NEXT_STATE <= S11DomkZamykanie;
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') and (krancEND = '0')) then
NEXT_STATE <= S3OtwieranieLocal;
else
NEXT_STATE <= S2Zamkniete;
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 (TIM2LONGO = '1') then -- gdy jest awaria
NEXT_STATE <= S6TooLongOper;
else -- gdy nie ma awarii
if ((krancPOC = '0') and (krancEND = '1')) then
NEXT_STATE <= S12DomkOtwieranie;
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 (TIM2LONGZ = '1') then -- gdy jest awaria
STATUSO <= "1010";
NEXT_STATE <= S6TooLongOper;
else -- gdy nie ma awarii
if ((krancEND = '0') and (krancPOC = '1')) then
NEXT_STATE <= S11DomkZamykanie;
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 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';
when S11DomkZamykanie => DIRPin <= '0';--Generacja malejacych wypelnien zamykanie (WEKTORY_REVERSE)
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";
NEXT_STATE <= S11DomkZamykanie;
when S12DomkOtwieranie => DIRPin <= '1';--Generacja malejacych wypelnien otwieranie (WEKTORY_REVERSE)
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";
NEXT_STATE <= S12DomkOtwieranie;
--when others => DIRPin <= '1';--stan S4Awaria
-- SLPPin <= '0';--blokada mostka
-- pb1_Zam <= '1';
-- pb2_Otw <= '1';--klawisze nieaktywne
-- blokada_Zam <= '0';
-- blokada_Otw <= '0';
-- AWARIA <= '0'; --sygnal aktywny
-- LEDZAMKNIETE <= '0';
-- LEDOTWARTE <= '0';
-- LEDPRACA <= '0';
-- LEDAWARIA <= '1';
-- STATUSO <= "1100";
-- NEXT_STATE <= S10Awaria;
end case;
end process;
end BEHAVE;



Entity: WEKTORY_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 WEKTORY_WYPELNIEN is
generic
(
NBit : natural := 30;
Div : natural := 20_000_000 --20s
);
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 WEKTORY_WYPELNIEN;

architecture BEHAVE of WEKTORY_WYPELNIEN is

signal ADDRESS : integer range 0 to 32 := 0;
signal TEMP : integer range 0 to 10_000_000 := 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 GENERACJA2_SERII_WEKTOROW : std_logic := '0';

signal KONIEC_GENERACJI_WEKTOROW : std_logic := '0';
-- okreslenie kiedy koniec generacji serii wektorow

signal OPOZNIENIE_BUTTONA : integer range 0 to 1_000_000 := 0;

signal cnt : std_logic_vector(Nbit - 1 downto 0) := (others => '0'); --licznik timera czasu otwarcia

type mem is array (0 to 2 ** 5 - 1) of std_logic_vector(7 downto 0);
constant my_Rom : mem := (
0 => "00000011",
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 < 10_000) 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';
GENERACJA2_SERII_WEKTOROW <= '0';
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 < 250_000) then --okolo 0,25 s
TEMP <= TEMP + 1;
else
TEMP <= 0;
if (ADDRESS < 31) then
ADDRESS <= ADDRESS + 1;
else
KONIEC_GENERACJI_WEKTOROW <= '1';
GENERACJA_SERII_WEKTOROW <= '0';
GENERACJA2_SERII_WEKTOROW <= '1';
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 (blokada = '0') then
DATA <= "00000000";
else
if (GENERACJA_SERII_WEKTOROW = '1') and (GENERACJA2_SERII_WEKTOROW = '0') then-- gdy trwa generacja -- wektorow
DATA <= my_rom(ADDRESS);
else
if (GENERACJA2_SERII_WEKTOROW = '1') then
DATA <= "11100000"; --Duze wypelnienie PWM: stan czekania na zmiane stanu czujnikow krancowych
else -- gdy generacja nie trwa
DATA <= "00000000";
end if;
end if;
end if;
end if;
end process;

-- Timer do odliczania czasu otwierania (gdy za dlugo trwa operacja - zmiana stanu)

process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if ((rst = '0') or (blokada = '0')) then
cnt <= (others => '0');
timerO <= '0';
else
if ((GENERACJA_SERII_WEKTOROW = '1') or (GENERACJA2_SERII_WEKTOROW = '1')) then
if cnt < Div then
cnt <= cnt + 1;
else
cnt <= (others => '0');
timerO <= '1';
end if;
end if;
end if;
end if;
end process;

end BEHAVE;


Plik projektu głównego: Project.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
OVERLOAD : inout 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 : inout 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 : 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
);

C5 : WEKTORY_WYPELNIEN
port map(clk_1MHz, pb1_Zam, blokada_Zam, RST, TIM2LONGZ, data1_signal);
C6 : WEKTORY_WYPELNIEN
port map(clk_1MHz, pb2_Otw, blokada_Otw, RST, TIM2LONGO, data2_signal);
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);

--WyjPWM <= pwm1_out when DIRPIN = '0' else pwm2_out;

end Behavioral;


Nie wiem, czy dość dokładnie opisałem problem, w razie konieczności mogę go doprecyzować.
Macie może jakieś podejrzenia, gdzie tkwi błąd?

Będę wdzięczny za wszelkie uwagi.

PozdrawiamTen post został edytowany przez Autora dnia 13.10.17 o godzinie 09:49
Jakub Tyburski

Jakub Tyburski Asystent dydaktyczny
- Wojskowa Akademia
Techniczna w War...

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Z poziomu samego kodu czy też czystego języka (nie uzględniajac natury ukladu czy zawiłości środowiska) nie widzę błedów w koncepcji (i to mimo lekkiego pogmatwania, ktore jednak prowadzi do zamierzonego celu). Natomiast może być tak, że środowisko coś w syntezie zrobiło po swojemu po prostu z diodami, nie naruszając reszty funkcjonalności tak jak napisałeś (zwłaszcza, że w tym stanie S10Awaria nie ustaliłeś jaka ma być wartość tego rejestru, mając w domyśle to, żeby w rejestrze była wartość poprzedniego stanu, z którego doszło do wejścia w ten stan, co prowadzi do tworzenia zatrzasków - i pewnie tą drogą niechcący coś się zeruje i nic ci się dlatego nie pokazuje- coś co ja np kiedyś w jednej z rzeczy miałem w Quartusie). Sprawdź w podglądzie RTL czy czasem serio się zatrzaski nie porobiły.Ten post został edytowany przez Autora dnia 14.10.17 o godzinie 11:01
Maciej G.

Maciej G. Projektant /
Programista, Famor
S.A.

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Jakub T.:
Z poziomu samego kodu czy też czystego języka (nie uzględniajac natury ukladu czy zawiłości środowiska) nie widzę błedów w koncepcji (i to mimo lekkiego pogmatwania, ktore jednak prowadzi do zamierzonego celu). Natomiast może być tak, że środowisko coś w syntezie zrobiło po swojemu po prostu z diodami, nie naruszając reszty funkcjonalności tak jak napisałeś (zwłaszcza, że w tym stanie S10Awaria nie ustaliłeś jaka ma być wartość tego rejestru, mając w domyśle to, żeby w rejestrze była wartość poprzedniego stanu, z którego doszło do wejścia w ten stan, co prowadzi do tworzenia zatrzasków - i pewnie tą drogą niechcący coś się zeruje i nic ci się dlatego nie pokazuje- coś co ja np kiedyś w jednej z rzeczy miałem w Quartusie). Sprawdź w podglądzie RTL czy czasem serio się zatrzaski nie porobiły.

Jakub jak zwykle można na Ciebie liczyć. Ja też nie mogłem znaleźć błędu - zrobię dokładnie jak mi poradziłeś.

Wielkie dzięki i pozdrawiam :)
Maciej G.

Maciej G. Projektant /
Programista, Famor
S.A.

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Cześć,

poświeciłem wczoraj kilka godzin na znalezienie przyczyny błędu - bez skutku.
Podgląd maszyny stanów (RTL) jest na tyle złożony, że nie jestem w stanie go przeanalizować.
Wypróbowałem wczoraj kilka pomysłów, wszystkie zakończyły się porażką.
Inicjowanie zmiany stanu z timera skutkuje nie wyświetlaniem statusu niezależnie od tego do jakiego stanu przejście bym ustawił (np. do S5OVERLOAD zamiast do S6TooLongOper).
Wygląda na to, że połączenie między WEKTORY_WYPENIEN a maszyną stanów nie działa prawidłowo (wyjście timera, które wchodzi do DMASM).

Mógłbym to zostawić tak jak jest, ale trudno mi się pogodzić z myślą, iż nie umiem osiągnąć zaplanowanych rezultatów.

Pozdrawiam
Maciej G.

Maciej G. Projektant /
Programista, Famor
S.A.

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Już chyba wiem co było przyczyną - sygnał z timera trwał za krótko (1 takt zegara) - ponieważ wyjście z timera było na liście wrażliwości dla procesu COMB zmiana stanu była inicjowana, ale maszyna stanów "nie zdążyła" w czasie gdy sygnał z timera był równy '1' zmienić stanu.

Gdy na końcu instrukcji case zmieniłem iłem warunek dla "when others" mam prawidłowo sygnalizowany stan S6TooLongOper:

when others =>null";

na

when others => STATUSO <= "1010";

Pozdrawiam
Jakub Tyburski

Jakub Tyburski Asystent dydaktyczny
- Wojskowa Akademia
Techniczna w War...

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

No niezupełnie sięzgodzę z tym timerem - w tym generowaniu wektorów to GENERACJA_SERII_WEKTOROW i GENERACJA2_SERII_WEKTOROW - zawsze któraś z nich będzie jedynką - skoro tak to timer (czy też właściwiej po prostu licznik lub counter bo to nie mikroprocesor) będzie się realizował cały czas i cały czas na jego wyjściu będzie jedynka, która zostanie wyłączona dopiero w momencie przejścia do stanu nr 6 (sygnał związany z blokadą). Więc ten pomysł że będzie przez jeden takt zegara nie zajdzie (początkowo analizując ten kod i to rozpatrywałem tj. że pewnie tylko jeden impuls zegara i że zwyczajnie nie jest to łapane, ale, że na wyjściu timera będzie ciągle jedynka i minie czas zanim jedynka zostanie wyłączona, więc tą hipotezę odrzuciłem). Co do podglądu RTL - chodziło mi wyłącznie o wyjścia, żeby zobaczyć, czy zatrzaski (latche) się nie porobiły na samych wyjściach, a nie cały układ rozpatrywać (co mnie zaskoczylo, ze sie podjales, choć nie o to mi chodziło). Takie ot proste sprawdzenie, żeby tylko potwierdzić, że dla syntezy w środowisku kod jest "niekompletny" (bo tak jak mówiłem - kod z poziomu samego czystego języka jest OK i da taki, a siaki rezultat - ale to bez przekładania na układ) i tylko stwierdzić czy chodzi po prostu o marne diody - bo wtedy by wystarczyło albo dopisać STATUSO w stanie awarii nr 10, albo dopisać dopisać "WHEN OTHERS" i zobaczyć czy to dla środowiska wystarczy (w kodzie, którym podałeś WHEN OTHERS było całkowicie zakomentowane). I już :) Niemniej widzę, że pośrednio przypadkiem do tego doszedłeś, a także doszedłeś do jednej rzeczy - że czasem trzeba pisać przesadnie jak dal dziecka, żeby środowisko coś zajarzyło :) I że tylko chodzi wyłącznie o samą syntezę, a nie język :)Ten post został edytowany przez Autora dnia 15.10.17 o godzinie 12:47
Maciej G.

Maciej G. Projektant /
Programista, Famor
S.A.

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

Jakub T.:
No niezupełnie sięzgodzę z tym timerem - w tym generowaniu wektorów to GENERACJA_SERII_WEKTOROW i GENERACJA2_SERII_WEKTOROW - zawsze któraś z nich będzie jedynką - skoro tak to timer (czy też właściwiej po prostu licznik lub counter bo to nie mikroprocesor) będzie się realizował cały czas i cały czas na jego wyjściu będzie jedynka, która zostanie wyłączona dopiero w momencie przejścia do stanu nr 6 (sygnał związany z blokadą).

Przepraszam, za to ale wczoraj zmieniłem kod timera w WEKTORY_WYPELNIEN (nie wysyłałem już zmain w kodzie z wczorajszego dnia). Oto zmiana:

-- Timer do odliczania czasu otwierania
process(CLK)
begin
if (CLK'event and CLK='1') then
if ((rst = '0') or (blokada = '0')) then
cnt <= (others => '0');
timerO <= '0';
else
if ((GENERACJA_SERII_WEKTOROW = '1') or (GENERACJA2_SERII_WEKTOROW = '1')) then
if cnt < Div then
timerO <= '0';--Tutaj zmiana - dodana ta linia
cnt <= cnt+1;
else
cnt <= (others=>'0');
timerO <= '1';
end if;
end if;
end if;
end if;
end process;
Nie wiem co dokładnie było przyczyną błędu - niemniej przekonałeś mnie, że zawsze trzeba podawać kod VHDL dla nie branych pod uwagę przypadków ;)

Pozdrawiam
Jakub Tyburski

Jakub Tyburski Asystent dydaktyczny
- Wojskowa Akademia
Techniczna w War...

Temat: Maszyna stanów - błąd zmiany stanu z Timera (VHDL)

A widzisz - to zmienia postać rzeczy po dodaniu tej linijki, którą pokazałeś - wtedy zgadza się - będzie generacja sygnału z licznika na czas jednego taktu zegara . I wtedy z punktu widzenia układu nie powinno to zadziałać, jako że masz odrębne komponenty, które będą się zachowywały jako odrębne - jeden będzie coś wysyłał, ale drugi w tym czasie pobierze na tym samym takcie zegara starą wartość (jako, że jednak jakiś czas trwa propagacja sygnału z jednego komponentu do drugiego i nie ma szans, aby ten drugi zdążył nową wartość "chwycic"). Innymi słowy - ten drugi chwyci nową wartość na drugim takcie zegara, ale że wtedy już nie będzie tego sygnału z licznika to i de facto nigdy nie dojdzie do przejścia do stanu nr 6 . Będzie się to zachowywało innymi słowy jak architektura potokowa w byle procesorze czy mikroprocesorze (tam też masz kilka komponentów złączonych szeregowo i pracujących na tym samym zegarze) :) Więc twoje obawy były jak najbardziej nie bez podstawt i słusznie zauważyłeś ten problem z "jednym taktem zegara" :) Niemniej ciekawe, że działa mimo, że to zostawiłeś i tylko dodałeś "WHEN OTHERS" (może czas propagacji sygnału z jednego do drugiego komponentu jest wystarczająco mały, albo do maszyny stanów z pewnym opóźnieniem dociera zegar, jako że i to podlega opóźnieniu, albo i jedno i drugie zachodzi i szczęśliwym zbiegiem okoliczności spasowało się - czasem i taki zbieg okoliczności może zajść). Najlepsze jest jednak to, że jednak tak będzie ale tylko dla układów - w przypadku czystej symulacji (bez uwzględnienia układu) to będzie tak, że od razu na jednym takce zegara i wysłanie i odebranie sygnału będzie (ale dlatego, że tam założenie jest takie, że sygnał nie propaguje się z opóźnieniem, tylko natychmiast). I też spokojnie z tym, że nie wiesz co dokładnie się stało - to jest właśnie jak z programowaniem w tradycyjnym sensie i tymi memami zwłaszcza zagranicznymi, gdzie pokazują, że "nie działa - jesteś wkurwiony i nie wiesz dlaczego, działa - jestem zadowolony, ale i tak nie wiesz dlaczego" - więc się tym nie przejmuj (jak zaczynałem to tak samo miałem i do dzisiaj czasem, ale jednak mam) :)



Wyślij zaproszenie do