工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

パルス幅変調(PWM)は、デジタルFPGAピンを強力なアナログ・コントローラに変えます。高速で電源をオン/オフ切り替えることで、真のアナログ電圧を生成せずに、負荷が必要とする正確な平均電流を供給します。

典型的なPWM用途には、スピーカー用音声出力、LED調光、サーボ・モーター、PCファン、ポンプ、電気自動車用ブラシレスDCモーターなどの誘導モーターのトルク制御があります。

関連記事: FPGAピンからのPWMを使ったRCサーボ・コントローラ

PWMの仕組み

電源を高周波で100%と0%の間で切り替えると、負荷が見る時間平均電流は、電源がオンである時間の割合に比例します。以下の図がこの原理を示しています:

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

デューティ・サイクル

デューティ・サイクルは、各周期でPWM出力がハイでいる時間を定義します。パーセンテージで表現され、バイナリ・カウンター値から計算されます:

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

VHDL実装では、デューティ・サイクルを符号なし整数として扱い、PWMカウンターの全分解能を得られます。0%デューティ・サイクルは出力を永続的にオフにし、100%は継続的にオンにします。達成可能な分解能はカウンターの幅によって決まります。

バイナリ・デューティ・サイクル値をパーセンテージに変換するには:

\mathit{duty\_cycle\_percentage} = \frac{\mathit{commanded\_duty\_cycle} * 100}{2^\mathit{pwm\_bits} - 1}

PWM周波数

PWM周波数は周期の逆数です:

\mathit{pwm\_freq} = \frac{1}{\mathit{pwm\_period}}

適切な周波数の選択はターゲット・デバイスに依存します。LEDの場合、数百ヘルツで可視フリッカーを防止できます。一方、ブラシレスDCモーターは通常数十キロヘルツ帯で動作します。周波数が低すぎると機械的振動を生じ、高すぎると電力を浪費します。

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

MOSFETスイッチはFPGAロジックより遅いため、PWMを高速化しすぎるとトランジスタが部分導通状態で時間を費やし、余分な熱を発生させます。

PWMジェネレーター・モジュール

以下は、任意のカウンター幅とクロック分周係数でインスタンス化できる汎用VHDL PWMコントローラ実装です。

エンティティ宣言

 entity pwm is generic ( pwm_bits : integer; clk_cnt_len : positive := 1 ); port ( clk : in std_logic; rst : in std_logic; duty_cycle : in unsigned(pwm_bits - 1 downto 0); pwm_out : out std_logic ); end pwm; 

clkとrstポートは同期制御を提供。duty_cycle入力の幅はpwm_bitsで定義されるため、カウンター分解能は直接設定可能。pwm_out信号はMOSFETゲートを駆動するFPGAピンにルーティングされます。

内部信号

 signal pwm_cnt : unsigned(pwm_bits - 1 downto 0); signal clk_cnt : integer range 0 to clk_cnt_len - 1; 

pwm_cntカウンターはデューティ・サイクル幅をミラーします。clk_cntカウンターはオプションのクロック分周器を実装し、clk_cnt_lenを1に設定すると分周器が無効化され、関連ロジックが削除されます。

クロック分周プロセス

 CLK_CNT_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then clk_cnt <= 0; else if clk_cnt < clk_cnt_len - 1 then clk_cnt <= clk_cnt + 1; else clk_cnt <= 0; end if; end if; end if; end process; 

デフォルトのclk_cnt_len = 1では、合成ツールがこのプロセスを自動的に削除します。

PWM出力プロセス

 PWM_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pwm_cnt <= (others => '0'); pwm_out <= '0'; else if clk_cnt_len = 1 or clk_cnt = 0 then pwm_cnt <= pwm_cnt + 1; pwm_out <= '0'; if pwm_cnt = unsigned(to_signed(-2, pwm_cnt'length)) then pwm_cnt <= (others => '0'); end if; if pwm_cnt < duty_cycle then pwm_out <= '1'; end if; end if; end if; end if; end process; 

カウンターはclk_cntがゼロのときのみインクリメントされ、実質的にPWM周波数をスロットリングします。pwm_cntをその最後から2番目の値でリセットする条件付き処理により、100%デューティ・サイクルが達成可能になります。

\mathit{pwm\_hz} = \frac{\mathit{clk\_hz}}{(2^\mathit{pwm\_bits} - 1) * \mathit{clk\_cnt\_len}}

トップレベル設計

PWMコントローラをデモするため、設計はLattice iCEstick FPGAの電源投入LEDを駆動します。ボードの12MHz発振器がカウンターを駆動し、LED強度をノコギリ波パターンで制御します。

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

エンティティ宣言

 entity pwm_led is generic ( pwm_bits : integer := 8; cnt_bits : integer := 25; clk_cnt_len : positive := 47 ); port ( clk : in std_logic; rst_n : in std_logic; led_1 : out std_logic; led_2 : out std_logic; led_3 : out std_logic; led_4 : out std_logic; led_5 : out std_logic ); end pwm_led; 

12MHzクロックと選択されたジェネリックにより、PWM周波数は約1kHzになります:
\frac{12e6}{(2^8 - 1) * 47} \approx 1 \text{ kHz}

cnt_bitsジェネリックは25ビットのノコギリ波カウンターを駆動し、LEDデューティ・サイクルを制御。その周期は約2.8Hzです:

\frac{2^{\mathit{cnt\_bits}}}{\mathit{clk\_hz}} = \frac{2^{25}}{12e6} \approx 2.8 \text{ Hz}

LED 5のみ使用し、他のLEDは迷光防止のためローに固定します。

内部信号と配線

 architecture str of pwm_led is signal rst : std_logic; signal cnt : unsigned(cnt_bits - 1 downto 0); signal pwm_out : std_logic; alias duty_cycle is cnt(cnt'high downto cnt'length - pwm_bits); begin led_1 <= '0'; led_2 <= '0'; led_3 <= '0'; led_4 <= '0'; led_5 <= pwm_out; 

rst信号は、外部リセットの同期化された非反転バージョンです。エイリアスduty_cycleはcntの最上位ビットをPWMコントローラにマッピングします。

モジュール・インスタンス化

 RESET : entity work.reset(rtl) port map ( clk => clk, rst_n => rst_n, rst => rst ); PWM : entity work.pwm(rtl) generic map ( pwm_bits => pwm_bits, clk_cnt_len => clk_cnt_len ) port map ( clk => clk, rst => rst, duty_cycle => duty_cycle, pwm_out => pwm_out ); COUNTER : entity work.counter(rtl) generic map ( counter_bits => cnt'length ) port map ( clk => clk, rst => rst, count_enable => '1', counter => cnt ); 

シミュレーション

ジェネリックのおかげでシミュレーション高速化が容易です。cnt_bitsとclk_cnt_lenを削減することで、数秒ではなく数マイクロ秒で完全なPWMサイクルを観察できます。

テストベンチ・インスタンス化:

 DUT : entity work.pwm_led(str) generic map ( pwm_bits => 8, cnt_bits => 16, clk_cnt_len => 1 ); 

ModelSimの波形は、ノコギリ波カウンターがLED輝度を駆動する様子を示しています。デューティ・サイクルが最大値に達する各サイクルの頂点で、短い「オン」パルスが現れます。

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

FPGA実装

iCEcube2で合成後、設計はice40hx1ktq144パートの利用可能な64 LUTのうちわずか5%を消費します:

 Resource Usage Report for pwm_led Mapping to part: ice40hx1ktq144 Cell usage: GND 3 uses SB_CARRY 31 uses SB_DFF 5 uses SB_DFFSR 39 uses SB_GB 1 use VCC 3 uses SB_LUT4 64 uses I/O ports: 7 I/O primitives: 7 SB_GB_IO 1 use SB_IO 6 uses I/O Register bits: 0 Register bits not including I/Os: 44 (3%) Total load per clock: pwm_led|clk: 1 @S |Mapping Summary: Total LUTs: 64 (5%) 

Diamondスタンドアロン・プログラマーでUSB経由でFPGAをプログラミングは簡単でした。結果のLEDアニメーションは、滑らかな輝度ランプの後、サイクル繰り返し前に一瞬暗くなります。

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

正弦波デューティ・サイクルによるブリージングLED

ノコギリ波カウンターを正弦波ルックアップ・テーブルに置き換えると、通知LEDでよく見られる自然な「呼吸」効果が生まれます。

VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ

次の記事では、ブロックRAMを使った正弦波ジェネレーターの構築方法と、pwm_led設計への統合方法を紹介します。

次の記事を読む: ブロックRAMに格納された正弦波を使ったブリージングLED効果の作り方

関連記事: FPGAピンからのPWMを使ったRCサーボ・コントローラ

VHDL

  1. PWM電力コントローラ:パルス幅変調ランプドライバの構築
  2. コンデンサ充電のステップバイステップガイド:安全かつ効率的な手順
  3. VHDLで文字列リストを作成する: ベスト・プラクティスと実装例
  4. Tcl駆動テストベンチでVHDLコード・ロック・モジュールを検証する
  5. VHDLテストベンチ・シミュレーションを優雅に終了させる方法
  6. VHDLで乱数生成: 一様分布からOSVVMまで
  7. ブロックRAMにおける堅牢なVHDLリングバッファFIFOの設計
  8. VHDLで自己検証テストベンチを構築する実践ガイド
  9. VHDLで保護型とアクセスポインタを用いた動的リンクリスト実装
  10. プロセス内プロシージャでVHDLステートマシンをクリーンに設計
  11. VHDL関数マスター:効率的な設計のための実践ガイド