mwf_periph_pwm - PWM, Timer
mwf_periph_pwm - PWM, Timer
PWM,タイマーを用いるための手続きをまとめたペリフェラルオブジェクトです。
クラスオブジェクトthe_pwm[]
を用いて操作します。クラスオブジェクトは配列として定義されていますがPWM0(the_pwm[0]
)からPWM9(the_pwm[9]
)まで利用できます。
PWM10は本ライブラリでは対応しません。
コード例
以下の例では mwf::
名前空間を明示的に指定しています。省略する場合は using namespape mwf;
を記述してください。
TWENETcmpt (AHI 互換関数) を利用する場合は、
#include "mwf_periph_pwm.hpp"
// in some func.
void func() {
// create instance of PMW0.
if (!the_pwm[0]) { // The class object of PMW0 is the_pwm[0].
timer_n_pwm::global_init_pwm_manager(
0, // PWM0
timer_n_pwm::PIN::ALT,
// The timer_n_pwm::PIN::PRIMARY will assign smaller PIO number PIO0 from PWM0,
// or conversely, timer_n_pwm::PIN::::ALT assigns PIO12.
true // set true to enable PWM output.
);
}
// set `x' as an alias of the_pwm[0].
auto& x = the_pwm[0];
// Init the device
//x->init(); // not necessary, the constructor will call init() implicitly.
// if needs INT, set true. (default: false)
x->set_int_enabled(true);
// set prescale
x->set_prescale(6); // 0:32MHz 1:16Mhz 2:8Mhz ...
// set polarity: if false, set HIGH while active state. (default: false)
x->set_invert(false);
// set cycle
// note: 500Hz Duty 10% (Hi 0.2ms, Low 1.8ms)
x->set_cycle(
100 // conut for an active state (HIGH)
, 999 // count for a period (+1)
);
// start PWM out
x->restart();
}
// INT handler (call set_int_enabled() before restart())
// note: if TWENETcmpt library is not linked, the IRQ handlers for PWM1..9 shall be defined.
extern "C" void PWM0_IRQHandler(void) {
... // some procedures.
PWM_ClearStatusFlags(PWM, kPWM_Pwm0);
}
class mwf::periph::timer_n_pwm
global_init_pwm_manager()
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, uint8_t u8_pin_number
, bool b_output_enabled = true
);
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, PIN e_pin
, bool b_output_enabled = true
);
クラスオブジェクトthe_pwm[]
を構築します。構築時にPWM番号と対応するピンを指定します。
PWM番号は(u8_pwm_id
)として指定すします。各PWMは利用可能なピンが2ピンあり(PWM5はPIO16のみ)、本APIではu8_pin_number
として直接ピン番号を指定するか、指定可能なピンのうち若い番号(timer_n_pwm::PIN::PRIMARY
)または別のピン番号(timer_n_pwm::PIN::ALT
)を指定します。
矛盾する番号を指定した場合の動作は未定義です。
global_deinit_pwm_manager()
static void global_deinit_pwm_manager(uint8_t u8_pwm_id);
構築済みのthe_pwm[]
クラスオブジェクトを破棄します。
set_pwm_output()
void set_pwm_output(bool_t b_enable);
bool get_pwm_output();
ピンの出力状態を変更します。b_enable
がtrueの場合は出力を有効にする指定でハードウェアのピンも設定変更されます。falseの場合はデフォルトのピン(conf::pin::conf_defautl()
)に設定します。
- PWM出力中に呼び出すことが出来ます。
global_init_pwm_manager()
のパラメータで出力設定している場合、改めて呼ぶ必要はありません。
set_int_enabled()
void set_int_enabled(bool_t b_enable);
bool get_int_enabled();
割り込みの有効・無効を設定します。b_enable
がtrueの場合は割り込みが有効、falseの場合は無効になります。
- PWM出力中に呼び出すことが出来ます。
- 後述の「割り込みハンドラ」を参照してください。
set_prescale(), set_divisor()
void set_prescale(uint8_t u8_prescale);
void set_divisor(uint16_t u16_div);
PWM制御のプリスケールを設定します。これによりPWM制御周波数が決まります。
- PWM出力中に呼び出すことが出来ます。
set_prescale(u8_prescale)
を指定した場合、制御周波数は0
:32Mhz,1
:16Mhz,2
:8Mhz, …,9
: 62500Hz,10
: 31250Hz,11
以降は未定義(デバッグ時assert
)です。set_divisor(u16_div)
を指定した場合, 制御周波数は (32Mhz / u16_div) です。値域は 1..1024 の範囲で、それ以外の値を指定した場合の振る舞いは未定義です。- PWM周期とDUTY比は
set_cycle()
のパラメータで決まります。- 例えば
set_prescale(2)
と指定した場合は制御周波数は fb=8Mhz です。この設定でset_cycle(2, 10)
を指定すると PWM 周期は fbx10=800Khz で、パルス幅が 2x1/fb=1/8000000=250nsec になります。
- 例えば
set_cycle()
void set_cycle(uint16_t ct_comp, uint16_t ct_period);
uint16_t get_period_val(); // get total period count
uint16_t get_comp_val(); // get active region count
PWM1周期とその中でのアクティブ区間を決めるカウント値を指定します。アクティブ区間の間ピンの値が変化し、その終わりに割り込みが発生します。
ct_comp
までの値がアクティブ、ct_period
が1周期のカウント数です。例えばct_comp
を100
、ct_period
を1000
とした場合、PWM周期はPWM制御周波数で1000カウント分、set_invert(false)
の条件で100カウント分がHIGH、残りの900カウントがLOWになる振る舞いをします。
- PWM出力中に呼び出すことが出来ます。
ct_comp
は0
からct_period-1
までが有効です。アクティブが(ct_period-1/ct_period)
の比率までが上限で100%に設定することが出来ません。set_duty()
では100%の設定を考慮しています。- 1周期分のカウント値
ct_period
について、ハードウェアレジスタにはct_period - 1
として設定しています。本関数にはハードウェアレジスタ値を指定しないよう注意してください。
set_duty()
void set_duty(uint16_t u16duty, uint16_t u16duty_max = 1000);
PWMのDUTY比を設定します。
- 事前に
set_cycle()
を用いて、PWMの1周期のカウント数を指定しておきます。左記の手続きを省略した場合u16duty_max
がPWM周期のカウント数として設定されます。 - 1周期に対して
u16_duty/u16duty_max
の割合をアクティブ区間とします。例えばset_duty(100)
と指定した場合はアクティブ区間は1周期に対して10%です。 u16duty
にu16duty_max
と同じ値を指定した場合は、全区間がアクティブとなりデフォルトの反転しない波形出力set_invert(false)
の場合HIGHレベルに設定します(ハードウェアの制約からアクティブ区間を全区間に設定できないため、内部的には波形出力レジスタを反転して、アクティブ区間を0に設定しています)。- このため
set_duty()
で100%設定した後にset_cycle()
を呼び出すと波形が反転します。混用しないように注意してください。
- このため
set_invert()
void set_invert(bool_t b_invert);
bool get_invert();
出力波形を反転します。false(デフォルト)設定時はアクティブ区間がHIGHレベル、trueではLOWレベルです。
start(), stop()
void start();
void restart();
void stop();
PWM出力の開始、設定&開始(再開)、停止処理を行います。
- 停止処理
stop()
時のピンの状態は、set_invert(false)
(デフォルト)の場合 LOW レベル、set_invert(false)
の場合HIGHレベルです。
class mwf::periph::timer_n_pwm (sys_ev_handler)
sys_ev_handler
はスリープ前後の手続きです。
on_sleep()
PWMの実行状態を保存した上で、スリープ時のピン状態をデフォルト設定に戻す。
on_wakeup()
スリープ前の状態した状態を復元する。
class mwf::periph::timer_n_pwm (sys_global_resource_handler)
sys_global_resouce_handler<T>
(T
はtimer_n_pwm
クラス)は、複数のPWMクラスオブジェクトに対して、1度だけ必要な初期化処理、終了手続きを行うための手続きです。内部的に暗黙に利用されます。
- コンストラクタや
on_wakeup()
でsys_global_resource_handler<T>::init()
を呼び出します。- 最初に作成されたインスタンスの場合は
T::global_init()
を呼び出します。
- 最初に作成されたインスタンスの場合は
- デストラクタや
on_sleep()
でsys_global_resource_handler<T>::deinit()
を呼び出します。- 最後に破棄されるインスタンスの場合は
T::global_deinit()
を呼び出します。
- 最後に破棄されるインスタンスの場合は
T::global_init()
::PWM_Init()
を呼び出し、PWMを初期化します。
T::global_deinit()
::PWM_DeInit()
を呼び出し、PWMの利用終了手続きを行います。
割り込み
set_int_enabled(true)
を設定すると、アクティブ区間の終了で割り込みが発生します。割り込みハンドラはシステムで用意されたもので PWMn_IRWHandler()
(nはPWMチャネル)です。
割り込み発生 割り込み発生
V V
Vcc +----+ +----+
| | | | t
GND----+ +-------------+ +-------- ->
<----> アクティブ区間
<------------------> PWM 1周期
割り込みハンドラを明示的に定義します。TWENETcmpt ライブラリをリンクするかどうかで要定義のハンドラ関数が変わります。
- TWENETcmpt をリンク => 使用する PWM チャネルのみ定義する
- TWENETcmpt をリンクしない => PWM0 から PWM9 チャネルまでの割り込みハンドラを割り込みを使用していなくても明示的に定義する
割り込みハンドラ
TWENET を利用する場合は、割り込み関数(cbToCoNet_u8HwInt()
)、イベント(cbToCoNet_vHwEvent()
)に変換されます。
独自の割り込みハンドラを定義する場合は PWNn_IRQHandler()
を別途定義します。以下の例は PWM1 の定義例です。独自に定義する場合 TWENET の割り込み・イベントは発生しません。
// note: in c file, `extern "C"' should be remoded.
extern "C" void PWM1_IRQHandler(void) {
PWM_ClearStatusFlags(PWM, kPWM_Pwm1);
}