前のページでは、FspTimer.hライブラリを使って基本的なPWM信号を出力しました。さらに進めて相補PWMを出力できるか試してみましょう。Arduino UNO R4に使われているRA4M1のGPTのハードウェアには、互いに反転した2つのPWM信号を生成し出力する機能があります。この機能をFspTimer.hライブラリで利用できるか探ってみます。
内容がぐっとハードウェア寄りになりますので、読み進める際にはRA4M1のハードウェアマニュアルを合わせて見ていただければと思います。
ーーーーー 目次 ーーーーー
PWM出力(5) - FspTimerライブラリ 裏技編 (このページ)
相補PWM設定時のカウンタ動作は?
相補PWMというのは、1つのPWM信号に対してHIGH、LOW反転したもう1つのPWM信号をセットで出力するものです。モータ用インバータなどで、巻線に電圧を印加する電源側、GND側の2つのFETを交互にON、OFFして通電する時に利用されます。また2つのFETが同時にONしないよう隙間を空けるデッドタイム区間を付加することもあります。RA4M1では、GPTタイマーのカウント方式を三角波PWMモードに設定することで相補PWMの出力ができます。

三角波PWMモードでは、カウンタGTCNTは0から増加して設定値になったらそこから減少し0に戻ったらまた増加、を繰り返します。両者でのPWM出力A、Bの一例も示してあります。デッドタイムを付加する場合では、コンペアマッチBにはAからずれた値を設定して出力します。
ここでPWM設定の裏技を
UNO R4 MINIMAで、GPT0を使ってピンD6とD7から相補PWM出力します。プログラムをGitHubに置きました。プログラム名は pwm_by_fsptimerlib_on_triangle-wave.ino です。
https://github.com/inteGN/Arduino_UNO_R4_GPT_PWM_Examples
主要部分は色を変えました。
//timer output configurate
gptGtior_set.gtior_b.gtioa = 0x07; //set LOW initially, LOW at cycle end and toggle at compare-match
gptGtior_set.gtior_b.gtiob = 0x0B; //set LOW initially, HIGH at cycle end and toggle at compare-match
gptGtior_set.gtior_b.oae = 1; //enable A output
gptGtior_set.gtior_b.obe = 1; //enable B output
bool rv = timer0.begin(TIMER_MODE_PWM, GPT_TIMER, 0, pwm_period, pwm_count0, TIMER_SOURCE_DIV_1);
if (rv) {
timer0.add_pwm_extended_cfg();
auto cfg = timer0.get_cfg();
auto ext = (gpt_extended_cfg_t*)cfg->p_extend;
auto pwm_cfg = (gpt_extended_pwm_cfg_t*)ext->p_pwm_cfg;
cfg->mode = TIMER_MODE_TRIANGLE_WAVE_SYMMETRIC_PWM;
ext->gtior_setting.gtior = gptGtior_set.gtior;
pwm_cfg->dead_time_count_up = 80;
pwm_cfg->dead_time_count_down = 0; //RA4M1 does not use dead_time_count_down
timer0.open();
timer0.set_duty_cycle(pwm_count0, CHANNEL_A); //set after GPT0 is configurated by open()
timer0.start();
delayMicroseconds(100); //wait for 2 cycle of PWM
//gpio output configurate, only IOPORT_PERIPHERAL_GPT1 is usable here
pinPeripheral(D6, (uint32_t)(IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_GPT1)); //GPT0_B output
pinPeripheral(D7, (uint32_t)(IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_GPT1)); //GPT0_A output
}
説明の順番を変えて下の部分から。まず、begin()でtimerのインスタンスを初期化します。次に三角波PWMモードでの各種設定をするため、add_pwm_extended_cfg()を実行してPWM拡張設定データの構造体を付加します。
ここで裏技です。UNO R4では、コアライブラリによっていくつかのGPTがのこぎり波PWM出力モードの、TIMER_MODE_PWMにリザーブされています。GPT0もリザーブされていて、begin()の段階で三角波PWMモードのTIMER_MODE_TRIANGLE_WAVE_SYMMETRIC_PWMを設定しても受け付けられません。そのためTIMER_MODE_PWMでbegin()しておいて、その後に設定データの構造体にアクセスして三角波PWMモードに変更します。また、拡張データの構造体には出力パルスのHIGH、LOW設定、PWM拡張設定データの構造体にはデッドタイム設定もあるので、それらも設定します。
これらの設定は、open()を実行した時点でGPT0の各レジスタに反映されます。FspTimer.hによるGPT設定データの構造体とその配置を以下に示します。

出力パルスのHIGH、LOW設定は、色を変えた上の部分で作っておきました。A出力は周期終わりでLOW、コンペアマッチでトグルの設定、B出力は周期終わりでHIGH、コンペアマッチでトグルの設定にしました。ここはRA4M1ハードウェアマニュアルの汎用PWM タイマI/O コントロールレジスタ GTIORの知識が必要になります。もしかしたらライブラリでなんらかのデフォルト設定がされているかもしれませんが、外部回路と論理をマッチングする必要があるので、自分で設定したほうが安心できます。
ここまで示した設定方法で、汎用PWM タイマデッドタイムコントロールレジスタ GTDTCRは、ライブラリによって逆相波形設定TDRは1になっていて有効にされていました。そのためデューティ比はコンペアマッチAにだけ設定すればよく、もうひとつのコンペアマッチBに対してはデッドタイム設定値を付加して自動的に設定されます。設定後のレジスタ値は以下のようになりました。

相補PWMの出力波形は?
相補PWMのプログラム例でもloop()内でデューティ比を可変していますので、その様子を動画で示します。
1つのGPTで2つPWMを出していて、大きく見るとその波形は互いに反転した関係になります。細かく見ると、片方がLOWになってからもう片方がHIGHになるまで、わずかに両方ともLOWになる区間があります。これが付加されたデッドタイム区間です。
補足
PWM出力が自由に出せるようになると、BLDCモータを回す3相インバータへの適用を考えたくなります。その場合、ピン、GPTとパワー素子、ロータ角度センサとのつながりをどうしよう、という課題があります。レジスタ直接アクセスを併用しセンサのパターンを一括で読みたい、パワー素子を一括でコントロールしたい、などの理由でポートをまとめようとすると、実はそれほど選択肢はなさそうです。
Arduino UNO R4 MINIMAが対象で、かつあくまでポートをまとめる視点での個人的な考えですが、GPT-ピン接続リストを見ると、RA4M1のポートP100~P107のうち6本をPWM出力、ポートP300~P304のうち3本をセンサ入力にしたいところ。ところがP100、P101はアナログ入力なので空けておきたいし、P300とP107はGPT0_Aが被っているし。とすると、P102~P107をPWM出力、P301~P303(またはP302~P304)をセンサ入力にする、というほぼ1点がベストプラクティスと思えます。
PWM出力はここまで。次はGPTとFspTimer.hライブラリについてまだ書いていないところを、使い方を中心にいくつか見てみましょうか。すでにブログで紹介した多重割り込み、AD変換、PWM出力、イベントリンクまででは欠けていたピースがあるかも。
(2026-02-22 追記)
プログラム例を改訂しました、PWM出力の動作に違いはありません。
変更箇所はPWM拡張設定データの構造体 gpt_extended_pwm_cfg_t のp_pwm_cfgの扱いで、staticに置き換えていたのをやめて、add_pwm_extended_cfg()がヒープに確保したものをそのまま使うことにしました。それに伴い、dead_time_count_up などの設定はポインタが指す構造体へのアクセスになるため、アロー演算子で記述する形に変更しています。
当初はPWM拡張設定データの構造体の寿命をどうするか迷って、結局staticを選びました。ですが、ほかの設定データの構造体も動的に確保されていること、ライブラリ内で解放される設計になっていることから、それにしたがうのが適切と判断しました。
English Summary for Advanced Users
Topic: Unlocking Advanced Complementary PWM on Arduino UNO R4 using FspTimer & GPT
In this article, I demonstrate how to access the underlying hardware capabilities of the Arduino UNO R4 to enable Complementary PWM with Dead Time. While the standard FspTimer.h library defaults to basic sawtooth PWM, I explain how to configure the RA4M1’s General PWM Timer (GPT) for Symmetric Triangle-wave PWM mode by accessing its extended configuration structures.
Key Technical Takeaways:
- Accessing Hidden Features: How to initialize the timer and then override the timer_cfg_t structure to enable modes not exposed by the default library functions.
- Hardware-Level Control: A deep dive into the GTIOR (General PWM Timer I/O Control Register) to manually define the toggle logic for Phase A and Phase B.
- Dead Time Insertion: Leveraging the GPT’s hardware dead-time registers (GTDTCR), making this setup highly suitable for BLDC motor driver applications.
For those looking to push the UNO R4 into power electronics, this approach provides the low-level precision that is outside the scope of the standard analogWrite() function.
Keywords: Arduino UNO R4 Minima/WiFi, NANO R4, RA4M1, FspTimer, GPT (General PWM Timer), Complementary PWM, Dead Time Insertion, Register-level control