LoginSignup
1
1

Arduino Uno R4のGeneral Purpose Timer(GPT)を使ったPWM出力

Posted at

要約

Arduino Uno R4(以下R4) のレジスタを操作してPWM出力を行う方法を記載します。

下記はMinimaでもWifiでも同様ですが、出力ピンに対する内部ピン(pinout)が2種で異なることに注意して下さい。

実施することは3点です。

  • ピンの選定と設定
  • GPT(General Purpose Timer)の初期設定
  • 周期とdutyの設定

ピンの選定と設定

GPTのビット数の選定

GPTは32bitが2つ、16bitが6つ用意されています。32bitが優位であるものの、16bitで十分な用途ではそちらを選択するべきです。

どちらを使うべきかはPWMのdutyの分解能で決まります。
もしdutyを0.1%=1/1000刻みで変えたい場合、カウンタは1周期の中で1000カウントアップする必要があります。16bitは65536なので十分に余裕があり、実用的には16bitを使えば十分です。

また、分解能はPWM周波数とトレードオフです。Arduino Uno R4は48MHzで動作します。PWMの1周期で必要なカウント数をNとすると、1周期はどんなに短くてもN/48[us]必要です。この逆数の48/N[MHz]が最大PWM周波数なので、Nが1000であればPWM周波数の上限は48kHzです。Nが16bit最大値の65536では732Hzまで遅くなるため、用途によりますが32bitタイマは不適のことが多いでしょう。

なお、delay()やdelayMicroseconds()はAGTという別のタイマを利用するため、ここで考慮する必要はありません。

内部ピンの選定

16bitタイマはGPT162からGPT167という名前がついています。ここではGPT162を使うと仮定します。この時「Renesas RA4M1グループユーザーズマニュアル ハードウェア編」(以下マニュアル)を見ると、対応する出力機能がGTIOC2AおよびGTIOC2Bであること、そのうちGTIOC2AはP103およびP113,P500に割り当てられていることがわかります。

このうちR4 MinimaではP113はD4ピンに割り当てられていますのでこれを利用します。P113はマニュアルでm=1, n=13としてPmnPFSレジスタでピン設定が可能です。

  const int timerPinM = 1;
  const int timerPinN = 13;
  R_PFS->PORT[timerPinM].PIN[timerPinN].PmnPFS_b.PDR = 1;
  R_PFS->PORT[timerPinM].PIN[timerPinN].PmnPFS_b.PSEL = 0b00011;
  R_PFS->PORT[timerPinM].PIN[timerPinN].PmnPFS_b.PMR = 1;

ピンはPDRでデジタル出力として設定します。Arduinoらしくpinmodeなどを使っても大丈夫です。その場合はPSELレジスタの設定を忘れずに実施してください。

GPTの初期設定

まず初期設定のためのレジスタを設定します。この部分はPWMの周波数やdutyと関係がありません。

  R_MSTP->MSTPCRD_b.MSTPD6 = 0;
  R_GPT2->GTCR_b.CST = 0;
  R_GPT2->GTIOR_b.OAE = 1;
  R_GPT2->GTIOR_b.GTIOA = 0b11001;
  R_GPT2->GTBER_b.CCRA = 0b01;

MSTPD6は16bitGPTモジュールの省電力機能を解除し、モジュールに通電させる指令です。CSTは初期設定のためのモジュール停止を、0AEはGTIOC2Aを有効にする命令です。OBEはGTIOC2Bを有効にします(以下同様です)。GTIOAの設定は、「初期出力HIGH」「周期の終わり(リセット)でHIGH」「コンペアマッチ時LOW」を表します。詳細は次の周期設定で記述します。CCRAはバッファリングの設定で、dutyに関係するGTCCRレジスタをバッファリングします。これによりリセットタイミングとdutyタイミングの関係を切り離せます。

周期とduty

レジスタ値の計算

仮にPWMの希望する分解能0.1%とします。先ほど述べたように分解能の逆数が最大カウント数なので、次に述べるgptrCountを1000に設定します。また、希望する出力%を10倍した値を次に述べるgtccrCountに設定します。50%出力をしたい場合、1000カウントのうち500カウントはHIGH出力、500カウントはLOW出力をするということです。PWM周波数は元クロックが48MHzの場合48kHz、元クロックを分周した場合それに応じて周波数が低くなります。

逆に所望の周波数を得たい場合もあります。X[kHz]のPWM出力を得たい場合、48000/X カウントで1周期になるような設定とすればいいです。10kHzの信号が得たければ、gtccrCountは4800です。0.732kHzより遅い信号(1Hzとか)が欲しければ分周するか32bitのレジスタを使いましょう。

レジスタへの書き込み

最後に周期およびdutyに関わる設定を行い、出力を開始します。

  R_GPT2->GTCNT = 0;
  R_GPT2->GTPR = gptrCount - 1; // gptrCountはカウンタの周期
  R_GPT2->GTCCR[0] = gtccrCount;
  R_GPT2->GTCCR[2] = gtccrCount;
  R_GPT2->GTCR_b.CST = 1;

GTCNTはカウンタの値を保持するレジスタで、最初に0に初期化します。GTPRはカウンタの最大値であり、この値を超えるタイミングが「周期の終わり」で、そのタイミングでGTPRは1にリセットされます。そのため、想定する周期よりもカウンタのリセットは1クロック遅く、逆に設定する値は1を減じる必要があります。
GTCCR[0]はこの値と一致した時(コンペアマッチ)に出力を変更する値で、GTIOAの設定により出力がLOWに変わります。GTCCR[2]に設定した値はカウンタリセットのタイミングでGTCCR[0]にコピーされるため、初期設定では同じ値を入れておく必要があります。
最後にCSTを1にすると出力が開始されます。

最後に

R4は12bitのD/Aを持つため従来よりPWMの重要度は低くなりました。ライブラリを介さずにPWMを使うことはあまりないかもしれませんが、何かに役に立てば幸いです。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1