Arduino Uno R4でロータリーエンコーダポジションをハードウェア計測

# 初めに
ABZ相を持つロータリーエンコーダの回転角をArduino Uno R4でハードウェア計測するための方法を残します。Z相によるカウントリセットも可能です。

Arduino UNO R4 MinimaのMPUはRA4M1(R7FA4M1AB3CFM)です。
[Renesasのサイト](https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ra4m1-32-bit-microcontrollers-48mhz-arm-cortex-m4-and-lcd-controller-and-cap-touch-hmi)で「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公式サイトから引用します。
![4c4417b7-a3f3-4f5d-938f-210e902d979b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556921/c34c8264-ca31-2f98-5be2-4bd90122def4.png)
入力に使うピンの横にある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手順に分けて実施します。図解すると次のイメージです。
```mermaid
graph LR
  GPIO-->D([IRQ3])-->ELC
  ELC-->E([ELC_GPTA])-->GPT
```

まず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逓倍
 ```

 # 最後に
 低消費電力機能は罠だと思います。