0

100khz クロックと .6ms から 2.4 ms の範囲の PWM を使用して PWM ジェネレーターを作成しようとしていますが、これを vhdl に実装するのに行き詰まっています。これを行うためにステート マシンを使用しようとしていますが、より複雑になっています。必要以上に。

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 PWM is
    Port ( clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           pwm_out : out  STD_LOGIC;
              PWM_CONST : STD_LOGIC_VECTOR(2 downto 0));
end PWM;

architecture Behavioral of PWM is
type State_type is (LOW,HIGH,Counting); --States
signal Sreg, Snext : State_type; --Curent state and next state
signal t20ms,t100ms,t_6ms,t_825ms,t1_05ms,t1_275ms,t1_5ms,t1_725ms,t1_95ms,t2_175ms,t2_4ms: STD_LOGIC; 
signal twenty : STD_LOGIC;
signal count_flag : STD_LOGIC; 
begin
-------------------------Clock Dividers for timing---------------------------------------
process(clk,reset)
variable toggle_20ms,toggle_1666hz,toggle_1212hz,toggle_952hz,toggle_785hz,toggle_666hz,toggle_579hz,toggle_512hz,toggle_460hz,toggle_416hz  : STD_LOGIC :='0'; 
variable counter_20ms : integer range 0 to 999; 
variable counter_1666hz : integer range 0 to 29;
variable counter_1212hz : integer range 0 to 40;
variable counter_952hz : integer range 0 to 51;
variable counter_785hz : integer range 0 to 63;
variable counter_666hz : integer range 0 to 74;
variable counter_579hz : integer range 0 to 85;
variable counter_512hz : integer range 0 to 96;
variable counter_460hz : integer range 0 to 107;
variable counter_416hz : integer range 0 to 119;
 begin
 if reset = '1' then
      t_6ms<='0';
        t_825ms<='0';
        t1_05ms<='0';
        t1_275ms<='0';
        t1_5ms<='0';
        t1_725ms<='0';
        t1_95ms<='0';
        t2_175ms<='0';
        t2_4ms<='0';
        twenty<='0';
 else
    if(clk'event and clk = '1') then 
        counter_20ms := counter_20ms+1;
        counter_1666hz := counter_1666hz+1;
        counter_1212hz := counter_1212hz+1;
        counter_952hz := counter_952hz+1;
        counter_785hz := counter_785hz+1;
        counter_666hz := counter_666hz+1;
        counter_579hz := counter_579hz+1;
        counter_512hz := counter_512hz+1;
        counter_460hz := counter_460hz+1;
        counter_416hz := counter_416hz+1; 
        counter_20ms := counter_20ms+1; 
        if (counter_1666hz = 29) then 
            toggle_1666hz := not toggle_1666hz; 
            counter_1666hz := 0; 
        end if;
        if (counter_1212hz = 40) then 
            toggle_1212hz := not toggle_1212hz; 
            counter_1212hz := 0; 
        end if;
        if (counter_952hz  = 51) then 
            toggle_952hz  := not toggle_952hz ; 
            counter_952hz  := 0; 
        end if;
        if (counter_785hz = 63) then 
            toggle_785hz := not toggle_785hz; 
            counter_785hz := 0; 
        end if;
        if (counter_666hz = 74) then 
            toggle_666hz := not toggle_666hz; 
            counter_666hz := 0; 
        end if;
        if (counter_579hz = 85) then 
            toggle_579hz := not toggle_579hz; 
            counter_579hz := 0; 
        end if;
        if (counter_512hz = 96) then 
            toggle_512hz := not toggle_512hz; 
            counter_512hz := 0; 
        end if;
        if (counter_460hz = 107) then 
            toggle_460hz := not toggle_460hz; 
            counter_460hz := 0; 
        end if;
        if (counter_416hz = 119) then 
            toggle_416hz := not toggle_416hz; 
          counter_416hz := 0; 
       end if;
        if (counter_20ms = 999) then 
            toggle_20ms := not toggle_20ms;
            counter_20ms := 0;
        end if; 
        t_6ms<=toggle_1666hz;
        t_825ms<=toggle_1212hz;
        t1_05ms<=toggle_952hz;
        t1_275ms<=toggle_785hz;
        t1_5ms<=toggle_666hz;
        t1_725ms<=toggle_579hz;
        t1_95ms<=toggle_512hz;
        t2_175ms<=toggle_460hz;
        t2_4ms<=toggle_416hz;
        twenty<=toggle_20ms;
    end if; 
end if;
end process; 

-------------------------Next State Logic----------------------------------
    process(Sreg,reset,PWM_CONST)
        begin 
            case Sreg is 
                when LOW => if (rising_edge(twenty)) then Snext <= HIGH; 
                                else                                 Snext <= LOW; 
                                end if; 
                when HIGH => if reset = '1'        then Snext <= LOW;
                                 else                   Snext <= Counting; 
                                 end if;
                when Counting => if count_flag = '1'     then Snext <= Counting;
                                      else               Snext <= LOW; 
                                      end if; 
            end case; 
    end process; 
-----------------------Update State----------------------------------------
    process(clk)
        begin 
            if (clk'event and clk='1') then 
                Sreg <= Snext;
            end if;
    end process; 
------------------------Count_flag---------------------------------------------
    process(clk,PWM_CONST)
        begin
        case PWM_CONST is
                when "000"=> t_6ms <= count_flag;
                when "001"=> t_825ms <= count_flag;
                when "010"=> t1_05ms <= count_flag;
                when "011"=> t1_275ms <= count_flag;
                when "100"=> t1_5ms <= count_flag;
                when "101"=> t1_725ms <= count_flag;
                when "110"=> t1_95ms <= count_flag;
                when "111"=> t2_175ms <= count_flag;
                when others => t2_4ms <= count_flag;
        end case;       
    end process; 
----------------------Output Logic-----------------------------------------
with Sreg select -- output logic based on state only
        pwm_out <= '1' when HIGH | Counting,
                      '0' when LOW,
                      '0' when others;
---------------------------------------------------------------------------                   
end Behavioral;
<code>

合成しようとすると、不正な同期エラーが発生します

4

1 に答える 1

1

コードには少なくとも 3 つの大きな問題があります。最初のものは、次の状態プロセスです。

process(Sreg,reset,PWM_CONST)
    begin 
        case Sreg is 
            when LOW => if (rising_edge(twenty)) then Snext <= HIGH; 
                            else                                 Snext <= LOW; 
                            end if; 
            when HIGH => if reset = '1'        then Snext <= LOW;
                             else                   Snext <= Counting; 
                             end if;
            when Counting => if count_flag = '1'     then Snext <= Counting;
                                  else               Snext <= LOW; 
                                  end if; 
        end case; 
end process;

ケースに入れることはできませんrising_edge。それがどの電子部品を表しているのかわかりません。を使用する場合rising_edge、クロック分周器と更新状態プロセスで行ったように、すべてのステートメントをその中に含める必要があります (非同期リセットを除く)。

信号が「0」から「1」になることを検出したい場合は、twenty次のようにします。

process(reset, clk)
begin
    if reset = '1' then
        twenty_dl <= '0';
    elsif rising_edge(clk) then
        twenty_dl <= twenty; -- Delayed version of twenty

        if twenty_dl = '0' and twenty = '1' then -- twenty is rising
            -- Insert logic here
        end if;
    end if;
end process;

補足として、レジスタによって駆動される信号をクロックとして使用しないでください。クロックは賢明で、fpga のクロック有効ピンから供給され、PLL などによって変更されます。レジスタを使用してクロック信号を駆動することは (残念ながら) サポートされていますが、ツールはグローバル クロックの場合のようにネットを解析できません。つまり、ツールが通知せずにデザインが失敗する可能性があります。クロックを「分割」する場合は、クロック イネーブルを使用します。

process(reset, clk)
begin
    if reset = '1' then
        cnt <= (others => '0');
    elsif rising_edge(clk) then
        if cnt = 199 then -- Divide the clock by 200
            clk_div_200_en <= '1';
            cnt <= (others => '0');
        else
            clk_div_200_en <= '0';
            cnt <= cnt + 1;
        end if;
    end if;
end process;

process(clk)
begin
    if rising_edge(clk) and clk_div_200_en = '1' then
        -- Insert logic here
    end if;
end process;

コードの 2 番目の大きな問題は、シグナルt_6msと cie 用に複数のドライバーがあることです。クロック分周器プロセスと count_flag プロセスの両方がこれらの信号を割り当てます。VHDL では、信号へのすべての割り当てを 1 つのプロセスで行う必要があります。そうしないと、一般に合成でサポートされていない複数のドライバーが得られ、ネット上で競合が発生する可能性があります。

3 つ目の大きな問題は、count_flag プロセスです。このプロセスは組み合わせです (クロックなし)。組み合わせプロセスでは、プロセスが割り当てる信号はすべて、プロセスのすべてのパスで割り当てる必要があります。つまり、t_6msが の場合に割り当てる必要がPWM_CONSTあり"001", "010", etcます。そうしないと、ラッチ要素が発生します。これは悪いことです。

于 2015-04-14T01:34:49.617 に答える