2002/09/29 【ソフトウエア編TOPに戻る】
今回は、MTU(マルチファンクションタイマーユニット)を使って12相のPWM波形を出力させるプログラムをご紹介します。前回はモード1による8相のPWMについてご紹介していますので、そちらもご参照ください。
214−1.モード2によるPWM
SH2-7045Fには0〜4まで5チャンネル分のMTUがあり、チャンネル0、3、4にはそれぞれ4個ずつ、チャンネル1、2にはそれぞれ2個ずつのTGR(タイマージェネラルレジスタ)があります。モード1での各チャンネルの主要なレジスタと出力端子の構成は以下のようになっています。
| チャンネル | タイマカウンタ | ジェネラルレジスタ | 出力端子 |
| MTU0 | TCNT0 | TGR0A | TIOC0A (PE0と共用) |
| TGR0B | TIOC0B (PE1と共用) | ||
| TGR0C | TIOC0C (PE2と共用) | ||
| TGR0D | TIOC0D (PE3と共用) | ||
| MTU1 | TCNT1 | TGR1A | TIOC1A (PE4と共用) |
| TGR1B | TIOC1B (PE5と共用) | ||
| MTU2 | TCNT2 | TGR2A | TIOC2A (PE6と共用) |
| TGR2B | TIOC2B (PE7と共用) | ||
| MTU3 | TCNT3 | TGR3A | TIOC3A (PE8と共用) |
| TGR3B | |||
| TGR3C | TIOC3C (PE10と共用) | ||
| TGR3D | |||
| MTU4 | TCNT4 | TGR4A | TIOC4A (PE12と共用) |
| TGR4B | |||
| TGR4C | TIOC4C (PE14と共用) | ||
| TGR4D |
チャンネル3、4ではモード1にしか対応していないため、前回ご紹介したTGRA/BもしくはTGRC/DのペアでひとつのPWM波形を発生させる動作となりますが、チャンネル0、1、2ではモード2に対応しているため、各MTUでTGRごとにPWM波形を発生させることができます。なので、全部で12相のPWM波形を出力できます。
モード1では各MTUごとにTCNT(タイマーカウンタ)のカウンタクリア要因を用意してあげなければなりませんでした。しかし、モード2では各MTUのTCNTのカウンタクリア要因を、どこかのMTUのTGRに指定することができます。したがって、各MTUごとにカウンタクリア要因(PWMの周期を決定)を用意する必要がなくなり、その分を独立したPWM波形のパルス幅の指定として利用できるようになっています。
なので、PWMの周期が同じでよければ、モード2で動作させることによってPWM出力を多く得ることができるというわけです。例えば、MTU0、1、2のTCNTのカウンタクリア要因を、TGR3Aに指定することによって実現します。
![]() |
左図はモード1で動作するMUT3と、モード2で動作するMTU0の関係を示しています。
MTU3ではTCNT3のカウンタクリア要因をTGR3Aに設定して動作させている様子です。 MTU0では、TCNT0のカウンタクリア要因としてTGR3Aを指定し、TGR0A,B,C,Dの各TGRは、それぞれパルス幅を決定させるための値として動作させます。
図では示していませんが、TCNT0の他に、TCNT1とTCNT2のカウンタクリア要因として全てにTGR3Aを指定することによって、TGR1A,BとTGR2A,Bの各TGRもそれぞれPWM波形のパルス幅を決定するためのレジスタとして動作させることが出来るようになります。
|
214−2.モード2によるPWMプログラミング pwmtest2.c
以下に示すプログラムソースは、12チャンネル分のPWM波形を固定で出力する、もっとも単純な事例です。main関数でそれぞれのTGRを操作する処理を入れれば、サーボモータの角度制御やDCモータの速度制御が出来るようになりますが、ここでは先ずPWM波形を出力させるための設定を中心にご紹介します。
プログラムはここをクリックするとダウンロードできます。pwmtest2.c また、割込みベクタファイルもここをクリックするとダウンロードできます。vector.s 今回のプログラムでは、特に割り込みは利用していません。
|
/************************************* pwmtest2.c 2002.06.09 RIKIYA SH2_7045F PWM MODE 2による12相PWM出力 TIOC0A,0B,0C,0D TIOC1A,1B TIOC2A,2B TIOC3A,3C TIOC4A,4C /*************************************/ #include "sh7040s.h" void boot(void); void __main(void); int main(void); void sectionInit(void); /* __main(ダミー) *******************/ void __main(void){ } /* CPU初期化 ************************/ void boot(void){ /* IOポート設定 */ PFC.PACRH.WORD = 0x0000; /* PA23〜16 */ PFC.PACRL1.WORD = 0x0000; /* PA15〜8 */ PFC.PACRL2.WORD = 0x0145; /* PA7,6,5,2 TXD0,RXD0 */ PFC.PBCR1.WORD = 0x0000; /* PB9,PB8 */ PFC.PBCR2.WORD = 0x0000; /* PB7〜PB0 */ PFC.PCCR.WORD = 0x0000; /* PC15〜PC0 */ PFC.PDCRH1.WORD = 0x0000; /* PD31〜PD24 */ PFC.PDCRH2.WORD = 0x0000; /* PD23〜PD16 */ PFC.PDCRL.WORD = 0x0000; /* PD15〜PD0 */ PFC.PECR1.WORD = 0x5555; /* TIOC4D,4C,4B,4A,3D,3C,3B,3A */ PFC.PECR2.WORD = 0x5555; /* TIOC2B,2A,1B,1A,0D,0C,0B,0A */ PFC.PAIORH.WORD = 0x00ff; /* [OUT]PA23〜16 [IN]-- */ PFC.PAIORL.WORD = 0xffff; /* [OUT]PA15〜0 [IN]-- */ PFC.PBIOR.WORD = 0x03ff; /* [OUT]PB7 〜0 [IN]-- */ PFC.PCIOR.WORD = 0xffff; /* [OUT]PC15〜0 [IN]-- */ PFC.PDIORH.WORD = 0x00ff; /* [OUT]PD23〜16 [IN]PD31〜24 */ PFC.PDIORL.WORD = 0xffff; /* [OUT]PD15〜0 [IN]-- */ PFC.PEIOR.WORD = 0xffff; /* [OUT]PE15〜0 [IN]-- */ /* タイマシンクロ設定 */ MTU.TSYR.BYTE = 0x47; /* TCNT0〜3 同期クリア*/ /* MTU0 TIOC0A PWM MODE 2 設定 */ MTU0.TCR.BYTE = 0x63; /* TCNT SYNC CLEAR,CLOCK/64 */ MTU0.TGRA = 807; /* パルス幅2.23uS x 807 = 1.8mS */ MTU0.TGRB = 671; /* パルス幅2.23uS x 671 = 1.5mS */ MTU0.TIOR.BYTE.H = 0x55; /* 初期 1 , TGR0B → 0 , TGR0A → 0 */ MTU0.TMDR.BYTE = 0xC3; /* PWM MODE2 */ /* MTU0 TIOC0C PWM MODE 2 設定 */ MTU0.TGRC = 898; /* パルス幅2.23uS x 898 = 2.0mS */ MTU0.TGRD = 807; /* パルス幅2.23uS x 807 = 1.8mS */ MTU0.TIOR.BYTE.L = 0x55; /* 初期 1 , TGR0D → 0 , TGR0C → 0 */ /* MTU1 TIOC1A PWM MODE 2 設定 */ MTU1.TCR.BYTE = 0x63; /* TCNT SYNC CLEAR,CLOCK/64 */ MTU1.TGRA = 537; /* パルス幅2.23uS x 537 = 1.2mS */ MTU1.TGRB = 671; /* パルス幅2.23uS x 671 = 1.5mS */ MTU1.TIOR.BYTE = 0x55; /* 初期 1 , TGR1B → 0 , TGR1A → 0 */ MTU1.TMDR.BYTE = 0xC3; /* PWM MODE2 */ /* MTU2 TIOC2A PWM MODE 2 設定 */ MTU2.TCR.BYTE = 0x63; /* TCNT SYNC CLEAR,CLOCK/64 */ MTU2.TGRA = 807; /* パルス幅2.23uS x 807 = 1.8mS */ MTU2.TGRB = 895; /* パルス幅2.23uS x 895 = 2.0mS */ MTU2.TIOR.BYTE = 0x55; /* 初期 1 , TGR2B → 0 , TGR2A → 0 */ MTU2.TMDR.BYTE = 0xC3; /* PWM MODE2 */ /* MTU3 TIOC3A PWM MODE 1 設定 */ MTU3.TCR.BYTE = 0x23; /* TGR3A TCNT CLEAR,CLOCK/64 */ MTU3.TGRA = 8948; /* 周期2.23uS x 8948 = 20mS */ MTU3.TGRB = 671; /* パルス幅2.23uS x 671 = 1.5mS */ MTU3.TIOR.BYTE.H = 0x56; /* TGR3B → 0 , TGR3A → 1 */ MTU3.TMDR.BYTE = 0xC2; /* PWM MODE1 */ /* MTU3 TIOC3C PWM MODE 1 設定 */ MTU3.TGRC = 8948; /* 周期2.23uS x 8948 = 20mS */ MTU3.TGRD = 807; /* パルス幅2.23uS x 807 = 1.8mS */ MTU3.TIOR.BYTE.L = 0x56; /* TGR3D → 0 , TGR3C → 1 */ /* MTU4 TIOC4A PWM MODE 1 設定 */ MTU4.TCR.BYTE = 0x23; /* TIOC4A TCNT CLEAR,CLOCK/64 */ MTU4.TGRA = 8948; /* 周期2.23uS x 8948 = 20mS */ MTU4.TGRB = 671; /* パルス幅2.23uS x 671 = 1.5mS */ PWM.TOER.BIT.OE4A = 1; /* TIOC4A OUTPUT ENABLE */ MTU4.TIOR.BYTE.H = 0x56; /* TGR4B → 0 , TGR4A → 1 */ MTU4.TMDR.BYTE = 0xC2; /* PWM MODE1 */ /* MTU4 TIOC4C PWM MODE 1 設定 */ MTU4.TGRC = 8948; /* 周期2.23uS x 8948 = 20mS */ MTU4.TGRD = 807; /* パルス幅2.23uS x 807 = 1.8mS */ PWM.TOER.BIT.OE4C = 1; /* TIOC4C OUTPUT ENABLE */ MTU4.TIOR.BYTE.L = 0x56; /* TGR4D → 0 , TGR4C → 1 */ /* TCNT0,1,2,3,4 START */ MTU.TSTR.BIT.CST0 = 1; /* TCNT0 START */ MTU.TSTR.BIT.CST1 = 1; /* TCNT1 START */ MTU.TSTR.BIT.CST2 = 1; /* TCNT2 START */ MTU.TSTR.BIT.CST3 = 1; /* TCNT3 START */ MTU.TSTR.BIT.CST4 = 1; /* TCNT4 START */ sectionInit(); /* メモリ初期化 */ main(); /* メイン関数呼び出し */ } /* MAIN関数 ************************/ int main(void){ while(1){ /* とりあえず何もしない */ } return 0; } /************************************/ /* セクション初期化 */ /************************************/ extern char etext, sdata, edata, bss_start, end; void sectionInit(void){ char *src; char *dst; /* 初期化データ領域 */ src = &etext; dst = &sdata; while (dst < &edata) { *dst++ = *src++; } /* 未初期化データ領域 */ for ( dst = &bss_start; dst < &end; dst++ ) { *dst = 0; } } |
214−3.プログラムの説明
ちょっと見た感じは長めのプログラムで、特にイニシャル処理部分が長いのですが、良く見てみるとチャンネルの数だけ同じようなことをしているだけなのでたいしたことありません。
主要なレジスタの設定などは、前回の213.モード1による8相PWMでご紹介している内容と重複しますが、再びここでも掲載することにします。同じことを書いている部分も多いのですが、お許し下さい。m(_ _;m
■インクルードと使用関数の型宣言
#include
"sh7040s.h"
void boot(void);
void __main(void);
int main(void);
void sectionInit(void);
お馴染みSH7040S.Hヘッダファイルの読み込み指定と、使用する関数の型宣言です。
■ダミー関数を置く
void
__main(void){
}
すみません。ここは、こういうものだと思って置いてください。
■PFC(ピンファンクションコントローラ)の設定その1
boot( )関数の中身です。SH2が起動すると、一番はじめにこのboot( )関数が実行されるようにしています。 PFCの設定についてはの210.SH2先ずはPIOから(SH2-7045F)の解説を参照してください。
/* IOポート設定 */
PFC.PACRH.WORD = 0x0000; /* PA23〜16 */
PFC.PACRL1.WORD = 0x0000; /* PA15〜8 */
PFC.PACRL2.WORD = 0x0145; /* PA7,6,5,2 TXD0,RXD0 */
PFC.PBCR1.WORD = 0x0000; /* PB9,PB8 */
PFC.PBCR2.WORD = 0x0000; /* PB7〜PB0 */
PFC.PCCR.WORD = 0x0000; /* PC15〜PC0 */
PFC.PDCRH1.WORD = 0x0000; /* PD31〜PD24 */
PFC.PDCRH2.WORD = 0x0000; /* PD23〜PD16 */
PFC.PDCRL.WORD = 0x0000; /* PD15〜PD0 */
PFC.PECR1.WORD = 0x5555; /* TIOC4D,4C,4B,4A,3D,3C,3B,3A */
PFC.PECR2.WORD = 0x5555; /* TIOC2B,2A,1B,1A,0D,0C,0B,0A */
今回のプログラムで必要なPFC設定はポートEの設定だけで、上記では下から2行分だけです。それ以外の設定は特に記入する必要ありませんが、好みで載せてあります。
PWM信号の出力端子は、PIOのポートEと兼用になっているため、上記の2行分でMTU用の端子TIOCとして利用できように設定しています。PECR1(ポートEコントロールレジスタ1)とPECR2はそれぞれ16ビットのレジスタで、以下の意味があります。
PECR1(ポートEコントロールレジスタ1)
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
PE15 MD1 |
PE15 MD0 |
PE14 MD1 |
PE14 MD0 |
PE13 MD1 |
PE13 MD0 |
- |
PE12 MD |
- |
PE11 MD |
- |
PE10 MD |
- |
PE9 MD |
- |
PE8 MD |
PECR2(ポートEコントロールレジスタ2)
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | |
|
- |
PE7 MD |
- |
PE6 MD |
- |
PE5 MD |
- |
PE4 MD |
PE3 MD1 |
PE3 MD0 |
PE2 MD1 |
PE2 MD0 |
PE1 MD1 |
PE1 MD0 |
PE0 MD1 |
PE0 MD0 |
ポートEの16ビット分の用途を、コントロールレジスタの2ビットずつで指定します。MD1とMD0の2ビット分が用意されているところと、予約ビット「-」とMDの2ビット分で構成されるところの2種類があります。
MD1とMD0が用意されているビットについては、以下のような指定を行います。
| MD1 | MD0 | 説明 |
| 0 | 0 | 汎用入出力(ポートE) |
| 1 | MTUインプットキャプチャ入力/アウトプットコンペアマッチ出力 | |
| 1 | 0 | 端子によって用途が異なる(ハードウエアマニュアル参照) |
| 1 | 端子によって用途が異なる(ハードウエアマニュアル参照) |
予約ビットとMDが用意されているビットについては、以下のような指定を行います。
| - | MD | 説明 |
| 0 | 0 | 汎用入出力(ポートE) |
| 1 | MTUインプットキャプチャ入力/アウトプットコンペアマッチ出力 |
ところで、今回PWM出力を行う端子は、PE0,2,4,6,8,10,12,14に相当する端子のみですが、それ以外のPE1,3,5,7,9,11,13,15についても、MTU用の端子に設定しておくことにします。
したがって、各端子をMTU用に設定するには01 01 01 01 (0x5555)にするということになります。なので、
PFC.PECR1.WORD = 0x5555;
PFC.PECR2.WORD = 0x5555;
としています。
■PFC(ピンファンクションコントローラ)の設定その2
上記の設定では端子の用途を設定しましたが、今度は端子の入出力方向を設定します。
PFC.PAIORH.WORD = 0x00ff; /* [OUT]PA23〜16 [IN]-- */
PFC.PAIORL.WORD = 0xffff; /* [OUT]PA15〜0 [IN]-- */
PFC.PBIOR.WORD = 0x03ff; /* [OUT]PB7 〜0 [IN]-- */
PFC.PCIOR.WORD = 0xffff; /* [OUT]PC15〜0 [IN]-- */
PFC.PDIORH.WORD = 0x00ff; /* [OUT]PD23〜16 [IN]PD31〜24 */
PFC.PDIORL.WORD = 0xffff;
/* [OUT]PD15〜0 [IN]-- */
PFC.PEIOR.WORD = 0xffff; /* [OUT]PE15〜0 [IN]-- */
今回のプログラムではポートEの部分だけの設定が必要で、それ以外は特に必要ありませんが、やはり好みで載せてあります。
PEIOR(ポートE I/Oレジスタ)には以下の意味があります。
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
PE15 IOR |
PE14 IOR |
PE13 IOR |
PE12 IOR |
PE11 IOR |
PE10 IOR |
PE9 IOR |
PE8 IOR |
PE7 IOR |
PE6 IOR |
PE5 IOR |
PE4 IOR |
PE3 IOR |
PE2 IOR |
PE1 IOR |
PE0 IOR |
レジスタの各ビットがポートEの各ビットに相当し、「1」なら出力、「0」なら入力の設定となります。今回、各ポートはMTU用のTIOCに設定してあるので、出力ならアウトプットコンペアマッチ出力端子、入力ならインプットキャプチャ入力端子として働きます。今回はPWM波形を出力したいので、アウトプットコンペアマッチ出力とするために、全てのビットに「1」をセットします。したがって、PFC.PEIOR.WORD = 0xffff;とします。
■MTUのタイマシンクロの設定
/* タイマシンクロ設定 */
MTU.TSYR.BYTE = 0x47; /* TCNT0〜3 同期クリア*/
今回のモード2のPWM動作では、TGR3Aのジェネラルレジスタに同期してMTU0〜2のTCNTをカウンタクリアします。したがって、連動する必要のあるMTUを、このTSYR(タイマシンクロレジスタ)で設定してあげます。
TSYRには以下の意味があります。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| SYNC4 | SYNC3 | - | - | - | SYNC2 | SYNC1 | SYNC0 |
SYNC4〜0の各ビットはMTU4〜0の各チャンネルに相当し、お互いに同期動作を行うMTUに相当するビットに1を立ててあげます。今回はMTU3,2,1,0を同期動作させるため、0100 0111をセットします。なので、MTU.TSYR.BYTE = 0x47; としています。
■MTU0チャンネルの設定その1
最初に、MTU0チャンネルのTIOC0A出力端子用のPWM設定を行います。
/* MTU0 TIOC0A PWM MODE 2 設定 */
MTU0.TCR.BYTE = 0x63; /* TCNT SYNC CLEAR,CLOCK/64 */
MTU0.TGRA =
807; /* パルス幅2.23uS x 807 = 1.8mS */
MTU0.TGRB =
671; /* パルス幅2.23uS x 671 = 1.5mS */
MTU0.TIOR.BYTE.H = 0x55; /* 初期 1 , TGR0B → 0 , TGR0A → 0 */
MTU0.TMDR.BYTE = 0xC3; /* PWM MODE2 */
先ず、MTU0チャンネルの動作設定を行います。
MTU0.TCR.BYTE = 0x63; /* TCNT SYNC CLEAR,CLOCK/64 */
では、TCR(タイマーコントロールレジスタ)の設定を行い、タイマーの基本動作の設定を行っています。
TCRは8ビットのレジスタで、以下の意味があります。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| CCLR2 | CCLR1 | CCLR0 | CKEG1 | CKEG0 | TPSC2 | TPSC1 | TPSC0 |
CCLR(カウンタクリア)の3ビットでは、TCNT(タイマカウンタ)のカウンタクリア要因を設定します。
| CCLR2 | CCLR1 | CCLR0 |
説 明 |
| 0 | 0 | 0 | TCNTのクリア禁止 |
| 1 | TGRAのコンペアマッチでTCNTをクリア | ||
| 1 | 0 | TGRBのコンペアマッチでTCNTをクリア | |
| 1 | 同期クリア | ||
| 1 | 0 | 0 | TCNTのクリア禁止 |
| 1 | TGRCのコンペアマッチでTCNTをクリア | ||
| 1 | 0 | TGRDのコンペアマッチでTCNTをクリア | |
| 1 | 同期クリア |
今回は他のMTUのTGRに同期してTCNTのカウントをクリアさせ、PWM波形の周期を決定させたいので(冒頭でご説明した図のような動作を行わせるため)、TCNTのカウンタクリア要因を同期クリアとします。なので、011に設定します。
ここを同期クリアに設定すると、TSYR(タイマシンクロレジスタ)で1が立つMTUの中で、カウンタクリア要因として正式に設定されたTGR(タイマジェネラルレジスタ)に同期して自分のMTUのTCNTをカウンタクリアする動作となります。
CKEG(クロックエッジ)の2ビットでは、TCNTのカウントを行うためのエッジ(入力パルスの立ち上がりタイミングか、立下りタイミングか)を設定します。
| CKEG1 | CKEG0 | 説 明 |
| 0 | 0 | 立ち上がりエッジでカウント |
| 1 | 立ち下りエッジでカウント | |
| 1 | X | 両エッジでカウント |
今回は立ち上がりエッジでカウントさせることにします。なので00に設定します。ちなみに、両エッジでカウントさせると、倍の早さでカウント動作が行われることになります。
TPSC(タイマプリスケーラ)の3ビットでは、TCNTのカウンタクロックを設定します。
| TPSC2 | TPSC1 | TPSC0 | 説 明 |
| 0 | 0 | 0 | 内部クロック φ/1でカウント |
| 1 | 内部クロック φ/4でカウント | ||
| 1 | 0 | 内部クロック φ/16でカウント | |
| 1 | 内部クロック φ/64でカウント | ||
| 1 | 0 | 0 | 外部クロック TCLKA端子入力でカウント |
| 1 | 外部クロック TCLKB端子入力でカウント | ||
| 1 | 0 | 外部クロック TCLKC端子入力でカウント | |
| 1 | 外部クロック TCLKD端子入力でカウント |
今回は内部クロックφ/64でカウントさせますので、011に設定します。なお、φはシステムクロック周波数で、アルファプロジェクト製AP-SH2F-0AでCPUを4倍速の設定で動作させる場合は、28.63636MHzとなります。今回はこの1/64の速度で動作させることになるため、28.63636MHz/64 = 0.447443MHz つまり、TCNTは2.23μS周期でカウントされることになります。
以上の設定をまとめると、以下のようになります。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| CCLR2 | CCLR1 | CCLR0 | CKEG1 | CKEG0 | TPSC2 | TPSC1 | TPSC0 |
| 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
なので、0110 0011 で0x63となり、MTU0.TCR.BYTE = 0x63; となります。
次に、TGRAとTGRBの設定を行います。
MTU0.TGRA =
807; /* パルス幅2.23uS x 807 = 1.8mS */
MTU0.TGRB =
671; /* パルス幅2.23uS x 671 = 1.5mS */
今回、PWMの周期は別のMTU(TGR3A)で設定するため、ここでは2チャンネル分の必要なパルス幅だけを設定します。出力パルスの幅をサーボモータのほぼ動作中間点の1.5mSと、ちょっと回転した1.8mSにしてみようと思うので、1.5mS/2.23μS=671カウントと1.8mS/2.23μS=807カウントから、MTU0.TGRA = 807;とMTU0.TGRB = 671; としてみます。
次に、TIOR(タイマーI/Oコントロールレジスタ)で、出力端子の動作を設定します。
MTU0.TIOR.BYTE.H = 0x55; /* 初期 1 , TGR0B → 0 , TGR0A → 0 */
チャンネル0のTIORは8ビットのレジスタTIOR0HとTIOR0Lが2個あり、それぞれTGRA/TGRBとTGRC/TGRDの設定を行います。ここではTGRA/TGRBの設定を行うため、TIOR0Hについて設定を行います。
TIOR0Hには、以下の意味があります。なお、インプットキャプチャ動作時の設定については表記を省略させて頂きます。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| IOB3 | IOB2 | IOB1 | IOB0 | IOA3 | IOA2 | IOA1 | IOA0 |
TGR0Bに関する設定
|
IOB3 |
IOB2 |
IOB1 |
IOB0 |
機 能 |
||
|
0
|
0
|
0
|
0 |
TGR0Bは アウトプットコンペアマッチレジスタ
|
出力禁止 |
|
|
1 |
初期出力は 0出力
|
コンペアマッチで0出力 |
||||
|
1
|
0 |
コンペアマッチで1出力 |
||||
|
1 |
コンペアマッチでトグル出力 |
|||||
|
1
|
0
|
0 |
出力禁止 |
|||
|
1 |
初期出力は 1出力
|
コンペアマッチで0出力 |
||||
|
1
|
0 |
コンペアマッチで1出力 |
||||
|
1 |
コンペアマッチでトグル出力 |
|||||
ここではTGRBがコンペアマッチしたときの出力端子の変化を設定します。
今回のPWM動作では、TCNTでのカウント値がTGRBに設定した値と一致した(コンペアマッチした)ことによって出力端子TIOC0Aを0にしたいので、「初期出力は1出力」「コンペアマッチで0出力」となる設定の0101にします。冒頭の出力波形の例その2を参照して下さい。
なお、「初期出力」とはハードウエアマニュアルに明確な記載がないのですが(あるかもしれませんが...)、カウンタクリアされた時の出力状態を示すみたいです。今回はカウンタクリアされて次の周期になった時点で出力を1にしたいため、「初期出力は1出力」に設定します。ちなみに「初期出力は0出力」に設定するとPWM波形は出力されません。このあたりは、モード1の時の意味合いと異なるようなので注意してください。
TGR0Aに関する設定
|
IOA3 |
IOA2 |
IOA1 |
IOA0 |
機 能 |
||
|
0
|
0
|
0
|
0 |
TGR0Aは アウトプットコンペアマッチレジスタ
|
出力禁止 |
|
|
1 |
初期出力は 0出力
|
コンペアマッチで0出力 |
||||
|
1
|
0 |
コンペアマッチで1出力 |
||||
|
1 |
コンペアマッチでトグル出力 |
|||||
|
1
|
0
|
0 |
出力禁止 |
|||
|
1 |
初期出力は 1出力
|
コンペアマッチで0出力 |
||||
|
1
|
0 |
コンペアマッチで1出力 |
||||
|
1 |
コンペアマッチでトグル出力 |
|||||
ここではTGRAがコンペアマッチしたときの出力端子の変化を設定します。
ここはTGRBと同じ動作をさせたいので、前項にならって0101にします。
以上の設定を整理すると、以下のようになります。
TIOR0H
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| IOB3 | IOB2 | IOB1 | IOB0 | IOA3 | IOA2 | IOA1 | IOA0 |
| 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
なので、MTU0.TIOR.BYTE.H = 0x55; としています。
MTUの設定の最後として、TMDR(タイマーモードレジスタ)の設定を行います。
MTU0.TMDR.BYTE = 0xC3; /* PWM MODE2 */
TMDRはMTUとしての動作のモードを選択する、8ビットのレジスタです。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| - | - | BFB | BFA | MD3 | MD2 | MD1 | MD0 |
BFB(バッファ動作B)とBFA(バッファ動作A)については今回利用しませんので、別の機会にご紹介します。BIT7,6は予約ビットで初期値1がセットされます。
MD3〜0は以下の意味があります。
| MD3 | MD2 | MD1 | MD0 | 説 明 |
| 0 | 0 | 0 | 0 | 通常動作 |
| 1 | 予約(設定禁止) | |||
| 1 | 0 | PWMモード1 | ||
| 1 | PWMモード2 | |||
| 1 | 0 | 0 | 位相計測モード1 | |
| 1 | 位相計測モード2 | |||
| 1 | 0 | 位相計測モード3 | ||
| 1 | 位相計測モード4 | |||
| 1 | 0 | 0 | 0 | リセット同期PWMモード |
| 1 | 予約(設定禁止) | |||
| 1 | 0 | 予約(設定禁止) | ||
| 1 | 予約(設定禁止) | |||
| 1 | 0 | 0 | 予約(設定禁止) | |
| 1 | 相補PWMモード1(山で転送) | |||
| 1 | 0 | 相補PWMモード2(谷で転送) | ||
| 1 | 相補PWMモード3(山・谷で転送) |
今回はPWMモード1で動作させたいので、0011とします。
以上の設定を整理すると、TMDRは以下のようになります。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| - | - | BFB | BFA | MD3 | MD2 | MD1 | MD0 |
| 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
なので、MTU0.TMDR.BYTE = 0xC3; とします。
■MTU0チャンネルの設定その1
次に、MTU0チャンネルのTIOC0C出力端子用のPWM設定を行います。
/* MTU0 TIOC0C PWM MODE 2 設定 */
MTU0.TGRC =
898;
/* パルス幅2.23uS x 898 = 2.0mS */
MTU0.TGRD =
807;
/* パルス幅2.23uS x 807 = 1.8mS */
MTU0.TIOR.BYTE.L = 0x55;
/* 初期 1 , TGR0D → 0 , TGR0C → 0 */
今まではTGRAとTGRBのジェネラルレジスタについての動作を設定してきましたが、ここではTGRCとTGRDについての動作を設定して、TIOC0CとTIOC0Dの出力端子からのPWM波形を決定させます。
ただし、すでにTCR(タイマーコントロールレジスタ)とTMDR(タイマーモードレジスタ)の設定は済んでいるので、その環境のもとでTGRCとTGRDの設定を行うだけです。ここでは細かな解説は省略します。前項までの解説をご参照ください。
■MTU1,2チャンネルの設定
次に、MTU1,2チャンネルについての設定を行っていますが、基本的にはチャンネル0と一緒なので省略させて頂きます。ただし、MTU1,2チャンネルにはTGRC/Dがないため、それらに起因するレジスタ設定項目などに若干の違いがあります。詳しくは「SH7040シリーズハードウエアマニュアル」を紐解いてみてください。
■MTU3チャンネルの設定
MTU3チャンネルはモード1の設定とします。(モード2にはできません) モード1での設定については213.モード1による8相PWMのページを参照して下さい。ただし今回のプログラムでは、MTU3のカウンタクリア要因(TGR3A)が、MTU0〜2のTCNTのカウンタクリア要因として利用されますので、特別な意味を持つことになります。それ以外は普通のモード1の設定です。
/* MTU3 TIOC3A PWM MODE 1 設定 */
MTU3.TCR.BYTE = 0x23;
/* TGR3A TCNT CLEAR,CLOCK/64 */
MTU3.TGRA = 8948;
/* 周期2.23uS x 8948 = 20mS */
MTU3.TGRB =
671;
/* パルス幅2.23uS x 671 = 1.5mS */
MTU3.TIOR.BYTE.H = 0x56;
/* TGR3B → 0 , TGR3A → 1 */
MTU3.TMDR.BYTE = 0xC2;
/* PWM MODE1 */
/* MTU3 TIOC3C PWM MODE 1 設定 */
MTU3.TGRC = 8948;
/* 周期2.23uS x 8948 = 20mS */
MTU3.TGRD =
807;
/* パルス幅2.23uS x 807 = 1.8mS */
MTU3.TIOR.BYTE.L = 0x56;
/* TGR3D → 0 , TGR3C → 1 */
■MTU4チャンネルの設定
MTU4チャンネルもモード1の設定です。(モード2にはできません) 設定方法の詳細はMTU3と同様です。今回、MTU4は他のMTUと同期クリア動作をさせるようにしていないため、カウンタクリア要因はTGR4Aのコンペアマッチにしてあります。
/* MTU4 TIOC4A PWM MODE 1 設定 */
MTU4.TCR.BYTE = 0x23;
/* TIOC4A TCNT CLEAR,CLOCK/64 */
MTU4.TGRA = 8948;
/* 周期2.23uS x 8948 = 20mS */
MTU4.TGRB =
671;
/* パルス幅2.23uS x 671 = 1.5mS */
PWM.TOER.BIT.OE4A = 1;
/* TIOC4A OUTPUT ENABLE */
MTU4.TIOR.BYTE.H = 0x56;
/* TGR4B → 0 , TGR4A → 1 */
MTU4.TMDR.BYTE = 0xC2;
/* PWM MODE1 */
/* MTU4 TIOC4C PWM MODE 1 設定 */
MTU4.TGRC = 8948;
/* 周期2.23uS x 8948 = 20mS */
MTU4.TGRD =
807;
/* パルス幅2.23uS x 807 = 1.8mS */
PWM.TOER.BIT.OE4C = 1;
/* TIOC4C OUTPUT ENABLE */
MTU4.TIOR.BYTE.L = 0x56;
/* TGR4D → 0 , TGR4C → 1 */
ここでひとつだけ...重要。
PWM.TOER.BIT.OE4A = 1; /* TIOC4A OUTPUT ENABLE */
PWM.TOER.BIT.OE4C = 1; /* TIOC4C OUTPUT ENABLE */
MTU4チャンネルの出力TIOC4AとTIOC4Cは、そのままだと信号が出力されません。TOER(タイマアウトプットマスタイネーブルレジスタ)に、出力許可の指定をする必要があります。
TOERの意味は以下の通りです。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| - | - | OE4D | OE4C | OE3D | OE4B | OE4A | OE3B |
それぞれのビット名称の「OE」を「TIOC」に置き換えた出力端子について、許可したい出力に相当するビットに1を立てます。これをしないと、正しくPWM波形が出力されないので注意してください。
■カウントスタート
一連の設定が終わったら、カウントをスタートさせてPWM波形を出力させてみます。
/* TCNT0,1,2,3,4 START */
MTU.TSTR.BIT.CST0 = 1; /* TCNT0 START */
MTU.TSTR.BIT.CST1 = 1; /* TCNT1 START */
MTU.TSTR.BIT.CST2 = 1; /* TCNT2 START */
MTU.TSTR.BIT.CST3 = 1; /* TCNT3 START */
MTU.TSTR.BIT.CST4 = 1; /* TCNT4 START */
タイマーのカウントをスタートさせるには、TSTR(タイマースタートレジスタ)の中のチャンネルに相当するビットに1を立てます。
TSTRには以下の意味があります。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| CST4 | CST3 | - | - | - | CST2 | CST1 | CST0 |
CST4〜CST0が、それぞれMTU4〜0チャンネルのTCNT(タイマーカウンタ)に相当します。なので、上記ソースコードのようにビットごとに1をセットしても、MTU.TSTR.BYTE = 0xC7; とバイト単位で書き込みを行ってもかまいません。
これで、各出力端子からPWM波形が発生します。
■メイン関数 main( )
今回の例では、メイン関数では何もしていません。手抜きですみません。
int main(void){
while(1){
/* とりあえず、なにもしない */
}
return 0;
}
boot関数内で設定したイニシャル処理にしたがって、固定の周期/パルス幅でPWM波形を出力し続けます。なので、メイン関数内で、各MTUのTGRBもしくはTGRDを書き換える処理を行えば、PWM波形のパルス幅を制御することができ、サーボモータの首振りをコントロールできます。
今回の、前回にましてダラダラとした記事になってしまってすみません。読んでいるうちに的が絞れなくなってしまうと思いますが、お許しください。m(_ _;m
やはりここでも、PWM動作の設定で一番よく分からないところは、TIOR(タイマI/Oコントロールレジスタ)をどうしたら良いかというところではないでしょうか?どうやらモード1の時の設定と意味合いが変わるような感じですが、詳しいところが良く見えません。一応、記事でご紹介しているプログラムの設定では正常に動作しますので、ご安心を。
大分省略して書いたところもありますので、やはりハードウエアマニュアルを片手に持ちながらパソコンに向かわないと分からないと思います。(^^;
PWMが12相出力できると、とりあえずロボットの両足腰分で必要な関節をカバーできます。それ以上のチャンネル数が必要になると思いますが、ひとまず歩行のための実験は進められますよ。