Šoreiz apskatīsim vienu no FPGA izmantošanas piemēriem un stāvokļu mašīnas realizāciju.
FPGA (programmējamā integrālā shēma) ir balstīta uz ciparu elektronikas principiem, kur programmas koda izpilde notiek paralēli, nevis secīgi, proti, visas darbības tiek realizētas procesos, kur katrs no tiem ir atbildīgs par konkrētas darbības veikšanu, piemēram, datu izvadi, pienākošo takts signālu skaitīšanu, aprēķinu veikšanu u.c.
Kas ir stāvokļu mašīna?
Par stāvokļu mašīnu sauc sistēmu, kas apraksta izmaiņas diskrētos laika momentos atkarībā no ieejas datiem un iepriekšējā stāvokļa, proti, to var realizēt programmas kodā, kur tas tiek sadalīts stāvokļos, kur katrā no tiem tiek veiktas konkrētas darbības, kur pārslēgšanās uz nākamo stāvokli notiek tikai tad, kad iepriekšējā stāvoklī ir izpildītas visas nepieciešamās darbības (piešķires), kad ieejās tiek saņemtas atbilstošas signālu vērtības, kuras paziņo par nepieciešamību pārslēgties uz nākamo stāvokli, proti, šāda programmas koda realizācija palīdz izvairīties no kļūdām un garantē pareizu iekārtas darbību.
1.1.att. Stāvokļu mašīnas realizācija, kad tiek izvēlēts ātrais PWM režīms
1.2.att. Stāvokļu mašīnas realizācija, kad tiek izvēlēts precīzas fāzes PWM režīms
Programmas koda izstrāde sākās ar to, ka vispirms tika izveidota neliela blokshēma, pēc kuras sekoja programmas koda izveide. Programmas kods tika veidots VHD (Very High Speed Integrated Circuit Hardware Description) valodā. Programmas kods tika veidots tā, lai lietotājs varētu izvēlēties vienu no diviem PWM regulatora režīmiem, protams, lai lietotājam būtu pieejama iespēja mainīt PWM regulatora izšķirtspēju. Programmas kods tika sadalīts 6 paralēlos procesos, kuri savstarpēji konkurēja, kur katrā no tiem darbību izpilde bija secīga.
// Informācija par izmantoto FPGA un darba autoru
--------------------------------------------------------------------------------
-- Targeted device: <Family::IGLOO> <Die::AGLN250V2Z> <Package::100 VQFP>
-- Author: <Peteris Bitans>
--------------------------------------------------------------------------------
// Nepieciešamo bibliotēku pievienošana
// Nepieciešamo bibliotēku pievienošana
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
// Entītijas daļa un ģeneriķa izmantošana, lai vēlāk varētu izmainīt izšķirtspēju (bitos)
// PWM (impulsa platuma modulācija) režīmi --> ātrā PWM - 1, precīzas fāzes PWM - 2 (sākotnēji ir izvēlēts ātrais PWM režīms)
entity PWM is
generic(RESOLUTION: integer:=8;
PWM_mode: integer:=1
);
);
// Tiek definētas pieslēgvietas (porti)
port (
RESET, CLK, CLK_EN, SET_DUTY : IN std_logic;
DUTY : IN std_logic_vector(RESOLUTION-1 downto 0);
RESET, CLK, CLK_EN, SET_DUTY : IN std_logic;
DUTY : IN std_logic_vector(RESOLUTION-1 downto 0);
// Aizpildījuma vērtības garums bitos (8-1 downto 0 jeb 8 bitu)
PWM_OUT, PWM_N_OUT: OUT std_logic
);
end PWM;
end PWM;
architecture architecture_PWM of PWM is
constant MODE: integer:=PWM_mode;
constant Resolution_bits: integer:=RESOLUTION;
type state is (PWM_MODE_SELECT, PHASE_CORRECT, FAST_PWM, UP, DOWN, ZERO);
// Cik stāvokļi, tik vērtības
// Cik stāvokļi, tik vērtības
signal Direction : std_logic:='0';
// Skaitītāja virziena "karogs"
// Skaitītāja virziena "karogs"
signal Duty_cycle : std_logic_vector(RESOLUTION-1 downto 0):=(others=>'0');
// Signāls aizpildījuma vērtibas pagaidu uzglabāšanai
// Signāls aizpildījuma vērtibas pagaidu uzglabāšanai
signal Counter : std_logic_vector(RESOLUTION-1 downto 0):=(others=>'0');
// Nosaka skaitītāja bitu skaitu, kas nosaka maksimālo iespējamo vērtību
// Nosaka skaitītāja bitu skaitu, kas nosaka maksimālo iespējamo vērtību
signal NextState, PresentState : state;
// Divi "state" tipa signāli --> pašreizējais stāvoklis un nākamais stāvoklis
// Divi "state" tipa signāli --> pašreizējais stāvoklis un nākamais stāvoklis
signal CNT : integer:=0;
signal V_flag : std_logic:='0';
begin
// Skaitītāja process
// Jutības saraksts
process(RESET, CLK, CLK_EN, Direction, V_flag)
begin
if RESET = '1' then
if CLK = '1' and CLK'event and CLK_EN='1' then
if ((Direction = '1') and (V_flag = '0'))then
Counter<=Counter-1;
elsif ((Direction = '0') and (V_flag = '0')) then
Counter<=Counter+1;
elsif ((Direction = '0') and (V_flag = '1')) then
Counter<=(others=>'0');
else
Counter<=Counter;
end if;
end if;
elsif RESET = '0' then
Counter<=(others=>'0');
end if;
end process;
CNT <= conv_integer(Counter);
// Datu reģistra process
process(CLK, CLK_EN, RESET, SET_DUTY, DUTY)
begin
if RESET = '1' then
if CLK = '1' and CLK'event and CLK_EN='1' then -
if (SET_DUTY = '0') then
Duty_cycle <= DUTY;
else
Duty_cycle <= Duty_cycle;
end if;
end if;
elsif RESET = '0' then
Duty_cycle <=(others=>'0');
end if;
end process;
// Komparatora process
process (CLK, CLK_EN, RESET, Duty_cycle, Counter)
begin
if RESET = '1' then
if CLK = '1' and CLK'event and CLK_EN='1' then
if (Counter <= Duty_cycle) then
PWM_OUT <= '0';
PWM_N_OUT <= '1';
else
PWM_OUT <= '1';
PWM_N_OUT <= '0';
end if;
end if;
elsif RESET = '0' then
PWM_OUT <= '0';
PWM_N_OUT <= '0';
end if;
end process;
// FSM (stāvokļu mašīnas inicializācijas process) --
state_reg : process (RESET, CLK_EN, CLK)
begin
if RESET = '0' then
PresentState <= PWM_MODE_SELECT;
elsif RESET = '1' then
if CLK = '1' and CLK'event and CLK_EN = '1' then
PresentState <= NextState;
end if;
end if;
end process state_reg;
fsm : process(PresentState, CNT)
begin
case PresentState is
when PWM_MODE_SELECT =>
if MODE = 1 then
NextState <= FAST_PWM;
elsif MODE = 2 then
NextState <= PHASE_CORRECT;
else
NextState <= PWM_MODE_SELECT;
end if;
when FAST_PWM =>
if (CNT = ((2**Resolution_bits)-1)) then
NextState <= ZERO;
elsif (CNT = 0) then
NextState <= UP;
else
NextState <= FAST_PWM;
end if;
when PHASE_CORRECT =>
if (CNT = ((2**Resolution_bits)-1)) then
NextState <= DOWN;
elsif (CNT = 0) then
NextState <= UP;
else
NextState <= PHASE_CORRECT;
end if;
when UP =>
NextState <= PWM_MODE_SELECT;
when DOWN =>
NextState <= PWM_MODE_SELECT;
when ZERO =>
NextState <= PWM_MODE_SELECT;
end case;
end process fsm;
outputs : process (PresentState)
begin
case PresentState is
when PWM_MODE_SELECT =>
V_flag <= '0';
Direction <= '0';
when PHASE_CORRECT =>
V_flag <= '0';
Direction <= '0';
when FAST_PWM =>
V_flag <= '0';
Direction <= '0';
when ZERO =>
V_flag <= '1';
Direction <= '0';
when DOWN =>
V_flag <= '0';
Direction <= '1';
when UP =>
V_flag <= '0';
Direction <= '0';
end case;
end process outputs;
end architecture_PWM;
Programmas koda sākumā tiek pievienotas visas darbam nepieciešamās bibliotēkas. Tālāk programmas kodā tiek definēta entītija. Entītijā tiek definēts ģeneriķis, ar kura palīdzību lietotājs var izvēlēties PWM regulatora režīmu un izšķirtspēju. Vēl entītijā tiek definētas visas PWM regulatora pieslēgvietas (porti).
Tālāk programmas kodā seko arhitektūra, kurā ir iekļauti 6 procesi. Vēl arhitektūrā ir definēti 7 signāli, 2 konstantes un lietotāja definēts datu tips state.
Pirmais no procesiem apraksta skaitītāju, kurš tiek izvēlēts un vadīts, izmantojot stāvokļu mašīnu.
Otrais process apraksta datu reģistra darbību, kur jauna aizpildījuma vērtība tiek iestatīta (saglabāta) tad, kad tiek padots zems signāla līmenis uz SET_DUTY pieslēgvietu. Datu reģistra lielumu nosaka lietotāja ievadītā izšķirtspēja un entītijā definētais ģeneriķis.
Tālāk programmas kodā seko trešais process, kurā tiek aprakstīta komparatora darbība, kur, ja abās komparatora ieejās padotās vērtības ir vienādas, vai skaitītāja vērtība ir mazāka par datu reģistra vērtību, tā tiešajā izejā tiek iegūts augsts signāla līmenis, bet inversajā - zems, taču, ja skaitītāja vērtība ir lielāka par datu reģistra vērtību, tad tiešajā izejā tiek iegūts zems signāla līmenis, bet inversajā - augsts signāla līmenis.
Pēdējie trīs procesi apraksta galīga skaita stāvokļu mašīnu, kur pirmais no tiem ir atbildīgs par stāvokļu pārslēgšanu un sākotnējo stāvokli, otrajā procesā tiek noteikts tas, uz kuru no stāvokļiem notiks pārslēgšanās, bet trešais process nosaka konkrēto stāvokli un veic atbilstošajam stāvoklim visas nepieciešamās darbības (piešķires).
Katram no procesiem ir savs jutības saraksts, kurā tiek iekļauti tie signāli un pieslēgvietas, kas būtiski ietekmē integrālās shēmas darbību. Visi procesi savstarpēji konkurē.
Tālāk programmas kodā seko arhitektūra, kurā ir iekļauti 6 procesi. Vēl arhitektūrā ir definēti 7 signāli, 2 konstantes un lietotāja definēts datu tips state.
Pirmais no procesiem apraksta skaitītāju, kurš tiek izvēlēts un vadīts, izmantojot stāvokļu mašīnu.
Otrais process apraksta datu reģistra darbību, kur jauna aizpildījuma vērtība tiek iestatīta (saglabāta) tad, kad tiek padots zems signāla līmenis uz SET_DUTY pieslēgvietu. Datu reģistra lielumu nosaka lietotāja ievadītā izšķirtspēja un entītijā definētais ģeneriķis.
Tālāk programmas kodā seko trešais process, kurā tiek aprakstīta komparatora darbība, kur, ja abās komparatora ieejās padotās vērtības ir vienādas, vai skaitītāja vērtība ir mazāka par datu reģistra vērtību, tā tiešajā izejā tiek iegūts augsts signāla līmenis, bet inversajā - zems, taču, ja skaitītāja vērtība ir lielāka par datu reģistra vērtību, tad tiešajā izejā tiek iegūts zems signāla līmenis, bet inversajā - augsts signāla līmenis.
Pēdējie trīs procesi apraksta galīga skaita stāvokļu mašīnu, kur pirmais no tiem ir atbildīgs par stāvokļu pārslēgšanu un sākotnējo stāvokli, otrajā procesā tiek noteikts tas, uz kuru no stāvokļiem notiks pārslēgšanās, bet trešais process nosaka konkrēto stāvokli un veic atbilstošajam stāvoklim visas nepieciešamās darbības (piešķires).
Katram no procesiem ir savs jutības saraksts, kurā tiek iekļauti tie signāli un pieslēgvietas, kas būtiski ietekmē integrālās shēmas darbību. Visi procesi savstarpēji konkurē.
1.3.att. Programmas koda simulācija pie 6 % aizpildījuma
1.4.att. Programmas koda simulācija pie 50 % aizpildījuma
1.5.att. Programmas koda simulācija pie 99 % aizpildījuma