Stāvokļu mašīnas izveide, izmantojot FPGA


Š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
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); 
// Aizpildījuma vērtības garums bitos (8-1 downto  0 jeb 8 bitu)   

PWM_OUT, PWM_N_OUT: OUT std_logic 
);

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 

    signal Direction : std_logic:='0';
 
    // 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
                        
    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                                                                      
    signal NextState, PresentState : state;                                   
 
    // 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ē.


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

UZ SĀKUMU