lundi 6 mai 2013

PWM

Un exemple de PWM (Pulse With Modulation) en VHDL. Le rapport cyclique du signal de sortie est contrôlé à l'entrée duty_cycle de 0 à 100% par pas de 10.


~\Bureau\pwm2.vhd.html
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity pwm is port (
      clk: in std_logic;
      SW : in std_logic_vector (3 downto 0); --rapport cyclique (de 0 à 10) 
      reset : in std_logic;
      GPIO_0 : out std_logic_vector(35 downto 0)); -- sortie
end pwm;

architecture behavior of pwm is

signal cnt : std_logic_vector(3 downto 0) := "0000";
signal s : std_logic;

begin
process (clk,rst) begin
  if reset ='1' then s<=(others=>'0');
  elsif (clk'event and clk='1') then
    if (cnt < SW) then s <='1'; --met la sortie à 1 jusqu'a 
    else s <='0';               --la valeur du rapport cyclique
    end if;
    if (cnt >= "1001") then cnt<="0000"; --remet à 0 quand on a
    else cnt <= cnt + 1;                 -- compté jusqu'a 10
    end if;
  end if;
end process;
GPIO_0(29) <= s;
end behavior;


Simulation ModelSim

Encodeur en quadrature de phase

Le signal de sortie d'un encodeur optique à la forme suivante:


Ce signal est intéressant car déphasé de 90° il permet de déterminer le sens de déplacement. En effet, si la voie A est en avance par rapport à la voie B on se déplace dans un sens, dans le cas contraire on se déplace dans l'autre sens.
Dans le programme VHDL, j'utilise une machine à états finis (FSM Finite State Machine) pour compter ou décompter en fonction du niveau du signal reçu.

Diagramme d'état

Le schéma suivant présente les états possibles en fonction du niveau logique issu du capteur optique. Chaque cycle peut compter jusqu'a 4 incréments ou décréments. Il est toujours possible de modifier le programme de façon à prendre en compte que 1 ou 2 incréments par cycle en fonction de la précision que l'on désire.


Le diagramme d'état:


Le diagramme d'état prend en compte toutes les transitions possibles, ce qui correspond par exemple à des cas ou le cycle ne s'est pas totalement terminé. Imaginons que l'on se trouve à D5, le compteur à déjà compté jusqu'a 3, si on recule avant d'arriver à D6, on passe à l'état G2 qui immédiatement décrémentera d'une unité.

Programme VHDL associé
~\Bureau\Exercice VHDL\PersoExo\Incrementation\FSM_incrementeur.vhd.html
library ieee;
use ieee.std_logic_1164.all;

entity FSM_encoder is
port (
                clk: in std_logic;
                init: in std_logic;
                wayA_B : in std_logic_vector(1 downto 0);
                en: out std_logic; -- enable
                du: out std_logic); --down/up
end FSM_encoder;


architecture machine_behavior of FSM_encoder is

type state is (idle,D0,D1,D2,D3,D4,D5,D6,G0,G1,G2,G3,G4,G5,G6);
signal next_state,reg_state:state;

begin

process(clk)
        begin
                if rising_edge(clk) then
                        if init='1' then reg_state<=idle;
                        else reg_state<=next_state;
                        end if;
                end if;
end process;
----
process (reg_state,wayA_B)
        begin
        case reg_state is

                        when idle=>
                                        if (wayA_B = "01") then next_state<=G0;
                                        elsif (wayA_B = "10") then next_state<=D0;
                                        else next_state<=idle;
                                        end if;

                        when D0=> next_state<=D1;
                        when D1=>
                                        if (wayA_B = "10") then next_state<=D1;
                                        elsif (wayA_B = "11") then next_state<=D2;
                                        elsif (wayA_B = "00") then next_state<=G6;
                                        else next_state<=idle;
                                        end if;
                        when D2=> next_state<=D3;
                        when D3=>
                                        if (wayA_B = "01") then next_state<=D4;
                                        elsif (wayA_B = "10") then next_state<=G4;
                                        elsif (wayA_B = "11") then next_state<=D3;
                                        else next_state<=idle;
                                        end if;
                        when D4=> next_state<=D5;
                        when D5=>
                                        if (wayA_B = "00") then next_state<=D6;
                                        elsif (wayA_B = "01") then next_state<=D5;
                                        elsif (wayA_B = "11") then next_state<=G2;
                                        else next_state<=idle;
                                        end if;
                        when D6=> next_state<=idle;

                        when G0=> next_state<=G1;
                        when G1=>
                                        if (wayA_B = "01") then next_state<=G1;
                                        elsif (wayA_B = "11") then next_state<=G2;
                                        elsif (wayA_B = "00") then next_state<=D6;
                                        else next_state<=idle;
                                        end if;
                        when G2=> next_state<=G3;
                        when G3=>
                                        if (wayA_B = "01") then next_state<=D4;
                                        elsif (wayA_B = "10") then next_state<=G4;
                                        elsif (wayA_B = "11") then next_state<=G3;
                                        else next_state<=idle;
                                        end if;
                        when G4=> next_state<=G5;
                        when G5=>
                                        if (wayA_B = "00") then next_state<=G6;
                                        elsif (wayA_B = "10") then next_state<=G5;
                                        elsif (wayA_B = "11") then next_state<=D2;
                                        else next_state<=idle;
                                        end if;
                        when G6=> next_state<=idle;
        end case;
end process;

--down/up assignement
en<='1' when (reg_state=D0 or reg_state=D2 or reg_state=D4 or reg_state=D6 or reg_state=G0 or reg_state=G2 or reg_state=G4 or reg_state=G6) else '0';
du<='1' when (reg_state=D0 or reg_state=D2 or reg_state=D4 or reg_state=D6) else '0';

end machine_behavior;
Ce programme est utilisé dans le cas ou la sortie est connectée à des compteurs décimaux mise en cascade. La sortie en(enable) valide le comptage si sa valeur est '1' et du(down/up) détermine si on incrémente ou décrémente suivant sa valeur '0' ou '1'.

Voici un extrait de la simulation sous ModelSim avec l'exemple énoncé précédemment. On remarque bien que la valeur de du passe à '0' quand on revient vers la gauche momentanément.
(cette image est a mettre à jour car on ne distingue pas bien les noms des signaux)