STM32 PWMとは?仕組みと簡単な使い方を解説
はじめに
現代のエレクトロニクスにおいて、マイクロコントローラーは様々な機器の頭脳として不可欠な存在です。その中でも、STMicroelectronics社が開発・提供するSTM32シリーズは、豊富なラインナップと高性能、使いやすさから、プロトタイピングから製品開発まで幅広く利用されています。
STM32が持つ強力な機能の一つに、「タイマー」とそれを利用した「PWM(Pulse Width Modulation:パルス幅変調)」出力があります。PWMは、デジタル出力でありながらアナログ的な制御を実現する技術として、LEDの明るさ調整、モーターの速度制御、オーディオ信号の出力など、多岐にわたる応用分野で中心的な役割を果たしています。
この記事では、STM32におけるPWMの仕組みを根本から理解し、実際に開発環境であるSTM32CubeMXおよびSTM32CubeIDEを使ってPWMを生成・制御する方法を詳細に解説します。約5000語にわたるこの解説を通して、STM32のPWM機能を自在に使いこなすための知識とスキルを習得することを目指します。
PWMの基礎知識
STM32におけるPWMの仕組みを理解する前に、まず「PWMそのもの」について基礎から確認しましょう。
PWMの定義と原理
PWM(Pulse Width Modulation:パルス幅変調)は、デジタル信号を用いてアナログ的な効果を得るための技術です。基本原理は非常にシンプルです。一定周期のON/OFFを繰り返す方形波(パルス波)において、ONになっている時間(パルス幅)を変化させることで、波形の「実効的な」値を制御します。
考えてみてください。例えば、モーターに常に5Vを印加すれば、モーターは最高速度で回転します。しかし、5Vの電源を高速にON/OFFを繰り返すとどうなるでしょうか? ONの時間が長ければより多くのエネルギーがモーターに供給され、回転速度は速くなります。逆に、ONの時間が短ければ供給されるエネルギーは少なくなり、回転速度は遅くなります。このとき、ON/OFFの切り替えがモーターの応答速度に比べて十分に速ければ、モーターは振動するのではなく、そのON/OFFの割合に応じた滑らかな速度で回転します。これがPWMの基本的な考え方です。
デューティサイクル (Duty Cycle)
PWM波形を特徴づける最も重要なパラメータの一つが「デューティサイクル」です。デューティサイクルは、1周期(ON時間とOFF時間の合計)の中で、信号がONになっている時間(パルス幅)の割合を示します。通常、パーセンテージで表されます。
- デューティサイクル (%) = (ON時間 / 周期) × 100
例えば、周期が1ms(=1000μs)の波形があったとします。
* ON時間が0.5msであれば、デューティサイクルは (0.5ms / 1ms) × 100 = 50% です。
* ON時間が0.2msであれば、デューティサイクルは (0.2ms / 1ms) × 100 = 20% です。
* ON時間が1ms(つまり常にON)であれば、デューティサイクルは (1ms / 1ms) × 100 = 100% です。
* ON時間が0ms(つまり常にOFF)であれば、デューティサイクルは (0ms / 1ms) × 100 = 0% です。
デューティサイクルを0%から100%の間で変化させることで、出力の実効的な値を、あたかも0Vから最大電圧までのアナログ信号のように制御できるのです。
周期 (Period) または周波数 (Frequency)
PWM波形を特徴づけるもう一つの重要なパラメータが「周期」または「周波数」です。周期は、パルスが1回繰り返されるのにかかる時間です。周波数は、1秒間にパルスが繰り返される回数です。周期と周波数は逆数の関係にあります。
- 周波数 (Hz) = 1 / 周期 (秒)
- 周期 (秒) = 1 / 周波数 (Hz)
例えば、周波数が1kHzの波形であれば、周期は 1 / 1000Hz = 0.001秒 = 1ms です。
この周期(または周波数)は、PWMを適用する対象によって適切な値を選ぶ必要があります。
* LEDの輝度制御の場合、人間の目には高速な点滅はちらつきとして認識されないため、数百Hzから数kHz程度の周波数がよく使われます。
* DCモーターの速度制御の場合、モーターの応答速度や可聴ノイズを考慮して、数kHzから数十kHz程度の周波数が使われます。周波数が低すぎるとモーターが振動したり音を立てたりすることがあります。
* サーボモーターの制御の場合、通常は20ms(50Hz)程度の一定周期で、ON時間(パルス幅)を1msから2ms程度の範囲で変化させて角度を制御します。
* オーディオ出力(クラスDアンプなど)の場合、音声信号を忠実に再現するため、非常に高い周波数(数百kHzから数MHz)が必要になります。
適切な周期(周波数)を選ぶことで、対象物を滑らかに制御し、不要なノイズや振動を防ぐことができます。
アナログ出力との比較
マイクロコントローラーの多くは、真のアナログ電圧を出力できるDAC(Digital-to-Analog Converter)機能を備えています。しかし、DACは一般的にチャネル数が少なく、消費電力が大きい、コストが高いといった制約があります。
一方、PWMはデジタル出力ピンを使って実現できます。デジタル出力ピンは多くのマイクロコントローラーで豊富に利用可能であり、構造も比較的シンプルです。PWMを使うことで、DACを使わずに(あるいはDACチャネルが足りない場合に)、安価で多くのピンを使ってアナログ的な制御を行うことができるのです。もちろん、PWMはあくまでON/OFFの繰り返しであり、真のアナログ信号とは異なりますが、対象物の応答速度がPWMの周波数に比べて十分に遅い場合には、実質的にアナログ信号と同様の効果が得られます。
STM32のタイマーとPWMの関係
STM32マイクロコントローラーにおいて、PWM波形を生成する中心的な役割を担うのは「タイマー(Timer)」と呼ばれるペリフェラルです。STM32のタイマーは非常に多機能であり、PWM生成はその数ある機能の一つに過ぎません。
STM32のタイマーの種類
STM32シリーズには、用途に応じていくつかの種類のタイマーが搭載されています。
- Advanced-control Timers (TIM1, TIM8など): 高度な機能を持つタイマーで、特にモーター制御や電源コンバータ制御など、複雑なPWM波形生成に適しています。デッドタイム挿入、ブレーク入力、多相PWM出力といった機能を持っています。
- General-purpose Timers (TIM2, TIM3, TIM4, TIM5, TIM9, TIM10, TIM11, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17など): 一般的な用途に広く使われるタイマーです。PWM生成、入力キャプチャ、出力コンペア、外部イベントカウントなど、様々なモードで動作します。多くのSTM32マイコンで利用可能であり、PWM生成の入門にもよく使われます。
- Basic Timers (TIM6, TIM7): 最もシンプルなタイマーで、主に時間計測やDACトリガー生成などに使われます。PWM出力機能は持ちません。
- Low-power Timers (LPTIMx): 低消費電力用途に特化したタイマーです。
- System Timers (SysTick): OSのタスクスイッチングなど、システムレベルの時間管理に使われるタイマーです。
- Watchdog Timers (IWDG, WWDG): マイコンが暴走した際にリセットをかけるためのタイマーです。
PWM生成に利用できるのは、基本的にAdvanced-control TimersとGeneral-purpose Timersです。これらのタイマーは、内部にカウンター、プリスケーラー、各種レジスタ(ARR, CCRなど)を備えており、これらの設定によってPWM波形の周期やパルス幅を制御します。
タイマーの基本構成要素
PWM生成に使われるSTM32のタイマーは、以下のような基本要素から構成されています。
- クロックソース (Clock Source): タイマーを動作させるための基準となるクロック信号です。通常、システムクロック(HCLK)やその分周されたクロック(APBバスのクロック)が使われます。外部クロックや内部RC発振器を選択できるタイマーもあります。
- プリスケーラー (Prescaler): クロックソースから供給されるクロック信号を分周する機能です。タイマーのカウンターに供給されるクロック周波数を低くすることで、タイマーの最大周期を長くすることができます。プリスケーラーは、設定値に1を加えた値でクロックを分周します。例えば、プリスケーラー設定値がPであれば、クロックは(P+1)で分周されます。
- カウンター (Counter): プリスケーラーで分周されたクロックパルスを数えるレジスタです。カウンターの値は、アップカウント、ダウンカウント、またはアップ/ダウンカウントのいずれかのモードで変化します。
- ARR (Auto-Reload Register): カウンターが到達する上限値(または下限値)を設定するレジスタです。カウンターがARRの値に達すると、次のカウントでゼロ(またはARRの値)に戻ります。このARRの設定値によって、タイマーの「周期」が決まります。
- CCR (Capture/Compare Register): 出力コンペアモードで使用されるレジスタです。タイマーのカウンター値とこのCCRの値が一致した際に、特定のイベント(割り込み発生や、関連する出力ピンの状態変化)が発生します。PWM生成においては、このCCRの値がパルス幅(ON時間またはOFF時間)を決定します。
STM32におけるPWMの仕組み詳解
ここでは、STM32のタイマーがどのようにPWM波形を生成するのか、その詳細な仕組みを掘り下げていきます。General-purpose Timer(TIMx)を例に説明します。
タイマーの動作モード
PWM生成には、タイマーのカウンターが特定のモードで動作する必要があります。最も一般的なのはアップカウントモードです。
- アップカウントモード: カウンターは0から開始し、プリスケーラーによって分周されたクロックパルスが入るたびにインクリメント(+1)していきます。カウンターの値がARRレジスタの値に達すると、カウンターは再び0に戻り、タイマー周期が完了したことを示す更新イベント(Update Event)が発生します。この繰り返しによって、タイマーの周期的な動作が実現されます。
カウンタとARRによる周期の設定
タイマーの周期(そして周波数)は、タイマーに供給されるクロック周波数、プリスケーラーの値、そしてARRレジスタの値によって決まります。
- タイマーに供給されるクロック周波数:
f_timer_clk
[Hz] - プリスケーラー設定値:
PSC
- プリスケーラーによる分周後のカウンタクロック周波数:
f_cnt_clk = f_timer_clk / (PSC + 1)
[Hz] - ARR設定値:
ARR
アップカウントモードにおいて、カウンターが0からARRまでカウントアップし、再び0に戻るまでにかかる時間(これがタイマー周期)は、ARR+1ステップ分のカウント時間です。
- 1ステップあたりの時間 = 1 /
f_cnt_clk
= (PSC + 1) /f_timer_clk
[秒] - タイマー周期
T_period
= (ARR + 1) × (1ステップあたりの時間) = (ARR + 1) × (PSC + 1) /f_timer_clk
[秒]
周波数 f_PWM
は周期の逆数なので:
f_PWM = f_timer_clk / ((PSC + 1) * (ARR + 1))
[Hz]
この計算式から分かるように、f_timer_clk
、PSC
、ARR
の値を適切に設定することで、生成したいPWM波形の周波数を正確に調整できます。
出力コンペアレジスタ (CCR) と出力コンペアモード
タイマーには、いくつかの「チャンネル」が設けられています。それぞれのチャンネルは、カウンターの値と独立して比較を行うためのCCRレジスタ(TIMx_CCR1, TIMx_CCR2, TIMx_CCR3, TIMx_CCR4など)を持っています。これらのCCRレジスタの値とカウンターの値を比較し、その結果に基づいて関連付けられた出力ピン(TIMx_CHx)の状態を変化させるのが「出力コンペアモード」です。
PWMを生成するために使用される出力コンペアモードは、主に以下の2つです。
- PWM Mode 1:
- アップカウントモードの場合:カウンターが0からカウントを開始し、カウンター値がCCRレジスタの値よりも小さい間、出力はアクティブレベル(通常はHigh)になります。カウンター値がCCR値に達すると、出力は非アクティブレベル(通常はLow)に切り替わります。そして、カウンターがARR値に達して0に戻るとき(更新イベント)、出力は再びアクティブレベルに戻ります。
- これにより、パルス幅がCCRの値に比例したPWM波形が生成されます。
- PWM Mode 2:
- アップカウントモードの場合:PWM Mode 1とは逆に、カウンター値がCCRレジスタの値よりも小さい間、出力は非アクティブレベル(通常はLow)になります。カウンター値がCCR値に達すると、出力はアクティブレベル(通常はHigh)に切り替わります。そして、カウンターがARR値に達して0に戻るとき(更新イベント)、出力は再び非アクティブレベルに戻ります。
- これはPWM Mode 1の波形を反転させたような波形になります。
一般的にはPWM Mode 1がよく使われます。出力のアクティブレベルをHighとする設定が一般的ですが、Lowに設定することも可能です。
デューティサイクルの計算方法
アップカウントモードでPWM Mode 1を使用し、出力のアクティブレベルをHighとした場合、PWM波形のON時間(パルス幅)は、カウンターが0からCCRの値に達するまでの時間、つまりCCR+1ステップ分の時間になります。(カウンターが0のときから数え始め、CCRに達した瞬間に状態が変化するため)。
- ON時間 = (CCR + 1) × (1ステップあたりの時間) = (CCR + 1) × (PSC + 1) /
f_timer_clk
[秒]
周期は (ARR + 1) × (PSC + 1) / f_timer_clk
[秒] でした。
したがって、デューティサイクル (%) は:
Duty Cycle (%) = (ON時間 / 周期) × 100
Duty Cycle (%) = [ (CCR + 1) × (PSC + 1) / f_timer_clk ] / [ (ARR + 1) × (PSC + 1) / f_timer_clk ] × 100
Duty Cycle (%) = (CCR + 1) / (ARR + 1) × 100
この式から分かるように、プリスケーラーやタイマーのクロック周波数に関わらず、デューティサイクルはARRとCCRの値のみによって決まります。
デューティサイクルを制御するには、このCCRレジスタの値を変更すれば良いのです。CCRの値を0からARRまで変化させることで、デューティサイクルを約0%から約100%まで変化させることができます。
CCR = 0
の場合:ON時間は1ステップ分(カウンターが0のときのみHigh)または0ステップ分(常にLow)。設定によっては0%デューティサイクル(常にLow)になります。CCR = ARR
の場合:ON時間はARR+1ステップ分。周期と同じON時間なので、デューティサイクルは100%(常にHigh)になります。CCR
が0からARRの間の場合:デューティサイクルは上記の計算式で求まります。
例えば、ARR = 99
と設定すると、タイマーの周期は100カウント分になります。このとき、CCR = 49
と設定すれば、デューティサイクルは (49 + 1) / (99 + 1) = 50 / 100 = 50%
となります。
プリロード機能 (Preload)
タイマーのARRレジスタやCCRレジスタには、多くの場合「プリロード機能」があります。この機能が有効になっていると、ソフトウェアがレジスタの値を変更しても、その新しい値はすぐに有効にならず、次の更新イベント(カウンターがARRに達して0に戻るタイミング)まで内部のシャドウレジスタに保持されます。更新イベントが発生したときに、シャドウレジスタの値が実際の動作レジスタにコピーされて有効になります。
PWM生成においては、このプリロード機能を有効にすることが推奨されます。これにより、デューティサイクルや周期の変更がタイマーの周期の途中で行われることを防ぎ、波形が乱れることなく滑らかに変更されるようになります。
出力イネーブル (Output Enable)
タイマーチャンネルがPWM出力として機能するためには、そのチャンネルの出力機能を有効にする必要があります。これは、タイマーのCCER(Capture/Compare Enable Register)レジスタで行います。また、GPIOピンの設定も、そのタイマーチャンネルの代替機能(Alternate Function: AF)として設定する必要があります。
高度な機能 (Advanced Features)
Advanced-control Timers (TIM1, TIM8など) は、General-purpose Timersに加えて、さらにPWM応用を高度化する機能を持っています。
- デッドタイム挿入 (Dead Time Insertion): モーター制御などで、同時にONになってはいけない2つのスイッチ(例: Hブリッジの上下アーム)を制御する際に、片方のスイッチがOFFになってから、もう片方のスイッチがONになるまでの短い遅延時間(デッドタイム)を自動的に挿入する機能です。これにより、上下アームの同時導通による短絡を防ぎます。特に3相モーター制御などで重要になります。
- ブレーク機能 (Break Function): 外部からの緊急停止信号(例: 過電流検出、過熱検出)やソフトウェアトリガーに応じて、全てのPWM出力を強制的に非アクティブ状態(通常はLowインピーダンスまたは特定の安全な状態)にする機能です。システムの安全性を確保するために使用されます。
- 補数出力 (Complementary Output): 一つのチャンネル設定から、位相が反転した(逆相の)PWM波形を自動的に生成する機能です。これもモーター制御などでよく使われます。デッドタイム挿入機能と組み合わせて使用することが多いです。
- センターアラインモード (Center-aligned Mode): アップカウントモードやダウンカウントモードとは異なり、カウンターが0からARRまでカウントアップし、その後ARRから0までカウントダウンするという動作を繰り返します。PWM出力のON/OFF切り替えが、カウントアップ時とカウントダウン時の両方で発生します。このモードで生成されるPWM波形は、パルスが周期の中心に対して対称になります。モーター制御や電源コンバータで、高調波成分を低減したい場合などに使用されます。
これらの高度な機能は、特定の応用分野で非常に有用ですが、基本的なPWM生成にはGeneral-purpose TimerのアップカウントモードとPWM Mode 1/2で十分な場合が多いです。
STM32CubeMX/CubeIDEを使ったPWMの簡単な使い方
STM32の開発では、STMicroelectronicsが提供するグラフィカルコンフィギュレーションツールであるSTM32CubeMXと、統合開発環境であるSTM32CubeIDEを使用するのが一般的です。これらのツールを使うことで、タイマーやPWMの設定を視覚的に行い、必要な初期化コードを自動生成できます。ここでは、これらのツールを使ったPWM生成の簡単な手順を解説します。
開発環境の準備
- STM32CubeIDEをSTMicroelectronicsのウェブサイトからダウンロードし、インストールしておきます。STM32CubeIDEには、STM32CubeMXの機能が統合されています。
プロジェクト作成手順
- STM32CubeIDEを起動し、「File」->「New」->「STM32 Project」を選択します。
- Target Selection:
- 「Part Number」タブで、使用するSTM32マイクロコントローラーの型番(例: STM32F401RETx)を入力・選択します。
- 「Commercial Name」や「Board Selector」からも選択できます。
- 選択後、「Next」をクリックします。
- Project Name: プロジェクト名(例:
STM32_PWM_Example
)を入力します。「Targeted Project Type」は「Empty」または「STM32Cube」を選択します。ここでは「STM32Cube」を選択するのが一般的です。「Firmware Package Name and Version」はデフォルトの最新版で構いません。「Finish」をクリックすると、.ioc
ファイルが作成され、STM32CubeMXの画面が開きます。
STM32CubeMXでの設定
STM32CubeMXの画面(Device Configuration Tool)が開いたら、以下の手順でPWMの設定を行います。
- System Core 設定:
- 左ペインの「System Core」を展開し、「RCC」を選択します。
- 「High Speed Clock (HSE)」や「Low Speed Clock (LSE)」のソースを設定します。通常はHSEをCrystal/Ceramic Resonatorに設定し、外部水晶振動子を使用します。
- Clock Configuration:
- 画面上部の「Clock Configuration」タブに切り替えます。
- ここではシステムクロックの周波数を設定します。HSEやHSI(内部発振器)を元に、PLL (Phase-Locked Loop) を使ってシステムクロック(HCLK)を生成します。タイマーのクロックソースは通常、APBバスのクロック(PCLK)から供給されます。タイマーのクロック周波数がPWMの周波数精度や範囲に影響するため、ここで正確なクロック周波数を設定することが重要です。APB1タイマークロック(TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14など)とAPB2タイマークロック(TIM1, TIM8, TIM9, TIM10, TIM11, TIM15, TIM16, TIM17など)の周波数を確認します。多くのデバイスでは、APBクロックが分周されないか、または2倍されてタイマークロックとして供給されます。具体的な倍率はデータシートやリファレンスマニュアルで確認が必要です。CubeMXの画面でもタイマーのクロック周波数が表示されます。
- タイマー設定:
- 左ペインの「Timers」を展開し、使用したいタイマー(例:
TIM3
)を選択します。 - 設定画面の「Mode」セクションで、
Clock Source
をInternal Clock
に設定します。 - PWM出力を使用したいチャンネル(例:
Channel 1
)のMode
をPWM Generation CH1
に設定します。(他のチャンネルも必要に応じて同様に設定)。 - これで、
TIM3_CH1
に対応するGPIOピンが自動的にタイマー機能(Alternate Function)として設定されます。どのピンが割り当てられるかは、選択したMCUのピン配置によって決まります。Pinout View画面で確認できます。 - 「Configuration」タブに切り替えます。
- 「Parameter Settings」でタイマーの動作パラメータを設定します。
Prescaler (PSC)
: 0から65535までの値を設定します。これによりタイマーのカウンタクロック周波数を決定します。例えば、タイマークロックが84MHzで、カウンタクロックを1MHzにしたい場合、PSC = 84 - 1 = 83
と設定します。(分周比はPSC+1なので)。Counter Mode
:Up
を選択します(通常はデフォルトでUp)。Period (ARR)
: タイマー周期を決める値を設定します。0から65535までの値を設定できます(タイマーの種類によっては32ビットの場合もあります)。例えば、カウンタクロックが1MHz(周期1μs)で、PWM周期を1ms(1000μs)にしたい場合、Period (ARR) = 1000 - 1 = 999
と設定します。(周期はARR+1カウントなので)。- 上記の
Prescaler
とPeriod (ARR)
の設定により、PWMの周波数が決定されます。CubeMXの画面上で、設定した周波数が表示されるので確認してください。計算式:f_PWM = f_timer_clk / ((PSC + 1) * (ARR + 1))
- 「Output Compare Mode」セクションで、使用するチャンネル(例: Channel 1)のパラメータを設定します。
Mode
:PWM mode 1
またはPWM mode 2
を選択します。通常はPWM mode 1
を選択します。Pulse (CCR)
: PWM波形の初期ON時間を決定する値を設定します。0からPeriod (ARR)
までの値を設定できます。この値によって初期のデューティサイクルが決まります。計算式:Duty Cycle (%) = (Pulse + 1) / (Period + 1) × 100
(正確にはPulseの値そのものやPulse+1になるかはタイマーの実装や設定によるが、ここでは便宜的にPulse+1として説明)。例えば、Period = 999
の場合、Pulse = 499
と設定すれば初期デューティサイクルは約50%になります。Output Fast mode
: 有効にすると、コンペア一致時の出力切り替えが高速になります。通常は有効で構いません。Output Compare Preload
:Enable
に設定します。これにより、ソフトウェアによるCCR値の変更が次の更新イベントで有効になります。Output Polarity
:High
またはLow
を選択します。High
を選択すると、PWM mode 1
ではデューティサイクルが高いほど出力がHighになる時間が長くなります。Output State
:Enable
に設定します。これにより、そのチャンネルの出力ピンが有効になります。
- 左ペインの「Timers」を展開し、使用したいタイマー(例:
- GPIO 設定:
- 「Pinout & Configuration」タブに戻り、設定したタイマーチャンネルに対応するピン(例: PA6 for TIM3_CH1)が緑色になっていることを確認します。マウスカーソルを合わせると、割り当てられた機能が表示されます。ピン設定の詳細を確認したい場合は、左ペインの「System Core」->「GPIO」を選択し、該当ピンの設定を確認します。代替機能として設定されていることを確認します。
コード生成
設定が完了したら、プロジェクトのコードを生成します。
- 画面上部の「Device Configuration Tool Code Generation」アイコン(歯車のようなアイコン)をクリックするか、「Project」->「Generate Code」を選択します。
- 生成オプションを確認し、「OK」をクリックします。
- STM32CubeIDEが、設定に基づいた初期化コード(
main.c
,tim.c
,gpio.c
など)を生成します。
コードの編集(main.c)
生成されたコードを開き、main.c
ファイルを編集してPWM出力を開始し、必要に応じてデューティサイクルを変更します。
- プロジェクトエクスプローラーで「Core」->「Src」->「main.c」を開きます。
main
関数の中に、生成されたタイマー初期化関数 (MX_TIMx_Init()
) が呼び出されていることを確認します。-
PWM出力を開始するため、
main
関数の初期化部分(while(1)
に入る前など)に以下のHAL関数を追加します。
c
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // TIM3のChannel 1でPWM出力を開始
/* USER CODE END 2 */
ここで、htim3
はTIM3タイマーのハンドル構造体で、自動生成されたtim.c
内で定義されています。TIM_CHANNEL_1
は使用するチャンネルを指定するマクロです。 -
デューティサイクルを動的に変更したい場合は、
while(1)
ループの中でCCRレジスタの値を変更します。HALライブラリには直接CCRを設定する関数はありませんが、マクロを使ってアクセスできます。
“`c
/ USER CODE BEGIN WHILE /
while (1)
{
/ USER CODE END WHILE // USER CODE BEGIN 3 /
// 例:デューティサイクルを段階的に増加させる
for (uint32_t duty = 0; duty <= 999; duty += 10) // Period (ARR)が999の場合
{
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty); // TIM3_CH1のCCR値を設定
HAL_Delay(50); // 50ms待つ
}// 例:デューティサイクルを段階的に減少させる
for (uint32_t duty = 999; duty >= 0; duty -= 10) // Period (ARR)が999の場合
{
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty); // TIM3_CH1のCCR値を設定
HAL_Delay(50); // 50ms待つ
if (duty < 10) break; // unsigned intの場合の終了条件
}
}
/ USER CODE END 3 /
``
__HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_x, value)マクロは、指定したタイマー(
&htimx)の指定したチャンネル(
TIM_CHANNEL_x)のCCRレジスタに
valueを設定します。設定する
valueは、0から
Period (ARR)までの範囲で指定します。この
valueがデューティサイクル計算式の
CCRに対応します。デューティサイクル
% = (value + 1) / (ARR + 1) * 100となります(ただし、一部タイマーや設定で
value / (ARR + 1) * 100`となる場合もあります。リファレンスマニュアルや実際に波形を確認して調整してください。CubeMXの初期設定でPulse=0が0%デューティサイクル、Pulse=ARRが100%デューティサイクルに近い振る舞いをすることが多いです)。
ビルドと書き込み
- コードを保存し、「Project」->「Build Project」を選択してプロジェクトをビルドします。エラーがないことを確認します。
- STM32ボードをPCに接続します。
- 「Run」->「Debug」または「Run」を選択します。デバッグ構成/実行構成を確認し、ボードへの書き込みを行います。
動作確認
PWM出力ピン(例: PA6)にLEDと電流制限抵抗を接続すると、デューティサイクルの変化に応じてLEDの明るさが変化するのが確認できます。また、オシロスコープを使って該当ピンの波形を観測すれば、設定した周波数とデューティサイクル(ON時間)を持つ方形波が出力されていることを確認できます。
PWMの応用例
PWMはその柔軟性から、非常に多岐にわたる分野で活用されています。代表的な応用例をいくつか紹介します。
-
LEDの輝度制御 (Dimming):
最も単純で分かりやすい応用例です。LEDに供給する電力の実効値をPWMで制御することで、LEDの明るさを滑らかに調整できます。人間の目には、数百Hz以上の高速な点滅はちらつきとして認識されず、明るさが変化しているように見えます。PWMのデューティサイクルを0%から100%まで変化させることで、LEDを完全に消灯した状態から最大輝度まで制御できます。 -
DCモーターの速度制御:
DCモーターに印加する電圧の実効値をPWMで制御することで、モーターの回転速度を調整できます。モーターのインダクタンスがPWMの高速なON/OFFを平均化するため、モーターは振動することなく滑らかに回転します。PWM周波数は、モーターの種類やサイズに応じて数kHzから数十kHzが一般的です。周波数が低すぎると可聴ノイズが発生したり、モーターがスムーズに回転しなかったりすることがあります。デューティサイクルを上げると実効電圧が高くなり、回転速度が増加します。 -
サーボモーターの角度制御:
ラジコンなどでよく使われるサーボモーターは、PWM信号のON時間(パルス幅)によって回転軸の角度を制御します。通常、周期は約20ms(周波数50Hz)と一定で、ON時間を1msから2msの間で変化させます。例えば、ON時間1msで0度の位置、1.5msで90度(中心)の位置、2msで180度の位置といったように、パルス幅と角度が対応しています。STM32でサーボモーターを制御する場合、タイマーの周期を20msに設定し、CCRレジスタの値を変更してパルス幅(ON時間)を1ms~2ms相当になるように調整します。 -
オーディオ出力 (Class-D Amplifier):
オーディオ信号(アナログ電圧)を、高速なPWM信号のデューティサイクルに変換することで、効率の良いデジタルアンプ(Class-Dアンプ)を構成できます。音声信号の瞬時電圧が高いほどデューティサイクルを大きく、低いほどデューティサイクルを小さくします。非常に高いスイッチング周波数(数百kHz~数MHz)で動作させ、PWM波形をローパスフィルタに通すことで元の音声信号を復元します。STM32の高性能タイマーとDMA機能を使うことで、ソフトウェアベースのPWMオーディオ出力(ビットストリームDACやデルタシグマ変調など)も実現可能です。 -
スイッチング電源 (DC-DC Converterなど):
DC-DCコンバータやAC-DCコンバータなどのスイッチング電源回路において、スイッチング素子(MOSFETやIGBTなど)のON/OFF期間をPWMで制御することで、出力電圧や電流を安定化させます。この応用では、高いスイッチング周波数(数十kHz~MHz)と、負荷変動や入力電圧変動に応じたデューティサイクルのリアルタイムな高精度制御が求められます。STM32のAdvanced-control Timersが持つデッドタイム挿入やブレーク機能などが特に有用です。 -
通信(IR通信など):
赤外線リモコンなどで使用される変調信号をPWMで生成することがあります。特定のキャリア周波数(例: 38kHz)のパルス列を、送信したいデータパターンに応じてON/OFF(バースト信号)させることでデータを伝送します。STM32のタイマーのPWM機能と組み合わせることで、正確なキャリア周波数とパルスパターンを生成できます。
これらの応用例は、PWMが単にON/OFFを繰り返す波形であるだけでなく、その周期とデューティサイクルを精密に制御できるSTM32のタイマー機能と組み合わせることで、様々な物理量を制御するための強力なツールとなることを示しています。
PWM使用上の注意点とトラブルシューティング
STM32でPWMを使用する際に遭遇しやすい問題や、設定時の注意点について解説します。
-
クロック設定の確認:
- タイマーに供給されるクロック周波数が正しく設定されているか、Clock Configurationタブで確認します。HSEやPLLの設定ミス、APBプリスケーラーの設定によって、意図したタイマークロック周波数になっていないことがあります。
- タイマーの周波数は
f_PWM = f_timer_clk / ((PSC + 1) * (ARR + 1))
で計算されます。設定したPSCとARRの値から計算される周波数が、必要な周波数と一致しているか確認してください。 - 特にAPBバスのタイマークロックソースが、APBクロックをそのまま使うのか、または2倍されるのかは、STM32のファミリーやレジスタ設定(RCC_DCKCFGRなど)によって異なります。リファレンスマニュアルを確認するか、CubeMXの表示を信用してください。
-
ピン設定の確認:
- 使用するタイマーチャンネルに対応するGPIOピンが、正しく代替機能(Alternate Function: AF)として設定されているか確認します。CubeMXでタイマーチャンネルをPWM Generationに設定すれば自動的にAFに設定されますが、手動で変更したり、他のペリフェラルとピンが競合したりしていないか確認が必要です。
- ピンの出力タイプ(Push-PullまたはOpen-Drain)、出力速度(Low, Medium, High, Very high speed)も、用途に応じて適切に設定します。PWM波形の立ち上がり/立ち下がりを高速にしたい場合は、High speedまたはVery high speedを選択します。
-
ARRとCCRの値の範囲:
- タイマーのARRレジスタとCCRレジスタのビット幅は、タイマーの種類によって異なります。General-purpose Timerは通常16ビットですが、TIM2やTIM5のように32ビットのものもあります。設定する値がレジスタの範囲を超えないように注意が必要です。CubeMXを使用すれば自動的に制限されます。
- CCRの値は、基本的に0からARRまでの範囲で設定します。
-
デューティサイクル0%と100%の挙動:
- CCR=0の場合、デューティサイクルが厳密に0%になるか(常にLow)、それともごく短いパルスが出るか、またCCR=ARRの場合に厳密に100%になるか(常にHigh)、それともごく短いLowパルスが含まれるか、はタイマーの種類や設定(例: Output Compare Fast mode, Preload enable)によって若干異なる場合があります。意図したとおりの波形になっているかは、オシロスコープで確認するのが確実です。特に0%や100%に近いデューティサイクルが必要な場合は注意が必要です。
-
プリロード機能の有効化:
- デューティサイクルを動的に変更する場合、出力コンペアプリロード機能を有効にすることが推奨されます。これにより、変更が次のタイマー周期の開始時に適用され、波形が乱れるのを防ぎます。CubeMXではデフォルトで有効になることが多いですが、無効になっていないか確認してください。
-
HAL関数の使い方:
- PWM出力を開始するには
HAL_TIM_PWM_Start()
関数を使用します。使用するタイマーハンドルとチャンネルを引数に指定します。 - デューティサイクルを変更するには、
__HAL_TIM_SET_COMPARE()
マクロ(またはバージョンによっては関数)を使用します。タイマーハンドル、チャンネル、そして新しいCCR値を引数に指定します。 - 複数のチャンネルでPWMを使用する場合は、それぞれのチャンネルに対して
HAL_TIM_PWM_Start()
を呼び出す必要があります。
- PWM出力を開始するには
-
デバッグ方法:
- オシロスコープ: PWM波形を確認する最も基本的なツールです。周波数、デューティサイクル、信号レベルが意図した通りになっているか確認できます。
- デバッガー: STM32CubeIDEに統合されたデバッガーを使用して、タイマーのレジスタ(TIMx_CR1, TIMx_PSC, TIMx_ARR, TIMx_CCRx, TIMx_CCMRx, TIMx_CCERなど)の値をリアルタイムに確認できます。設定した値が正しく書き込まれているか、カウンタ(TIMx_CNT)が期待通りにカウントアップしているかなどを確認することで、問題の原因を特定するのに役立ちます。
- LED: 低速なPWM(数百Hz以下)であれば、LEDの点滅で周期やON/OFFの様子を視覚的に確認できる場合があります。
-
リソースの競合:
- 一つのGPIOピンは、特定の時点では一つの機能(GPIO入力/出力、タイマー、SPI、I2Cなど)しか持つことができません。使用したいタイマーチャンネルのピンが、他のペリフェナルや機能と競合していないか確認が必要です。CubeMXを使用している場合、競合がある場合は警告やエラーが表示されます。
これらの注意点やトラブルシューティングのヒントを参考に、問題を解決しながらSTM32のPWM機能を活用してください。
まとめ
この記事では、STM32マイクロコントローラーにおけるPWM(パルス幅変調)機能について、その基本的な原理から、STM32のタイマーを使った詳細な仕組み、そして開発環境であるSTM32CubeMX/CubeIDEを使った具体的な設定方法と簡単な使い方までを解説しました。
PWMは、デジタル信号でありながらON時間の割合(デューティサイクル)を変化させることでアナログ的な制御を実現する強力な技術です。STM32では、内蔵された多機能なタイマーペリフェラルを利用して、高精度かつ柔軟なPWM波形を生成できます。タイマーのクロック、プリスケーラー、ARRレジスタで周期(周波数)を、CCRレジスタでパルス幅(デューティサイクル)を制御します。
STM32CubeMX/CubeIDEを使えば、煩雑なレジスタ設定を手動で行うことなく、GUI上で視覚的にタイマーとPWMのパラメータを設定し、必要な初期化コードを自動生成できます。生成されたコードに数行のHAL関数呼び出しを追加するだけで、PWM出力を開始したり、デューティサイクルをリアルタイムに変更したりすることが可能です。
PWMは、LEDの輝度制御、DCモーターの速度制御、サーボモーターの角度制御、オーディオ出力、電源制御など、非常に幅広い応用分野で不可欠な技術です。この記事で解説した仕組みと使い方をマスターすることで、これらの応用をSTM32上で実現するための基盤が得られます。
はじめは簡単なLEDの輝度制御から始めて、徐々に複雑なモーター制御やその他の応用へとステップアップしていくと良いでしょう。今回解説した内容は、STM32のPWM機能の入り口に過ぎません。タイマーには今回触れられなかった様々なモードや連携機能があり、これらを使いこなすことで、さらに高度で複雑な制御も実現できます。
STM32の強力なPWM機能を理解し、使いこなすことは、組み込みシステム開発における大きな一歩となるはずです。ぜひ、この記事を参考に、実際に手を動かしてPWMを体験してみてください。