目次
前
次
PWM wave generator
2つのHブリッジ回路を内蔵したICが多くなってきました。
タイマー内蔵のワンチップマイコンであれば、PWM波形を
生成するのは、簡単です。
タイマー内蔵でも、PWM波形生成に利用できるタイマーの
数が不足している場合、CPLDの中にPWM波形生成器を入れ
対応したい場面が出てきます。
次の仕様を満足する、専用チップを作成してみます。
- 2波形を生成できる
- Hブリッジ入力の2ピンに、PWM波形を与えられる
- Hブリッジ入力の2ピンのどちらにPWM波形を与えられるか指定できる
- DUTY比(0から100)を、個別に与えられる
- モータ駆動は、専用ドライバICに任せる
内部ブロック図は、以下。
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" ;
目次
前
次