目次

PWM wave generator

 2つのHブリッジ回路を内蔵したICが多くなってきました。



 タイマー内蔵のワンチップマイコンであれば、PWM波形を
 生成するのは、簡単です。

 タイマー内蔵でも、PWM波形生成に利用できるタイマーの
 数が不足している場合、CPLDの中にPWM波形生成器を入れ
 対応したい場面が出てきます。

 次の仕様を満足する、専用チップを作成してみます。

 内部ブロック図は、以下。



 PWM波形を、2ピンのどちらに出力するのかを指定する
 VHDLコードは、次のように定義すれば、よいでしょう。

  AOUT(0) <= iLEFTOUT  when ( DIRA = '0' ) else '0' ;
  AOUT(1) <= iLEFTOUT  when ( DIRA = '1' ) else '0' ;
  BOUT(0) <= iRIGHTOUT when ( DIRB = '0' ) else '0' ;
  BOUT(1) <= iRIGHTOUT when ( DIRB = '1' ) else '0' ;

 これで、出力は次のように信号名を決められます。



 左右のDUTY比を設定するために、レジスタに値を設定する
 シーケンサを定義。

  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iGSTATE <= 0 ;
      iREGX   <= (others => '0') ;
      iLEFTD  <= 0 ;
      iRIGHTD <= 0 ;
    elsif rising_edge( CLOCK ) then
      case iGSTATE is
        -- get 7 bits
        when 0 => iGSTATE <= 1 ;
                  iREGX   <= DVX ;
        -- judge
        when 1 => if ( ENX = '0' ) then
                    iGSTATE <= 3 ;
                  else
                    iGSTATE <= 2 ;
                  end if ;
        -- deliver
        when 2 => if ( SELX = '1' ) then
                    iLEFTD <= conv_integer( iREGX ) ;
                  else
                    iRIGHTD <= conv_integer( iREGX ) ;
                  end if ;
                  iGSTATE <= 3 ;
        -- return first state 
        when 3 => iGSTATE <= 0 ;
        -- default
        when others =>
                  iGSTATE <= 0 ;
      end case ;
    end if ;
  end process ;

 外部と内部の信号は、次のように規定。



 DUTY比が確定していれば、カウンタの値と比較し
 論理値の1の0のどちらを出力するのかを決定
 するコンパレータを使えばよいはず。

  iLEFTOUT  <= '1' when ( iPCNT < iLEFTDX  ) else '0' ;
  iRIGHTOUT <= '1' when ( iPCNT < iRIGHTDX ) else '0' ;

 カウンタとレジスタの値の比較ですが、波形出力中に
 レジスタの値が変化しないように、バッファを用意し
 対応しています。

 カウンタとレジスタの値の更新は、次のようにします。

  process (nRESET,iCLK)
  begin 
    if ( nRESET = '0' ) then
      iPCNT<= 0 ;
      iLEFTDX  <= 0 ;
      iRIGHTDX <= 0 ;
    elsif rising_edge( iCLK ) then
      if ( iPCNT = 100 ) then
        iPCNT    <= 0 ;
        iLEFTDX  <= iLEFTD  ;
        iRIGHTDX <= iRIGHTD ;
      else
        iPCNT <= iPCNT + 1 ;
      end if ;
    end if ;
  end process ;

 カウンタを動かすためには、分周器が必要なので
 ディバイダを定義して使います。

  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iCNT<= 0 ;
    elsif rising_edge( CLOCK ) then
      iCNT <= iCNT + 1 ;
    end if ;
  end process ;
  iCLK <= '1' when ( iCNT = 0 ) else '0' ;

 これらをまとめます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity pwmx is
  port (
    -- system 
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 4MHz
    -- input
    DVX    : in  std_logic_vector(6 downto 0) ;
    ENX    : in  std_logic ;
    SELX   : in  std_logic ;
    DIRA   : in  std_logic ;
    DIRB   : in  std_logic ;
    -- output
    AOUT   : out std_logic_vector(1 downto 0) ;
    BOUT   : out std_logic_vector(1 downto 0) --;
  );
end pwmx;

architecture Behavioral of pwmx is
  -- internal register
  signal iGSTATE : integer range 0 to 3 ;
  signal iLEFTD  : integer range 0 to 100 ;
  signal iRIGHTD : integer range 0 to 100 ;
  signal iREGX   : std_logic_vector(6 downto 0) ;
  -- internal counter
  signal iPCNT     : integer range 0 to 100 ;
  signal iLEFTDX   : integer range 0 to 100 ;
  signal iRIGHTDX  : integer range 0 to 100 ;
  signal iLEFTOUT  : std_logic ;
  signal iRIGHTOUT : std_logic ;
  -- clock divider
  signal iCNT : integer range 0 to 1023 ;
  signal iCLK : std_logic ;
begin
  -- output
  AOUT(0) <= iLEFTOUT  when ( DIRA = '0' ) else '0' ;
  AOUT(1) <= iLEFTOUT  when ( DIRA = '1' ) else '0' ;
  BOUT(0) <= iRIGHTOUT when ( DIRB = '0' ) else '0' ;
  BOUT(1) <= iRIGHTOUT when ( DIRB = '1' ) else '0' ;

  -- latch sequencer
  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iGSTATE <= 0 ;
      iREGX   <= (others => '0') ;
      iLEFTD  <= 0 ;
      iRIGHTD <= 0 ;
    elsif rising_edge( CLOCK ) then
      case iGSTATE is
        -- get 7 bits
        when 0 => iGSTATE <= 1 ;
                  iREGX   <= DVX ;
        -- judge
        when 1 => if ( ENX = '0' ) then
                    iGSTATE <= 3 ;
                  else
                    iGSTATE <= 2 ;
                  end if ;
        -- deliver
        when 2 => if ( SELX = '1' ) then
                    iLEFTD <= conv_integer( iREGX ) ;
                  else
                    iRIGHTD <= conv_integer( iREGX ) ;
                  end if ;
                  iGSTATE <= 3 ;
        -- return first state 
        when 3 => iGSTATE <= 0 ;
        -- default
        when others =>
                  iGSTATE <= 0 ;
      end case ;
    end if ;
  end process ;

  -- clock divider
  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iCNT<= 0 ;
    elsif rising_edge( CLOCK ) then
      iCNT <= iCNT + 1 ;
    end if ;
  end process ;
  iCLK <= '1' when ( iCNT = 0 ) else '0' ;

  -- generate PWM wave
  process (nRESET,iCLK)
  begin 
    if ( nRESET = '0' ) then
      iPCNT<= 0 ;
      iLEFTDX  <= 0 ;
      iRIGHTDX <= 0 ;
    elsif rising_edge( iCLK ) then
      if ( iPCNT = 100 ) then
        iPCNT    <= 0 ;
        iLEFTDX  <= iLEFTD  ;
        iRIGHTDX <= iRIGHTD ;
      else
        iPCNT <= iPCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iLEFTOUT  <= '1' when ( iPCNT < iLEFTDX  ) else '0' ;
  iRIGHTOUT <= '1' when ( iPCNT < iRIGHTDX ) else '0' ;

end Behavioral;

 ピンアサインは、以下。

# system
NET "nreset"  LOC = "P39";
NET "clock"   LOC = "P5" ;

# PWM out
NET "aout<0>" LOC = "P1" ;
NET "aout<1>" LOC = "P2" ;
NET "bout<0>" LOC = "P43" ;
NET "bout<1>" LOC = "P44" ;

NET "dira" LOC = "P3" ;
NET "dirb" LOC = "P4" ;
NET "selx" LOC = "P11" ;
NET "enx"  LOC = "P12" ;

# data in
NET "dvx<0>" LOC = "P24" ;
NET "dvx<1>" LOC = "P25" ;
NET "dvx<2>" LOC = "P26" ;
NET "dvx<3>" LOC = "P27" ;
NET "dvx<4>" LOC = "P28" ;
NET "dvx<5>" LOC = "P29" ;
NET "dvx<6>" LOC = "P33" ;

 AOUT、BOUTを上のように指定すると、必要な
 マクロセル数を減らすことができました。

 次のように指定すると、マクロセル数は3つ増加しました。

NET "bout<0>" LOC = "P3" ;
NET "bout<1>" LOC = "P4" ;

NET "dira" LOC = "P6" ;
NET "dirb" LOC = "P7" ;


目次

inserted by FC2 system