google-site-verification: google3bd66dd162ef54c7.html

FlexiTimer2の挙動の調査(Arduino)

 ちょっとやってみたいことがあるので、Arduinoのタイマー割込みライブラリであるFlexiTimer2の使い方を試していました。何をやりたいのかは、もう少し目処が立ってから記事にしたいと思いますが、Arduinoで二種類のタイマー割り込みを使った機能を作りたいと思っています。

 ところで、Arduinoのタイマー割り込みで有名なのはMsTimer2です。私もよく使っていて、だいぶ前の記事でこのタイマーの精度を調べたことがあります。MsTimer2は使い易いのですが、割込み間隔が1ms 単位しか設定出来ないので、これより細かいタイミングを作ることが出来ません。

 もっと細かい時間が設定出来るようにするために、MsTimer2の上位互換のライブラリとしてFlexiTimer2があり、割込み周期をより細かく指定出来るようになっています。関数の形式は下記で、

 FlexiTimer2::set(unsigned long units, double resolution, void (*f)());

 最初の引数(units)には時間を、二番目の引数(resolution)には時間の単位を指定することになっていて、

 例えば、FlexiTimer2::set(1, 1.0/3000, IRQ);

 とやれば1秒間に3000回の割り込みがかかります。これ、Arduino Playground のFlexiTimer2の解説に書いてある通りで、これ以外の制約について何も書かれていません。ならば、第二引数に 1.0/1000000 と入れると1μs単位の値が設定出来そうな気配です。

 とは言ってもArduinoの時間は4μs単位でカウントされているので、そのあたりが限界になる?それと、第二引数のタイプがdouble(倍精度浮動小数点)になっているけど、この型をArduinoで使うのはちょっと違和感があるなー。

 なんて思いながら動かしてみると、FlexiTimer2はとんでもない挙動を示しました。

▼オシロで波形を確認しながら
波形
 同時にユニバーサルカウンタでパルスの周期を測りました。

▼測定に使ったスケッチ
/* FlexiTimer2のテスト
* 引数を変えた時のFlexiTimer2の挙動調査スケッチ
*/

#include <FlexiTimer2.h>

void setup() {
pinMode(13, OUTPUT);
IntervalSet(0.000036); // FlexiTimer2の条件を変えて
}

void loop() {
}

void IntervalSet(float data) { // 引数をFlexiTimer2に設定
FlexiTimer2::stop();
FlexiTimer2::set(1, data, IRQ_timer2); // 第二引数の値を変えて測定
FlexiTimer2::start();
}

void IRQ_timer2() { // FlexiTimer2の割込み処理
// PORTB |= B00100000; // sbi
// PORTB &= B11011111; // cbi
digitalWrite(13, HIGH);
digitalWrite(13, LOW);
}
 このスケッチの9行目にいろいろな値を入れてパルスの周期を測定してみました。

▼測定結果
FlexiTimer2の特性
 これはびっくり。設定値に対して実際に出力される値が一致するのは 40~1000μsの範囲(0.00004~0.001)だけでした。50μsで誤差が多くなっているのは、時間の単位である4μsで割り切れないので、こういう結果になったのだと思います。ちなみに4μの倍数で値を設定すると誤差が少なくなり、24μsあたりが少ない誤差で設定出来る下限でした。

 時間が短い方はタイミング的に苦しくなるのでまあこういう結果になっても仕方ないと思います。でも意外だったのは時間が長い方です。1ms以上の値を指定しても全く無視されています。ライブラリの説明にはそんなことは書かれていないのに、この結果はちょっとどうなんだかなーと思います。

▼測定結果のグラフ
FlexiTimer2、設定に対する出力周期
 設定出来るのは、このグラフに白抜き矢印で「使える範囲」と書いてある領域になります。なおこれは設定単位の話で、これに対する倍率を別途第一引数で指定出来るので、実際には1ms以上の割込み間隔を指定することが出来ます。
 FlexiTimer2はMsTimer2の構造を流用して作ったようなことがどこかに書いてあったような気がするので、上限の時間単位が1msになっているのかも知れません。

◆まとめ
 ということで、FlexiTimer2の使い方には条件があることが判りました。この記事に書いたような制約があることを理解して使わないと、思わぬトラブルに巻き込まれると思います。 というか、実際に私がトラブルに遭ったので詳しく調べた結果がこの記事です。

 こういう制約はライブラリの説明のどこかに書いておいて欲しいです。まあ私が見落としている、あるいは英語の文章の行間が読めなくて、こんな記事を書いてしまっているなら申し訳ないです。

 あと、この記事の結果は、ここで示しているスケッチを動かして得られた結果です (@Arduino
UNO 16MHz)。特に割込み処理ルーチン(21~26行)の中に何を書くかで結果が大きく変わってしまうはずなのでご注意下さい。
関連記事

コメントの投稿

管理者にだけ表示を許可する

タイマー2

「プリンタシールドでチャートレコーダ」
http://act-ele.c.ooco.jp/toukou/prnsld/prnsld1.htm
この中で、0.5mS割り込みが欲しかったので、MsTimer2ではなく、ATmega328のタイマ2レジスタを直接操作して割り込み処理しています。

プリスケーラとコンペアマッチレジスタに必要分周比をセット。
タイマー2割り込み内でA/D変換を開始。
A/D割り込み内で値をリード。

主要部をピックアップするとこんな感じです。

※setup部

// タイマー計時
// (MsTimer2は0.5mSに対応していないので使わない)
// MsTimer2::set(1, tm2int); // 1msサイクル割り込み処理
// MsTimer2::start(); //
TCCR2A = 0b00000010;
// ++---- WGM21,20 CTCモード
TCCR2B = 0b00000100;
// |+++---- プリスケーラ1/64
// +------- WGM22
OCR2A = 125-1; // 16MHz / 64 / 125 = 2kHz
TIMSK2 = 0b00000010;
// +----- OCIE2A
sei(); // 割り込み開始



※割り込みの記述

/***** タイマー2 0.5mS割り込み *****/
// A/Dに対して変換指令
ISR(TIMER2_COMPA_vect)
{
static byte tc = 0; // 1msカウント
TP2_H; // (!!!)test
// 0.5ms タイマー処理
:
:
// 0.5msを2回カウントして1msに
tc++; // 0,1
if(tc >= 2){ // 1ms
tc = 0;
// 1ms計時処理(ダウンカウント)
if(tm_1ms) tm_1ms--;
}
// A/D変換 データの読み出しは変換完了割り込みで
ADCSRA |= (1 << ADSC); // A/D変換開始
TP2_L; // (!!!)test
}

/***** A/D割り込み処理 *****/
// タイマー割り込みでA/D変換開始
// 1msで2chの変換を終わる
// 0,1は入力データ
// min,max判定のためこの処理の中で
ISR(ADC_vect)
{
int d;
TP3_H; // (!!!)test
d = (word)ADCL; //
d |= (ADCH & 0x03) << 8; // 符号なしで 0~3FF
:
:
TP3_L; // (!!!)test
}

re:タイマー2

居酒屋ガレージ店主(JH3DBO)さん詳しい解説ありがとうございます。

prinsld01a.inoのスケッチと、ここのコメントに書いていただいた解説と、CPUのデーターシートを見比べて読んでいますが、こうやって順番に説明していただくと、すごく判り易いです。

それと、プログラムの書き方やマクロ定義やPROGMEMの使い方などなど勉強になります。ソースを印刷して一通り目を通して勉強させていただきます。

パルス発生器

AarduinoじゃありませんがATtiny2313の応用例です。
http://act-ele.c.ooco.jp/toukou/pulse1/pulse1.htm
タイマーの使い方など参考にしていただければと。


re:パルス発生器

居酒屋ガレージ店主(JH3DBO)さん、情報ありがとうございます。

資料拝見しました。ATtinyのタイメーなどの機能をしゃぶりつくしたパルジェネなんですね。プログラムをAVRネイティブのCで書いたのかと思ったら、なんとアセンブラとは、恐れ入りました。

タイマーの出力を一旦ピンに出して、それを別のピンに入れるなんてテクニックがあろうとは、思いつきませんでした。

記事拝見しました。
FlexiTimer2の第二引数ですが、実験結果から察するに
下位10bitしか有効でないようですね。
2000や5000の結果を10bitで丸めてみると、それらしい値になるようです。
マイコンのハードウェアカウンタの制約かも。ソース見てませんが。

ちなみに第一引数次第で1ms以上を作れますが、どうやらソフトで数えているようで、
かつ多重割り込み非対応のようです。第一引数「10」で第二引数「1」にしている際、
10ms毎に割り込みに入りますが、この中で1ms以上の処理をしていると、どんどん
ズレていくようです。
このあたりは、作られてる方のポリシー次第でしょうかね。

re:記事拝見しました。

確かに、表の値を見ると、設定値を1024で割った余りとして評価されているみたいですね。

ただ、第二引数は浮動小数点で表わした秒単位の値を入れるので、例えば 2000μs なら 0.002 という値を入れます。なので、変数の下位10ビットという表現はちょっと違うような気がします。

まあライブラリの中でおっしゃているようなことが起きているんでしょうね。
カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード