FASTIOライブラリ(2)

このページをスマホなどでご覧になる場合は、画面を横長にする方が読みやすくなります。
目次へ  前のページへ (1) (2) (3) (4) (5) (6) (7) (8) 次のページへ
2019年08月07日 公開。

5.FASTIOライブラリの特徴の説明

FASTIOライブラリには次の様な特徴があります。

5-1.GPIOのアクセスが高速

FASTIOライブラリを使うと、Arduino本体のデジタルI/Oピン(GPIO)へのアクセスが高速化します。

Arduino標準のdigitalWrite関数およびdigitalRead関数によるそれぞれ10万回の入力および出力にかかった時間と、同様の操作をFASTIOを使って行った場合にかかった時間を、表2に示します。出力時には約22倍、入力時には約32倍の高速化ができている様子が分かります。

表2、Arduino標準関数を使った場合とFASTIOライブラリを使った場合の実行時間
  Arduino標準関数を使った場合の実行時間 FASTIOライブラリを使った場合の実行時間
出力(digitalWrite関数) 336ms(リスト1で計測) 15ms(リスト2で計測)
入力(dititalWrite関数) 291ms(リスト3で計測) 9ms(リスト4で計測)

注:計測はArduino Unoで行いました。また、コンパイルはArduino IDE 1.8.5で行いました。計測に使ったスケッチのリストをリスト1~リスト4に示します。

広告
リスト1、Arduino標準のdigitalWrite関数を使った実行時間計測スケッチCOPY
void setup() 
{
  Serial.begin(9600); // シリアルポートを9600bpsで開く
  pinMode(13,OUTPUT); // 13番ピンを出力に設定
} // setup

void loop() {
  uint32_t start, stop; // 実行時間を計測するための変数

  start=millis(); // 計測開始時刻の取得
  for(int i=0; i<10000; i++) { // digitalWrite関数を10万回呼び出す
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
  } // for i
  stop=millis(); // 計測終了時刻の取得
  Serial.println(stop-start); // 実行時間をms単位で表示
} // loop
リスト2、FASTIOライブラリのdigitalWrite関数を使った実行時間計測スケッチCOPY
#include <fastio.h> // FASTIOライブラリのヘッダファイルをインクルード

void setup() 
{
  Serial.begin(9600); // シリアルポートを9600bpsで開く
  pinMode(13,OUTPUT); // 13番ピンを出力に設定
} // setup

void loop() {
  uint32_t start, stop; // 実行時間を計測するための変数

  start=millis(); // 計測開始時刻の取得
  for(int i=0; i<10000; i++) { // digitalWrite関数を10万回呼び出す
    digitalWrite<13>(HIGH); // FASTIOライブラリのdigitalWrite関数の呼び出し。第1引数が<13>と、山括弧で囲まれている事に注意。
    digitalWrite<13>(LOW);
    digitalWrite<13>(HIGH);
    digitalWrite<13>(LOW);
    digitalWrite<13>(HIGH);
    digitalWrite<13>(LOW);
    digitalWrite<13>(HIGH);
    digitalWrite<13>(LOW);
    digitalWrite<13>(HIGH);
    digitalWrite<13>(LOW);
  } // for i
  stop=millis(); // 計測終了時刻の取得
  Serial.println(stop-start); // 実行時間をms単位で表示
} // loop
リスト3、Arduino標準のdigitalRead関数を使った実行時間計測スケッチCOPY
void setup() 
{
  Serial.begin(9600); // シリアルポートを9600bpsで開く
  pinMode(13,INPUT_PULLUP); // 13番ピンを入力(プルアップ付き)に設定
} // setup

void loop() {
  uint32_t start, stop; // 実行時間を計測するための変数

  start=millis(); // 計測開始時刻の取得
  for(int i=0; i<10000; i++) { // digitalRead関数を10万回呼び出す
    int data; // 入力の結果を格納する変数
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);
    data=digitalRead(13);    
  } // for i
  stop=millis(); // 計測終了時刻の取得
  Serial.println(stop-start); // 実行時間をms単位で表示
} // loop
リスト4、FASTIOライブラリのdigitalRead関数を使った実行時間計測スケッチCOPY
#include <fastio.h> // FASTIOライブラリのヘッダファイルをインクルード

void setup() 
{
  Serial.begin(9600); // シリアルポートを9600bpsで開く
  pinMode(13,INPUT_PULLUP); // 13番ピンを入力(プルアップ付き)に設定
} // setup

void loop() {
  uint32_t start, stop; // 実行時間を計測するための変数

  start=millis(); // 計測開始時刻の取得
  for(int i=0; i<10000; i++) { // digitalRead関数を10万回呼び出す
    int data; // 入力の結果を格納する変数
    data=digitalRead<13>(); // FASTIOライブラリのdigitalRead関数の呼び出し。第1引数が<13>と、山括弧で囲まれている事に注意。
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();
    data=digitalRead<13>();    
  } // for i
  stop=millis(); // 計測終了時刻の取得
  Serial.println(stop-start); // 実行時間をms単位で表示
} // loop

念のために、リスト1(Arduino標準のdigitalWrite関数を使用)を実行した場合と、リスト2(FASTIOライブラリのdigitalWrite関数を使用)を実行した場合について、13番ピンの出力波形をロジックアナライザで観察してみました。

リスト1の実行時の出力波形を図1に、リスト2の実行時の出力波形を図2に示します。これらの波形からも、FASTIOライブラリを使う事により、digitalWrite関数の実行が二十数倍に速くなっている事が確認できます。

図1、リスト1(Arduino標準のdigitalWrite関数を使用)の実行時の出力波形
↑ 画像をクリックすると拡大
図1、リスト1(Arduino標準のdigitalWrite関数を使用)の実行時の出力波形

ばらつきがあるものの、digitalWrite関数1回の実行に、3.2~3.4μs(3200~3400ns)程度の時間がかかっている事が分かります。16MHzのArduino Unoのクロック周期は62.5nsですから、1回のdigitalWrite関数の実行に3300nsかかっているとして、3300÷62.5=52.8クロック程度の実行サイクルが必要な事が分かります。出力がLになっている期間がHになっている期間より短い傾向が観察できるので、Lを出力する場合とHを出力する場合で実行時間が少し違いそうです。この測定は、Arduino starter kit with Logic Analyzer付属のロジックアナライザで行いました。

図2、リスト2(FASTIOライブラリのdigitalWrite関数を使用)の実行時の出力波形
↑ 画像をクリックすると拡大
図2、リスト2(FASTIOライブラリのdigitalWrite関数を使用)の実行時の出力波形

digitalWrite関数1回の実行に、120~130ns程度の時間がかかっている事が分かります。時々波形のLの期間が380ns程度に広くなっている理由は、digitalWrite関数を10回実行するたびに、forループによる繰り返しがあり、変数iのインクリメント、iの値のチェック、ジャンプ命令などに時間がかかるためです。digitalWrite関数1回の実行に125nsの時間がかかっているとして、125÷62.5=2サイクルで実行できている事が分かります。なお、計測結果が120nsになったり130nsになったりするのは、ロジックアナライザの時間分解能が10nsだからです。

参考:表2に示した、10万回の関数の実行にかかった時間をms単位で表わした数字を10倍して、100万回の関数の実行にかかった時間に換算すれば、1回の関数の実行にかかった時間をns単位で表わした数字に、理屈の上ではなります。表1ではリスト1の実行に336msかかっていますから、関数1回あたり3360nsかかっている計算になります。これは、図1に示したロジックアナライザで測定した結果によく一致しています。また、表1ではリスト2の実行に15msかっかっていますから、関数1回あたり150nsかかっている計算になります。図2に示したロジックアナライザによる測定結果(120~130ns)より少し長めに出ているのは、forループによるオーバーヘッドも含めて計測しているからだと推測できます。(リスト1の場合は、digitalWrite関数の実行に長い時間がかかっているので、forループによるオーバーヘッドはあまり問題になりません)

次のページでは、FASTIOライブラリのその他の特徴について説明します。

目次へ  前のページへ (1) (2) (3) (4) (5) (6) (7) (8) 次のページへ

このページで使われている用語の解説

関連ページ

Arduino 電子工作
このサイトの記事が本になりました。
書名:Arduino 電子工作
ISBN:978-4-7775-1941-5
工学社の書籍の内容の紹介ページ
本のカバーの写真か書名をクリックすると、Amazonの書籍購入ページに移動します。