GPTW とは?
- RX66T、RX72T、RX72N には、汎用 PWM 機能(GPTW)が備わっています。
- 一般に PWM 生成は MTU を使いますが、GPTW はさらに細かい設定が可能で、MTU の拡張版的な扱いのようです。
- カウンタは32ビットになっており、高いクロックでの駆動が可能なようになっています。
- RX66T、RX72T は GPTW は 10 チャネル、RX72N には 4 チャネルあります。
- RX66T、RX72T はより高いクロック(PCLKC、最大160MHz、200MHz)を分周器のクロックとして使えます。
- RX72N は(PCLKA、最大120MHz)を分周器のクロックとして利用します。
- 「汎用」とありますが、かなり細かい設定が可能で、主に FET や IGBT などのパワーデバイスの制御に向いています。
- RX66T、RX72T には、さらに、高分解能波形成型器を通す事で、より細かい PWM 波形を生成できます。
- インプットキャプチャーや、位相入力(エンコーダー入力)などにも使えます。
- A/D コンバーターを同期して動かす事が出来るので、正確な電圧、電流の検出が行えます。
GPTW 用ポートの設定クラスを作る。
-
最近の RX マイコンは、ポートのアサインを行う候補が増えて、より柔軟性が増したと思えます。
-
そこで、「port_map_gptw」クラスを新規に追加して、専用クラスを用意しました。
-
候補のポリシーは、ハードウェアーマニュアルにある「MPC」にある説明に沿った物にしてあります。
-
自分のフレームワークでは、別プログラムで設定を生成しないので、判りやすさと柔軟性を与える為、「候補」(ORDER)型を使い、設定します。
-
ポートマッピングオーダー型
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief ポート・マッピング・オーダー型
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
enum class ORDER : uint8_t {
BYPASS, ///< ポートマップの設定をバイパスする場合
FIRST, ///< 第1候補
SECOND, ///< 第2候補
THIRD, ///< 第3候補
FOURTH, ///< 第4候補
FIFTH, ///< 第5候補
SIXTH, ///< 第6候補
SEVENTH, ///< 第7候補
};
- GPTW0 A チャネルのポート候補
static bool gptw0_(CHANNEL ch, bool ena, ORDER opt) noexcept
{
bool ret = true;
uint8_t sel = ena ? 0b011110 : 0;
switch(ch) {
/// GTIOC0A (入出力)
/// 224 176 144 100
/// P23 ○ ○ ○ ○
/// P83 ○ ○ ○ ×
/// PA5 ○ ○ ○ ○
/// PD3 ○ ○ ○ ○
/// PE5 ○ ○ ○ ○
/// PH6 ○ × × ×
case CHANNEL::A:
switch(opt) {
case ORDER::FIRST:
PORT2::PMR.B3 = 0;
MPC::P23PFS.PSEL = sel;
PORT2::PMR.B3 = ena;
break;
case ORDER::SECOND:
PORT8::PMR.B3 = 0;
MPC::P83PFS.PSEL = sel;
PORT8::PMR.B3 = ena;
break;
case ORDER::THIRD:
PORTA::PMR.B5 = 0;
MPC::PA5PFS.PSEL = sel;
PORTA::PMR.B5 = ena;
break;
case ORDER::FOURTH:
PORTD::PMR.B3 = 0;
MPC::PD3PFS.PSEL = sel;
PORTD::PMR.B3 = ena;
break;
case ORDER::FIFTH:
PORTE::PMR.B5 = 0;
MPC::PE5PFS.PSEL = sel;
PORTE::PMR.B5 = ena;
break;
case ORDER::SIXTH:
PORTH::PMR.B6 = 0;
MPC::PH6PFS.PSEL = sel;
PORTH::PMR.B6 = ena;
break;
default:
ret = false;
break;
}
break;
制御クラス(gptw_mgr)
- MTU のマネージャークラスと同じような構成にして、「gptw_mgr」クラスを実装しました。
- 現状では、PWM 波形を出力するだけですが、テンプレートを使い設定を参照する事で、複数のマイコンでもシンプルな構成にする事が出来ます。
動作モード
- 動作モードとして、以下の型があります。(今後拡張予定)
- 現状、のこぎり波以外は実装されていません。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief 動作モード型
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
enum class MODE : uint8_t {
PWM_S_HL, ///< のこぎり波 PWM (AB: H --> L)
PWM_S_LH, ///< のこぎり波 PWM (AB: L --> H)
PWM_S_HL_LH, ///< のこぎり波 PWM (A: H --> L, B: L --> H)
PWM_S_LH_HL, ///< のこぎり波 PWM (A: L --> H, B: H --> L)
SINGLE, ///< ワンショット・パルス
PWM_T1, ///< 三角波 PWM 1(谷32ビット転送)
PWM_T2, ///< 三角波 PWM 2(山/谷32ビット転送)
PWM_T3, ///< 三角波 PWM 3(谷64ビット転送)
};
出力制御と型
- 出力制御では、以下の型のどれかを設定出来ます。
- RX66T、RX72T では「反転出力」を指定出来ます。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief 出力型 @n
※反転出力は、RX66T、RX72T の場合にのみ有効
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
enum class OUTPUT : uint8_t {
NONE, ///< 無効
A, ///< A を利用
B, ///< B を利用
AB, ///< AB
NA, ///< 反転 A を利用
NB, ///< 反転 B を利用
NA_B, ///< 反転 A, 正 B を利用
A_NB, ///< 正 A, 反転 B を利用
NA_NB, ///< 反転 A, 反転 B を利用
};
gptw_mgr テンプレートクラス
- gptw_mgr テンプレートのプロトタイプは以下のようになっています。
- パラメータとして、GPTW のチャネル型、割り込み時に起動させる事が可能なファンクタクラスを指定します。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief GPTW マネージャー・クラス
@param[in] GPTWn GPTW[n] ユニット
@param[in] CMTASK コンペアマッチタスク型
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class GPTWn, class CMTASK = utils::null_task>
class gptw_mgr : public gptw_base {
...
};
- gptw_mgr の宣言では、以下のようにします。(RX72N GPTW1 を使った場合)
- RX72N Envision Kit では、PMod コネクタ CN6 に (7)PD0、(8)PD1 がアサインされており、GPTW1 の出力をマッピング出来ます。
/// PMOD Connector: PD0(CN6-7), PD1(CN6-8)
typedef device::GPTW1 GPTW_CH;
const auto ORDER_A = device::port_map_gptw::ORDER::FOURTH;
const auto ORDER_B = device::port_map_gptw::ORDER::FOURTH;
typedef device::gptw_mgr<GPTW_CH, utils::null_task> GPTW;
GPTW gptw_;
GPTW の開始
- プロトタイプは以下のようになっています。
- 周期は、整数値で周波数を指定します。
- RX72T、RX72N ではベースクロックが異なりますが、その定義は、GPTx インスタンスで指定されている為、自動で最適な値を計算します。
- ポート候補で、A、B 出力の「候補」を指定します。
- 「バッファー動作」は、DUTY 設定をバッファリングする事で、DUTYを変更した場合にノイズが出ません。
- 通常、PWM 周期とは非同期に DUTY を変更すると思うので、標準でバッファー動作になっています。
- 設定に反故があると「false」を返して失敗します。
//-----------------------------------------------------------------//
/*!
@brief 開始
@param[in] mode 動作モード
@param[in] out 出力型
@param[in] freq 周期
@param[in] ord_a ポート候補A
@param[in] ord_b ポート候補B
@param[in] ilvl 割り込みレベル(0 なら割り込み無し)
@param[in] buffer バッファー動作を無効にする場合「false」
@return 設定が適正なら「true」
*/
//-----------------------------------------------------------------//
bool start(MODE mode, OUTPUT out, uint32_t freq, typename port_map_gptw::ORDER ord_a, typename port_map_gptw::ORDER ord_b,
uint8_t ilvl = 0, bool buffer = true) noexcept
- GPTW の開始では、動作モード、出力ポート候補、PWM 周波数、などを指定します。
- モードは、PWM_S_HL(初期'H' で 'L' になる)
- 出力は AB
- 周期は 100KHz
- 初期状態で、33%、66%のデューティー幅のパルスを出力します。
{ // GPTW の開始 (PWM / AB 出力)
uint32_t freq = 100'000; // 100KHz
if(gptw_.start(GPTW::MODE::PWM_S_HL, GPTW::OUTPUT::AB, freq, ORDER_A, ORDER_B)) {
utils::format("GPTW%d start: freq: %u\n") % GPTW::value_type::CHANNEL_NO % freq;
duty_a_ = 0.33f;
gptw_.set_duty_a(duty_a_);
duty_b_ = 0.66f;
gptw_.set_duty_b(duty_b_);
} else {
utils::format("GPTW%d start fail...\n") % GPTW::value_type::CHANNEL_NO;
}
}
DUTY の変更
- サンプルでは、ターミナルを接続して、コマンド入力で、A、B チャネルの DUTY を指定できるようにしてあります。
- a duty(0 to 1.0)
- b duty(0 to 1.0)
- help
Start GPTW sample for 'RX72N Envision Kit' 240[MHz]
SCI PCLK: 60000000
SCI Baud rate (set): 115200
SCI Baud rate (real): 115384 (0.16 [%])
CMT rate (set): 100 [Hz]
CMT rate (real): 100 [Hz] (0.00 [%])
GPTW1 start: freq: 100000
# a
A: duty: 0.330
# b
B: duty: 0.660
# b 0.5
#
まとめ
- PWM 波形の出力は、意外と複雑なので、マネージャークラスの介入が欠かせません。
- 出来る範囲で、柔軟な設定が可能なように工夫してありますが、十分ではありません。
- 足りない設定は、gptw_mgr クラスの構成に習って、改修すれば良いと思います。
- ソースコードはコメントも多く、動作の概要を掴みやすいように実装されています。
- 詳細な解説が無くてもソースコードやサンプルコードを少し眺めれば理解できるものと思います。
- gpt_mgr クラスは、単一のソースなので、他のコードを余り意識しなくても構造が判ると思います。
- 他に「RX600/gptw.hpp」、「RX72N/port_map_gptw.hpp」を参照する必要があるかもしれません。
- 「レジスター名」はハードウェアーマニュアルと同一にしてあるので、何かの機能を追加する場合に実装しやすいと思います。