見出し画像

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

User's Manual


この記事が気に入ったらサポートをしてみませんか?