初めに
ABZ相を持つロータリーエンコーダの回転角をArduino Uno R4でハードウェア計測するための方法を残します。Z相によるカウントリセットも可能です。
Arduino UNO R4 MinimaのMPUはRA4M1(R7FA4M1AB3CFM)です。
Renesasのサイトで「Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編」をダウンロードしてください。
2024/01時点でRev.1.10でした。
開発にはArduinoIDE Ver2.2.1を使っています。
ハードウェア的な接続設定
エンコーダのA相をD3ピン、B相をD2ピン、Z相をD12ピンに入力します。ピンの選択には一定の制限があるので後ほど解説します。
当然ですがエンコーダとArduinoのGNDを接続してください。UNO R4はR3以前に比べて電源入力範囲が広がったため、電源も共用可能なケースが多いと思います。
低消費電力モードの解除
リセット状態ではタイマ(GPT、General Purpose Timer)とイベントリンクコントローラ(ELC)は無効になっています。
モジュールストップコントロールレジスタD(MSTPCRD)でGPTを有効にします。なお、本記事では32bitカウンタを使います。
R_MSTP->MSTPCRD_b.MSTPD5 = 0; // 32bitのカウンタ2つ
R_MSTP->MSTPCRD_b.MSTPD6 = 0; // 16bitのカウンタ6つ
モジュールストップコントロールレジスタC(MSTPCRC)でELCを有効にします。
R_MSTP->MSTPCRC_b.MSTPC14 = 0;
入力ピンとタイマの設定
ピン及びタイマを設定します。最初にタイマのカウントを停止します。ただし、リセット時0なので省略可能です。
R_GPT1->GTCR_b.CST = 0;
GPIOピンの汎用設定
GPIOピンをデジタル入力・内蔵プルアップに設定します。まず最初に入力に使うピンとMPUの内部ポートの関係を特定します。Arduino Uno R4のpinout画像をArduino公式サイトから引用します。
入力に使うピンの横にあるP+3桁の数字に着目してください。百の桁がm、十の桁以下がnです。D3ピンを入力に使う場合、P104なのでm=1かつn=4です。P105とP110についても同様です。
PmnPFSレジスタを設定します。PDRでデジタル入力を指定、PCRでプルアップ有効を指定します。
int m=1;
int n=4;
R_PFS->PORT[m].PIN[n].PmnPFS_b.PDR = 0;
R_PFS->PORT[m].PIN[n].PmnPFS_b.PCR = 1;
タイマとGPIOの関係を設定
更に、A相とB相についてはタイマの一部として設定します。PMRをセットして周辺機能用のポートとして使用します。PSELについては0b11(GPT)を設定します。
R_PFS->PORT[m].PIN[n].PmnPFS_b.PMR = 1;
R_PFS->PORT[m].PIN[n].PmnPFS_b.PSEL = 0b11;
GPTの入力として使うピンについて
GPTに使えるピンには制限があり、マニュアル19.6の「入出力端子機能のレジスタ設定」を見ながら進めます。32bitタイマは2つあり、GP320とGP321と名前がついています。ここではGP321を使います。
GP321はGTIOC1AとGTIOC1Bという内部的な入力端子を持ち、GTIOC1Aはマニュアル22.1の表「GPTの入出力端子」に記載の通りGPIOのP105,P109,P405に接続されています。P105はD2、P109はD11、P405は無接続です。つまり、GP321タイマがA相の入力端子とて使えるのはD2とD11のみです。同様にB相はD3とD12に限定されます。
Z相についても制限があるので、ELC機能の項で説明します。
タイマの設定
A相とB相を使って位相計数機能を設定します。マニュアル22.3.10に詳細があり、この通りに設定すればOKです。ここでは位相計数モード1を用います。GTUPSRとGTDNSRは逆に設定するとカウント方向を逆にできます。組み付けや配線に合わせて選択してください。
R_GPT1->GTUPSR = 0x6900;
R_GPT1->GTDNSR = 0x9600;
GTPRにカウンタの最大値を入力します。ここではGPT321を使っているので32bitの最大値を設定します。
R_GPT1->GTPR = 0xffffffff;
CSELCAをセットすることにより、Z相の入力で発生するELC_GPTAイベントでカウンタ値(GTCNT)を0にクリアする設定とします。ELC_GPTAはカウンタを動作開始させた後で設定するので、先にカウンタを開始するためにCSTを1にセットします。
R_GPT1->GTCSR_b.CSELCA = 1 // ELS_GPTAでカウントをクリアする
R_GPT1->GTCR_b.CST = 1;
ELCの設定
RA4M1はイベント駆動が可能なので、Z相によるカウンタクリアを実現するために割り込みイベント発生⇒カウンタクリアという2手順に分けて実施します。図解すると次のイメージです。
まずGPIOと割り込み番号の関係を調べた後、ELCの設定を実施した後でZ相GPIOを設定します。
GPIOからIRQを調べる
ELCで使う割り込み番号(IRQ)はGPIOのピンから決まります。D12の場合はP110なので、表19.7「入出力端子機能のレジスタ設定(ポート1)」を見るとP110はIRQ3に対応します。IRQが振られていないピンもあり、そのピンはELCに使えません。
ELCリンクの設定とELC起動
IRQ番号をGPT(A)およびELS_GPTAに相当するELSR0のHAに設定した後、ELCONを1にセットしてELCを有効にします。ただしIRQ番号とHAの設定値は1ずれます。
R_ELC->ELSR[0].HA = 0x04; // IRQは0始まりだが、ELSRは0が停止を表すため1ずれる
R_ELC->ELCR_b.ELCON = 1;
GPIOへの割り込み設定
GPIO側で割り込みを有効にするため、P110のPmnPFSのISELに1をセットします。
R_PFS->PORT[1].PIN[10].PmnPFS_b.ISEL = 1;
以上で設定を終わります。お疲れさまでした。
肝心のカウント値読み出し方
GTCNTがカウント値にあたります。回転方向によっては負のオーバーフローを起こすため、longまたはsigned longにキャストすると楽です。位相計数モード1では信号は4逓倍されることに注意してください。
(signed long)R_GPT1->GTCNT / 500.0 * 4; // 一回転500パルスのエンコーダで4逓倍
最後に
低消費電力機能は罠だと思います。