214.モード2による12相PWM(SH2-7045F)


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に対応しているため、各MTUTGRごとにPWM波形を発生させることができます。なので、全部で12相のPWM波形を出力できます。

モード1では各MTUごとにTCNT(タイマーカウンタ)のカウンタクリア要因を用意してあげなければなりませんでした。しかし、モード2では各MTUTCNTのカウンタクリア要因を、どこかのMTUTGRに指定することができます。したがって、各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の他に、TCNT1TCNT2のカウンタクリア要因として全てにTGR3Aを指定することによって、TGR1A,BTGR2A,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ビットずつで指定します。MD1MD0の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〜2TCNTをカウンタクリアします。したがって、連動する必要のある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 同期クリア

今回は他のMTUTGRに同期してTCNTのカウントをクリアさせ、PWM波形の周期を決定させたいので(冒頭でご説明した図のような動作を行わせるため)、TCNTのカウンタクリア要因を同期クリアとします。なので、011に設定します。

ここを同期クリアに設定すると、TSYR(タイマシンクロレジスタ)で1が立つMTUの中で、カウンタクリア要因として正式に設定されたTGR(タイマジェネラルレジスタ)に同期して自分のMTUTCNTをカウンタクリアする動作となります。

 

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 つまり、TCNT2.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 00110x63となり、MTU0.TCR.BYTE = 0x63; となります。

 

次に、TGRATGRBの設定を行います。

     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 */

チャンネル0TIORは8ビットのレジスタTIOR0HTIOR0Lが2個あり、それぞれTGRA/TGRBTGRC/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にしたいので、「初期出力は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 */

 

TMDRMTUとしての動作のモードを選択する、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 */

今まではTGRATGRBのジェネラルレジスタについての動作を設定してきましたが、ここではTGRCTGRDについての動作を設定して、TIOC0CTIOC0Dの出力端子からのPWM波形を決定させます。

ただし、すでにTCR(タイマーコントロールレジスタ)とTMDR(タイマーモードレジスタ)の設定は済んでいるので、その環境のもとでTGRCTGRDの設定を行うだけです。ここでは細かな解説は省略します。前項までの解説をご参照ください。

【先頭に戻る】

■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チャンネルの出力TIOC4ATIOC4Cは、そのままだと信号が出力されません。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波形を出力し続けます。なので、メイン関数内で、各MTUTGRBもしくはTGRDを書き換える処理を行えば、PWM波形のパルス幅を制御することができ、サーボモータの首振りをコントロールできます。

【先頭に戻る】


今回の、前回にましてダラダラとした記事になってしまってすみません。読んでいるうちに的が絞れなくなってしまうと思いますが、お許しください。m(_ _;m

やはりここでも、PWM動作の設定で一番よく分からないところは、TIOR(タイマI/Oコントロールレジスタ)をどうしたら良いかというところではないでしょうか?どうやらモード1の時の設定と意味合いが変わるような感じですが、詳しいところが良く見えません。一応、記事でご紹介しているプログラムの設定では正常に動作しますので、ご安心を。

大分省略して書いたところもありますので、やはりハードウエアマニュアルを片手に持ちながらパソコンに向かわないと分からないと思います。(^^;

PWMが12相出力できると、とりあえずロボットの両足腰分で必要な関節をカバーできます。それ以上のチャンネル数が必要になると思いますが、ひとまず歩行のための実験は進められますよ。

 

【ソフトウエア編TOPに戻る】


【表紙に戻る】