RISC-V搭載の「お求めやすい」マイコン、GigaDevice社GD32VF103の機能を一通り触ってみるべく「活動」しておりますが、まだまだ題材は尽きる気配はありません。今回は、ありがちな、タイマをつかったPWM出力をやってみたいと思います。使用する開発ボードは、久しぶり、Sipeed社のLongan nanoであります。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
さてGD32VF103は、周辺回路として7個のタイマを搭載しています。この数の中にはウオッチドッグタイマとか、実時間タイマ(RTC)など特定用途向けのタイマは含まれません。プログラムで普通にタイマとして使えるタイマの数です。さらに言えば、タイマ0番から4番までの5本のタイマは、それぞれ4CHをその内部に含んでいるので、機能的には20+2本で22本といってもあながち間違いではありません。まとめるとこんな感じです
-
- タイマ0 Advanced timer (内部に4チャネル)
- タイマ1,2,3,4 General level0 timer (それぞれ内部に4チャネル)
- タイマ5,6 Basic timer
ザックリ言ってしまうと、タイマ0がこのチップ上は最強にいろいろできるタイマで、タイマ1,2,3,4はそのお手軽バージョン(タイマ0の一部割愛版)です。タイマ0から4までは、内部にコンペア、キャプチャのための4チャネルをもち、それぞれのチャネルでIOが可能なタイマです。これに対してBasic timerと呼ばれている5番と6番は、入出力用ではなく、内部の「タイミング」を生成するため、例えば、DMAの周期とか割り込み周期とか、「昔ながらの」タイマの仕事を行うためのものです。
基本、すべてのタイマは16ビット幅のカウンタと、16ビット幅のプリスケーラ(もちろんプログラマブル)を持っています。一番ゴージャスなタイマ0にいたっては、配下?のタイマ1、2、3、4をプリスケーラとして接続するようなモードも持っています。
タイマ0,1,2,3,4については以下のような、近代的な(いつの時代からだ)マイコンには必須の入出力機能が備わっています。
-
- インプットキャプチャ
- アウトプットコンペア
- PWM出力
また、モーター制御のため
-
- Quadrature decoder
- Hall sensor function
も備えています。
今回、まずは
TIMER 3 の CH0からCH3までをつかったPWM出力
をやってみます。タイマは4本あるのですが、REMAPしないデフォルト状態では、多くの入出力信号端子はポートAとポートBに集中しています。このため、Longan nanoのような48ピンパッケージ版でもタイマの端子にはあまり不自由はしません。このところ100ピン版のSeeed Studio版の開発ボードばかり使ってきましたが、今回、久しぶりにLongan nanoに戻ってきました。TIMER 3 にしたのは、Longan nanoのUSBを下にしておいた時の右肩のGND端子の横に
GND, GND, PB9, PB8, PB7, PB6
と言う具合にTIMER 3 のCH3, CH2, CH1, CH0出力が並ぶので、出力信号を「観察しやすい」というだけの理由です。
まずは、例によって、周辺回路の初期化。ポートBへのクロック供給(最初、PWM出力が出なくてさんざん、タイマ回りを見直しましたが、忘れていたのはこれでした)から始まり、Alternate Function(タイマはオルタネートなんだそうな)、タイマ端子の初期化です。
rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_AF); // initialize GPIO // PB6 ... TIMER3 CH0 // PB7 ... TIMER3 CH1 // PB8 ... TIMER3 CH2 // PB9 ... TIMER3 CH3 gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); // TIMER3 CH0 gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7); // TIMER3 CH1 gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8); // TIMER3 CH2 gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // TIMER3 CH3
続いて、タイマ内部の設定ですが、この関数は、SDKの中のPWMのExampleをTIMER3用にして、さらに4CH全てを使うように設定しただけのものなので、先頭のみで以下省略させていただきます。
void timer_config(void) { timer_oc_parameter_struct timer_ocinitpara; timer_parameter_struct timer_initpara; rcu_periph_clock_enable(RCU_TIMER3); timer_deinit(TIMER3); ~以下略~
ちゃんとPWM出力でているのか、確認するために、いつもお世話になっている
Digilent社Analog Discorery 2
を使用させていただきました。CH1, 2の波形みるとこんな感じ。OKかな。
なお、「ゆっくり」観察できるように周期は160msくらいになるように設定してあります(Example設定値の10倍)。
Analog Discovery 2のオシロは2CHなので、4CHある全信号を同時に見ることはできません。しかし、Analog Discovery 2は優れものです。Analogといいながら、
Logic Analyzer(的な)
機能を含んでいます。そのときの接続がこちら。
これでRUNすれば、アイキャッチ画像のようなPWM波形の出来上がり。
まっことありがち