213.モード1による8相PWM(SH2-7045F)


2002/9/29 【ソフトウエア編TOPに戻る】

今回は、MTU(マルチファンクションタイマーユニット)を使って8相のPWM波形を出力させるプログラムをご紹介します。PWMについては、106.PWMでモータ制御112.ラジコンサーボモータを動かすのページなどをご参照下さい。


213−1.モード1によるPWM

SH2-7045Fには0〜4まで5チャンネル分のMTUがあり、チャンネル0、3、4にはそれぞれ4個ずつ、チャンネル1、2にはそれぞれ2個ずつのTGR(タイマージェネラルレジスタ)があります。モード1での各チャンネルの主要なレジスタと出力端子の構成は以下のようになっています。

チャンネル タイマカウンタ ジェネラルレジスタ PWM出力端子
MTU0 TCNT0 TGR0A

TIOC0A

(PE0と共用)

TGR0B
TGR0C

TIOC0C

(PE2と共用)

TGR0D
MTU1 TCNT1 TGR1A

TIOC1A

(PE4と共用)

TGR1B
MTU2 TCNT2 TGR2A

TIOC2A

(PE6と共用)

TGR2B
MTU3 TCNT3 TGR3A

TIOC3A

(PE8と共用)

TGR3B
TGR3C

TIOC3C

(PE10と共用)

TGR3D
MTU4 TCNT4 TGR4A

TIOC4A

 (PE12と共用)

TGR4B
TGR4C

TIOC4C

(PE14と共用)

TGR4D

■出力波形の例その1

左の図は、PWM波形を発生させるための動作の一例です。

PWM波形のパルス幅と周期はTRG(ジェネラルレジスタ)のA,BC,Dのペアによって左図のように決定されます。(左図ではA,Bの例)

ただし、左図の場合はTGRBに設定した値の大きさとパルス幅の大きさが反比例するため直感的ではありません。

■出力波形の例その2

そこで、左図のような動作をさせることとします。

良く見ると出力パルスの波形が反転しているだけですが、これによってTGRBに設定した値の大きさとパルス幅の大きさが比例するため、直感的に分かりやすくなります。

PWM波形の周期に変化はありません。

 

上図の例で考えると、TCNTのカウントアップのクロック周期とTGRAに設定する値でPWM波形の周期が決定され、TGRBに設定する値でパルス幅が決定されることが分かります。これはTGRCTGRDの組み合わせでも同様です。 TCNTのカウントアップのクロック周期とカウンタクリア条件はチャンネルごとにTCR(タイマーコントロールレジスタ)で設定できますので、チャンネルごとならば独立して周期などを設定することが可能ということになります。

以上はモード1でのPWM動作で、TGRのペアの数である8相までのPWM波形を出力させることができます。この他にモード2のPWM動作というものもあり、それを利用すると全部で12相のPWM波形に対応させることができます。モード2については次の機会にご紹介するとして、先ずはモード1のプログラミングについてご紹介することにしましょう。


213−2.モード1によるPWMプログラミング pwmtest1.c

 

以下に示すプログラムソースは、8チャンネル分のPWM波形を固定で出力する、もっとも単純な事例です。main関数でそれぞれのTGRBTGRDを操作する処理を入れれば、サーボモータの角度制御やDCモータの速度制御が出来るようになりますが、ここでは先ずPWM波形を出力させるための設定を中心にご紹介します。

プログラムはここをクリックするとダウンロードできますpwmtest1.c また、割込みベクタファイルもここをクリックするとダウンロードできますvector.s 今回のプログラムでは、特に割り込みは利用していません。

/*************************************
pwmtest1.c                                 2002.06.7
                                                   RIKIYA
                                              SH2_7045F
PWM MODE 1による8相PWM出力
TIOC0A,0C
TIOC1A
TIOC2A
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]-- */

/* MTU0 TIOC0A PWM MODE 1 設定 */
     MTU0.TCR.BYTE = 0x23;           /* TGR0A TCNT CLEAR,CLOCK/64 */
     MTU0.TGRA = 8948;                 /* 周期2.23uS x 8948 = 20mS */
     MTU0.TGRB = 671;                  /* パルス幅2.23uS x 671 = 1.5mS */
     MTU0.TIOR.BYTE.H = 0x56;       /* TCR0B → 0 , TGR0A → 1 */
     MTU0.TMDR.BYTE = 0xC2;        /* PWM MODE1 */

/* MTU0 TIOC0C PWM MODE 1 設定 */
     MTU0.TGRC = 8948;               /* 周期2.23uS x 8948 = 20mS */
     MTU0.TGRD = 807;                 /* パルス幅2.23uS x 807 = 1.8mS */
     MTU0.TIOR.BYTE.L = 0x56;      /* TCR0D → 0 , TGR0C → 1 */

/* MTU1 TIOC1A PWM MODE 1 設定 */
     MTU1.TCR.BYTE = 0x23;         /* TGR1A TCNT CLEAR,CLOCK/64 */
     MTU1.TGRA = 8948;               /* 周期2.23uS x 8948 = 20mS */
     MTU1.TGRB = 671;                /* パルス幅2.23uS x 671 = 1.5mS */
     MTU1.TIOR.BYTE = 0x56;        /* TCR1B → 0 , TGR1A → 1 */
     MTU1.TMDR.BYTE = 0xC2;      /* PWM MODE1 */

/* MTU2 TIOC2A PWM MODE 1 設定 */
     MTU2.TCR.BYTE = 0x23;        /* TGR2A TCNT CLEAR,CLOCK/64 */
     MTU2.TGRA = 8948;              /* 周期2.23uS x 8948 = 20mS */
     MTU2.TGRB = 895;               /* パルス幅2.23uS x 895 = 2.0mS */
     MTU2.TIOR.BYTE = 0x56;       /* TCR2B → 0 , TGR2A → 1 */
     MTU2.TMDR.BYTE = 0xC2;     /* PWM MODE1 */

/* 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;    /* TCR3B → 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;   /* TCR3D → 0 , TGR3C → 1 */

/* MTU4 TIOC4A PWM MODE 1 設定 */
     MTU4.TCR.BYTE = 0x23;      /* TGR4A 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;  /* TCR4B → 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; /* TCR4D → 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;
     }
}

【先頭に戻る】


213−3.プログラムの説明

ちょっと見た感じは長めのプログラムで、特にイニシャル処理部分が長いのですが、良く見てみるとチャンネルの数だけ同じことをしているだけなのでたいしたことありません。

■インクルードと使用関数の型宣言

#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;とします。

【先頭に戻る】

■MTU0チャンネルの設定その1

最初に、MTU0チャンネルTIOC0A出力端子用のPWM設定を行います。

/* MTU0 TIOC0A PWM MODE 1 設定 */
     MTU0.TCR.BYTE = 0x23;           /* TGR0A TCNT CLEAR,CLOCK/64 */
     MTU0.TGRA = 8948;                 /* 周期2.23uS x 8948 = 20mS */
     MTU0.TGRB = 671;                  /* パルス幅2.23uS x 671 = 1.5mS */
     MTU0.TIOR.BYTE.H = 0x56;       /* TCR0B → 0 , TGR0A → 1 */
     MTU0.TMDR.BYTE = 0xC2;        /* PWM MODE1 */

先ず、MTU0チャンネルの動作設定を行います。

     MTU0.TCR.BYTE = 0x23;           /* TGR0A TCNT 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 同期クリア(別の機会に解説します)

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

 

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 0 1 0 0 0 1 1

なので、0010 00110x23となり、MTU0.TCR.BYTE = 0x23; となります。

 

 

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

     MTU0.TGRA = 8948;                 /* 周期2.23uS x 8948 = 20mS */
     MTU0.TGRB = 671;                  /* パルス幅2.23uS x 671 = 1.5mS */

TGRAではPWM波形の周期を、TGRBでは出力パルスの幅を設定したいと思います。

PWM波形の周期は、サーボモータの制御信号に合わせて20mSにします。先ほどご説明した通り、現在の設定ではTCNTのカウントは2.23μS周期でカウントされるため、20mSをカウントするのに要するカウント数は、20mS/2.23μS=8948カウントとなります。したがって、MTU0.TGRA = 8948;とします。

同様に、出力パルスの幅をサーボモータのほぼ動作中間点の1.5mSとするためには、1.5mS/2.23μS=671カウントとなるので、MTU0.TGRB = 671;とします。

 

 

次に、TIOR(タイマーI/Oコントロールレジスタ)で、出力端子の動作を設定します。

     MTU0.TIOR.BYTE.H = 0x56;       /* TCR0B → 0 , TGR0A → 1 */

チャンネル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を参照して下さい。

なお、「初期出力」とは、ハードウエアマニュアルに明確な記載がないので(あるかも知れませんが...)良くわかりません。MTUが動き出した時の一番最初の出力状態を設定するのかなと思うのですが、今回のPWM波形では、「初期出力は0出力」に設定しても動作には影響ありませんでした。あやふやですみません。おわかりの方お教えください。

 

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がコンペアマッチしたときの出力端子の変化を設定します。

今回のPWM動作では、TCNTでのカウント値がTGRAに設定した値と一致した(コンペアマッチした)ことによって出力端子TIOC0Aにしたいので、「初期出力は1出力」「コンペアマッチで1出力」となる設定の0110にします。冒頭の出力波形の例その2を参照して下さい。

ここでも初期出力を0に設定してもあまり影響ありません。

以上の設定を整理すると、以下のようになります。

TIOR0H

7 6 5 4 3 2 1 0
IOB3 IOB2 IOB1 IOB0 IOA3 IOA2 IOA1 IOA0
0 1 0 1 0 1 1 0

なので、MTU0.TIOR.BYTE.H = 0x56;  としています。

 

 

MTUの設定の最後として、TMDR(タイマーモードレジスタ)の設定を行います。

     MTU0.TMDR.BYTE = 0xC2;        /* PWM MODE1 */

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で動作させたいので、0010とします。

以上の設定を整理すると、TMDRは以下のようになります。

7 6 5 4 3 2 1 0
- - BFB BFA MD3 MD2 MD1 MD0
1 1 0 0 0 0 1 0

なので、MTU0.TMDR.BYTE = 0xC2; とします。

【先頭に戻る】

■MTU0チャンネルの設定その1

次に、MTU0チャンネルTIOC0C出力端子用のPWM設定を行います。

/* MTU0 TIOC0C PWM MODE 1 設定 */
     MTU0.TGRC = 8948;               /* 周期2.23uS x 8948 = 20mS */
     MTU0.TGRD = 807;                 /* パルス幅2.23uS x 807 = 1.8mS */
     MTU0.TIOR.BYTE.L = 0x56;      /* TCR0D → 0 , TGR0C → 1 */

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

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

【先頭に戻る】

■MTU1〜4チャンネルの設定

次に、残りのMTUチャンネル(1〜4)についての設定を行っていますが、基本的にはチャンネル0と一緒なので省略させて頂きます。ただし、チャンネルによって機能に若干の違いがあるため、レジスタで設定できる項目などもちょっと違ったりします。特に、MTU0,3,4MTU1,2に違いがあります。

詳しくは「SH7040シリーズハードウエアマニュアル」を紐解いてみてください。

ひとつだけ...重要。

     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波形のパルス幅を制御することができ、サーボモータの首振りをコントロールできます。

【先頭に戻る】


213−3.TGRA,BとTGRC,Dの関係について補足

 

MTU0,3,4チャンネルについてはPWMモード1の場合、TGRAとTGRBTGRCとTGRDの2ペアを使ってPWM波形をそれぞれ2チャンネルずつ出力させることができます。このとき、タイマー動作の基本となるTCNT(タイマーカウンタ)と、そのカウンタクリア要因については各MTUにひとつしかないため、2ペアの波形出力で共用することになります。

したがって、MTU0チャンネルを例にとると、TIOC0A出力とTIOC0C出力のPWM周期は個別に設定できず共通のものとなります。両出力で個別に設定できるのはパルス幅のみです。

今回のプログラムpwmtest1.cでは、TGRATGRCを両出力の周期を決定させるものとして、同じ値に設定して動作させましたが、これらのレジスタの値を違う数値に設定すると、以下のような動作となります。

左図は、カウンタクリア要因をTGRAのコンペアマッチに設定した場合の例です。

TIOCATGRATGRBのペアによって決定させる出力波形で、標準的な動作です。このとき、TGRCTGRAよりも小さな値とした場合、TGRCTGRDのペアによって出力されるTIOCCのパルス幅については、TGRDで設定した値よりも大きくなります。

逆に、TGRCTGRAよりも大きな値にすると、TGRCによるコンペアマッチが発生しなくなるため、TIOCCからはPWM波形が出力されなくなります。

上記のように、同じMTUチャンネル内でのPWM波形出力は完全に独立したものではないため、注意が必要です。単純に多チャンネルのPWM波形が必要な場合は、TGRAとTGRCを同じ値に設定しておく必要があります。

【先頭に戻る】


今回もダラダラとして説明になってしまい、すみませんでした。m(_ _;m

PWM動作の設定で一番よく分からないところは、TIOR(タイマI/Oコントロールレジスタ)をどうしたら良いかというところではないでしょうか?ハードウエアマニュアルにも、あまり細かな説明が載っていないので、とりあえず色々試してみて動作を掴むといった感じでしたが、TIORの設定がうまく行ってないと、きちんとした波形が出力されないので重要です。それ以外では特に難しい点はないと思います。

今回のモード1の動作では各MTUが独立で動作し、必ず2個のTGRがペアになってPWM波形を決定させるというものでしたが、モード2では複数のMTUTCNTが、あるひとつのTGRをカウンタクリア要因とすることによって、もっと多くのPWM波形を出力させることが可能となっています。

次回はそのモード2でのPWM動作についてご紹介します。

 

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


【表紙に戻る】