RZ/A1Hの位相計数モードを使う
時間が経つのは速いもので、もう師走の下旬です。今年もとりあえず、Advent Calendar向けに記事を1本書きました。今回のはゴリゴリの技術ネタです。ググってもあまり情報が出てこないものにしました。
注:この記事は、OpenEsys Advent Calendar 2023用に作成したものです (僕はもうメンバーではないんですけどね)
What's RZ/A1H?
いわゆるMCUの一種です。Renesas製で、大容量のRAM(10MB)と高性能なコア(Cortex-A9, 最大400MHzのクロック周波数)を特長とします。組み込み画像処理にもってこいですね。また、様々な機能が搭載されています(User's Manual (以下UMと略記)を見ていると、CD-ROM decoderなんて機能がありました)。詳細は製品ページでご確認下さい。
そんなRZ/A1Hですが、mbedを用いてプログラム開発を行うことが出来ます。ただ、mbed OSのAPIからRZ/A1Hの全ての機能が使えるわけではありません。先述のCD-ROM decoderもそうですし、今回扱う位相計数モード(Phase Counting Mode)もそうです。なので、そのような機能を使いたければ開発環境を変えるか、他人の作ったライブラリに頼るか、ライブラリが無ければデータシートを見ながらレジスタを直叩きするしかありません。本記事では、mbedによる開発環境において(いや、開発環境は関係ないかも)、レジスタを叩いて位相計数モードを使用する方法について説明します。
What's Phase Counting Mode?
位相計数モード時(以下PCMと略記)には、2本のピンの電圧変化を検知してカウンタが自動的に増加・減少します。これにより、2相インクリメンタルエンコーダの計測をハードウェア側で(=CPUに負荷をかけずに)させることができます。STM32で言う、エンコーダインターフェースモードです。
Before Getting Started
PCMの使用方法を説明する前に、まずRZ/A1Hのタイマ・カウンタ周りについて説明します。このMCUでは、MTU2 (Multi-Function Timer Pulse Unit 2)というモジュールにタイマ・カウンタの機能が集約されています。このモジュールは5つのchannel (0~4)を持ち、各channelは1つのカウンタを持ちます。また、PCMが設定可能なchannelは1, 2のみです。このため、最大で2つのエンコーダをPCMで扱うことが出来ます。MTU2について詳しくは、UMの10章を参照してください。なお、本記事ではchannel 1を使います。
Workflow
Overview
PCMを使うためには、まず、エンコーダのA・B相を接続するピンに対して設定を行う必要があります。続いてMTU2を起動し、PCMを有効化する設定を行います。そしてカウンタの計数を開始することで、カウンタレジスタからエンコーダの計測値が取り出せます。以下では各手順の説明を行います。
Enable Alternative Mode
まず、エンコーダA・B相から出力されるパルスが、channel 1のクロック供給源となるようにします。PCM時のchannel 1のクロック供給源はUMによればTCLKA, Bなのですが、この機能はどのピンが対応しているかと言いますと、UMのTable 1.6より
TCLKA -> P1_0 or P6_2
TCLKB -> P1_10 or P10_1
となります。今回はP1_0とP1_10を各々TCLKAとBに設定します。この設定を行うに当たって、いくつかのレジスタを操作します。
1. Port Function Control Register (PFCn) / Port Function Control Expansion Register (PFCEn) / Port Function Control Additional Expansion Register (PFCAEn)
これら3つのレジスタを設定することで、P1_0とP1_10にTCLKAとBを割り当てることが出来ます。ここで、UMのtable 1.4より、TCLKA, Bは各々P1_0の3rd alternative function、P1_10の4th alternative functionです。alternative functionというのは、GPIO以外の機能、くらいの認識でいます。この設定を行うためには、UMのtable 54.6より、以下のように各レジスタの各ビットを設定すれば良いです。
PCE1 @<PORT1_base> + 0x0500 + 4
PFCE1 @<PORT1_base> + 0x0600 + 4
PFCAE1 @<PORT1_base> + 0x0A00 + 4
---------------------------------------------------------
m PFCAE1m PFCE1m PFC1m Function
0 0 1 0 3rd Alternative function
10 0 1 1 4th Alternative function
ここで、例えばPFC1mはPFC1のmビット目を表します。これを行うCコードは次のようになります。
uint32_t PORT1_BASE = 0xFCFE3000;
uint16_t *PFC1 = (uint16_t *)(PORT1_BASE + 0x0500 + 4),
*PFCE1 = (uint16_t *)(PORT1_BASE + 0x0600 + 4);
*PFC1 |= 1 << 10;
*PFCE1 |= 1 | (1 << 10);
2. Port IP Control Register (PIPCn)
このレジスタの各ビット値により、対応するピンの入出力をプログラマとalternative functionのどちらが決めるかを設定できます。
PIPCn @<PORTn_base> + 0x4200 + n × 4
------------------------------------
Bit 15 ... 0
PIPCn15 PIPCn0
------------------------------------
PIPCn[15:0] 0 -> The I/O direction is controlled by PMnm bit.
1 -> The I/O direction is controlled by the alternative function.
UM 54.3.14より、今回は入出力をalternative functionに決めさせてあげる必要があるので、PIPC1の0, 10ビット目を1にします。
uint16_t *PIPC1 = (uint16_t *)(PORT1_BASE + 0x4200 + 4);
*PIPC1 |= 1 | (1 << 10);
3. Port Mode Control Register (PMCn)
このレジスタの各ビット値により、対応するピンがport mode (普通のGPIO)で動作するかalternative mode (alternative functionが使える)で動作するかが決まります。
PMCn @<PORTn_base> + 0x0400 + n × 4
------------------------------------
Bit 15 ... 0
PMCn15 PMCn0
------------------------------------
PMCn[15:0] 0 -> Port mode
1 -> Alternative mode
今回はalternative modeにする必要があるので、PMC1の0, 10ビット目を1にします。
uint16_t *PMC1 = (uint16_t *)(PORT1_BASE + 0x0400 + 4);
*PMC1 |= 1 | (1 << 10);
以上の設定で、エンコーダA, B相のパルスがchannel 1に入力されるようになります。
Activate MTU2
実は、MTU2はデフォルトで停止しており、これを起動させないとカウンタが動きません。MTU2を起動させるには、UM 55.2.3より、次のレジスタを操作します。
STBCR3 (Standby Control Register 3) @0xFCFE0420
------------------------------------
Bit 7 ... 3 ... 0
MSTP37 MSTP33 MSTP30
------------------------------------
MSTP33 0 -> MTU2 runs.
1 -> Clock supply to MTU2 is halted.
従って、以下のコードを書けばMTU2が起動します。
uint8_t *STBCR3 = (uint8_t *)0xFCFE0420;
*STBCR3 &= ~(1 << 3);
Enable Phase Counting Mode
長かったですが、ようやくPCMの設定です。これは以下のレジスタを操作することで行えます。
TMDR_1 (Timer Mode Register) @0xFCFF0381
------------------------------------
Bit 7 ... 3 ... 0
MD[3:0]
------------------------------------
MD3 MD2 MD1 MD0 Function
0 1 0 0 PCM 1
1 PCM 2
1 0 PCM 3
1 PCM 4
なお、PCMの各モードについてはUM 10.4.6を参照してください。また、UM 10.3.2より、TMDRの操作はカウンタ(TCNTレジスタ)の計数が停止しているときに行え、とあるので、以下のレジスタを操作して停止します。
TSTR (Timer Start Register) @0xFCFF0280
------------------------------------
Bit 7 6 5 ... 3 2 1 0
CST4 CST3 CST2 CST1 CST0
------------------------------------
CSTn 0 -> TCNT_n count operation is stopped.
1 -> TCNT_n performs count operation.
以上より、PCMを(モード1で)有効化するコードは次のようになります。
uint8_t *TMDR1 = (uint8_t *)0xFCFF0381,
*TSTR = (uint8_t *)0xFCFF0280;
*TSTR &= ~(1 << 1);
*TMDR1 |= 0x04;
Start Counting and Reading Counter
あとはカウンタの計数を開始すれば、TCNT_1レジスタからエンコーダ計測値を取り出すことができます。
*TSTR |= 1 << 1;
uint16_t *TCNT1 = (uint16_t *)0xFCFF0386;
int16_t count = *TCNT1;
// operations using count
Conclusion
やや簡単にですが、RZ/A1Hの位相計数モードの使い方を説明しました。データシートとにらめっこしてレジスタをいじれるようになると、マイコンの性能・機能を最大限生かしたプログラムが作れるようになると思います。時間はかかりますが、マイコンを使い倒したい人はぜひレジスタを直叩きしましょう(笑)。
Reference
この記事が気に入ったらサポートをしてみませんか?