続いて割り込み以外のタイマー機能である PWM とエンコーダ読み取りを利用してみたいと思います。やっぱり STM32 に似ているなぁという感想。
ところでこの記事シリーズ、STM32 のときと同様にペリフェラルの説明ばかりになっていますが、このような感じで以後やっていきたいと思います。
エンコーダ
通常の割り込みタイマーの設定にチャネルの設定を加えるだけです。
当然、出力レベルやモードの設定不可欠ですが、チャネル出力有効化をしないとどうやっても波形が観測されないのでご注意ください。
以下にコードを示します。TIME_CAR
はカウントの上限で、自分の使うエンコーダによって都合のいい値を代入するようにしてください。今回は 1024 カウントで1回転するものを用いていますので、0〜1023 をカウントできるように設定しました。
void timer_encoder_init(void) { // PA0, PA1
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1);
rcu_periph_clock_enable(RCU_TIMER1);
TIMER_CAR(TIMER1) = 1024 - 1; // maximum value of counting up
TIMER_SMCFG(TIMER1) = TIMER_ENCODER_MODE0; // encoder mode0
TIMER_CHCTL0(TIMER1) = (TIMER_IC_SELECTION_DIRECTTI << 0) | (TIMER_IC_SELECTION_DIRECTTI << 8);
// input channel n is connected to CInFEn
TIMER_CTL0(TIMER1) = TIMER_CTL0_CEN;
}
uint16_t get_encoder(void) {
return TIMER_CNT(TIMER1);
}
ピン方法接続は使用するエンコーダICによって異なりますが、例えば単純な機械式ロータリーエンコーダの場合は普通に(?)プルアップしておけばいいです。
ユーザーマニュアルを見ていると TIMER_CHCTL0
の記述がソースコードと微妙に一致しておらず不思議です。意味はなんとなく察してくれ 「それマクロが用意されてるなら使ってみるべ」と使ってみましたが、こう出来上がってみると意味がわかりにくく微妙ですね。ですので CHCTL0
では却ってマクロを使わないほうが良いと思いますね。
ちなみにこの部分は TIMER_CHCTL0(TIMER1) = (0b01 << 0) | (0b01 << 8)
という値になります。
CHCTLx
は16bitのレジスタで、上位8ビットと下位8ビットで対応するチャネルが違います。どうやら CTCTL0
のビットマクロは対応する1チャネル分の8ビット分を1まとまりとしてセットしてからシフトするというやり方が正しいのだと思います。
PWM
こちらもチャネルの出力設定をすればいいのです。割と簡単ですね。
void timer_pwm_init(void) { // PA1, no AF remapping needed
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
rcu_periph_clock_enable(RCU_TIMER1);
TIMER_PSC(TIMER1) = 1000 * 108 / 2 - 1; // prescaler
TIMER_CAR(TIMER1) = 1000 * 2 - 1; // maximum value of counting up
TIMER_CH1CV(TIMER1) = 200 * 2 - 1;
TIMER_CHCTL0(TIMER1) = TIMER_OC_MODE_PWM0 << 8;
TIMER_CHCTL2(TIMER1) = TIMER_CHCTL2_CH1EN; // Needed for Output
TIMER_CTL0(TIMER1) = TIMER_CTL0_CEN;
}
他にもコンプリメンタリな PWM モードもありますが、それはやりません。STM32 同様、ちょこっと設定を変えるだけでできるので。
次はアナログ関連です。