MSP430開発入門講座(4) PWM
今回のソース
PWM(Pulse Width Modulation)という手法でLEDの明るさを変えてみます。 今回使うPWMは一番単純に、一周期中に1個の矩形波があって、そのデューティ比を 変えるタイプです。PWMはLEDの他にもDCモータの速度を制御するときなどにも 使えます。 PWMを発生する際は、時間を測って(タイマ割り込みで)ソフトウェアでon/offしても いいのですが、MSP430をはじめ ほとんどのマイコンのタイマには勝手に出力ピンをon/offしてくれる機能が ついています (LaunchPad もそれを前提として設計されてるフシがあります) 。せっかくなので今回はこっちの機能を使ってみましょう。
// tutorial03.c by Yagshi 2011
#include <io.h>
#define kPeriod 0xff // 12000 / 256 = 46.875 [Hz]
#define kInitialDuty 0x07 // 0-0x07: on, 0x08-0xff: off
void initializeMCU(void)
{
WDTCTL = WDTPW + WDTHOLD; // shut up the dog
BCSCTL3 |= LFXT1S_2; // Select VLO for ACLK
// setup PORT1
P1SEL |= BIT6;
P1DIR |= BIT6;
// setup TIMER_A
TACTL = TASSEL__ACLK + ID_0 + MC__UP;
TACCR0 = kPeriod;
TACCR1 = kInitialDuty;
TACCTL1 = OUTMOD_6; // toggle/set mode
}
int main(void)
{
initializeMCU();
for(;;) _BIS_SR(SCG1 | SCG0 | CPUOFF); // goes into LPM3
return 0;
}
タイマのお約束2機能
そもそもタイマ(timer)とは
タイマというと、なんとなくカウントダウンしてある時間たったらアラームが なるみたいなそんなイメージがありますが、マイコンのタイマの場合、 一般には『放っておいても勝手にアップ(ダウン)してくれるカウンタ』のことを 指します。そういう意味では 時計やストップウォッチみたいなもの と 思った方が誤解が少ないかもしれません。 とはいっても単なる自動カウンタだけではあまりにショボいので、ふつうは 『キャプチャ』と『コンペア』 という二つの機能が最低でももれなくついてくると 思って間違いないです。 『コンペア』機能を使うと上述のようないわゆる日常用語としてのタイマぽい ことができるようになります。
MSP430には 第1回 で紹介したWatchdogタイマを別にすれば) Timer_AとTimer_Bという二つのタイマがありますが、G2ファミリには Timer_Bは今のところなさそうなので気にしないことにしましょう。ちなみに Timer_Bの方が若干高機能です。
キャプチャ(capture)(TACCTLx.CAP=1)
時計で言えばストップウォッチ。
外部ピンなどの状態変化が生じたときのタイマの値をキャプチャする機能です。
時間計測などに使えます。MSP430の場合は、TACCRxレジスタに
記録されます。
コンペア(compare)(TACCTLx.CAP=0)
時計で言えば目覚まし(=アラーム)。
あらかじめレジスタ
(MSP430の場合はTACCRxレジスタ)にセットした値と現在のタイマ値を
比較し、
一致したらあるアクションを起こします。具体的には次のようなアクションです
(両方同時に実行することもできます)。
- 割り込みをかける → 次回は この機能で LED を点滅させます。
- 事前に設定した出力ピンの値を事前に設定したルールに基づいて制御する → 今回はこの機能で PWM を実現します。
Timer_A のクロック設定(TACTLレジスタ→TASSELx/IDxビットフィールド
Timer_A のクロック源はTACKL, ACLK, SMCLK, INCLKの4つで、これを設定
するのがTACTLレジスタのTASSELxビットフィールド
(2bit)です。4つのクロック源のうち ACLK, SMCLK は
別ページで解説してあるとおりです。
残りの2つ、TACLK, INCLKは外部ピンから入力するTimer_A 専用の
クロック源のようです。それぞれのクロック源はTACTLレジスタの
IDxビットフィールドを使って、1, 2, 4, 8分周可能です。
Timer_A の4つの動作モード(TACTLレジスタ→MCxビットフィールド)
Timer_A は 16 ビットのカウンタで、 Up, Continuous, Up/down の3つのTimer Modeがあります。簡単に説明すると…
- Upモード:
スタート後、上限値(TACCR0レジスタの値)までカウントアップし、0に戻り 再びカウントアップ。 - Continuousモード:
スタート後、上限値(0xffff)までカウントアップし、0に戻り 再びカウントアップ。 - Up/downモード:
スタート後、上限値(TACCR0レジスタの値)までカウントアップしたら 今度は0までカウントダウンし、再びカウントアップ…を繰り返す。 となります。
TACTLレジスタのMCx
という2ビットのビットフィールドです
MSP430x2xx Family User’s Guide
の12.3 節あたり参照)。
ソース中では以下の1文で
MC__UPという定数を使って Up モードを指定しています。
キャプチャ・コンペアレジスタ(TACCRx)
出力設定(Output unit)
さぁ、ここが今回の一番ややこしいところです。MSP430の中でも比較的 自由度が低いところなので、良く考えてハードウェアの設計をしないと 後から困ります。 MSP430固有と感じた注意点を以下にまとめます。
-
キャプチャ・コンペアレジスタ
TACCR0だけは特別。
一見直交性がありそうなネーミングのTACCRxですが、 0とそれ以外は全然違います。上図にも示したとおり、0だけが タイマの上限値を設定可能です。まずはこれを押さえておきましょう。 -
キャプチャ・コンペアレジスタ(
TACCRx)毎に出力ピンが決まっている。
文字通りですが、Output unit でPWMを作ろう、などというときに適当に 配線してあとはソフトウェアで…ということはできません。TACCR0はこのピン、TACCR1はこのピン、という ようにハードウェアで決められています。さらに前項で書いたとおり、TACCR0だけは特別なのでOutput としての機能が限られてきます。 平たく言うと、xが1以上のTACCRxに対応したピンは 高機能で嬉しいと言えると思います。 -
MSP430G2ファミリの
TACCRxは本数が少ない(x=0, 1 あるいはせいぜい2)。
前項に従えば、xがたくさん選べればそれだけ嬉しいのですが、残念ながら MSP430G2ファミリではx=2が最大のようです。 さらにLaunchPadのに付属のデバイスは両方とも x は1まででした。 xが1までだと、独立したPWMが1本しか作れません。 (まったく同じ波形でいいなら、同時に複数のピンから出せそうですが。) したがって、どうしても2本以上のPWMが欲しければ ソフトで何とかするしかないです。