ループ処理の実行時間について

こんにちは。マイコン初心者です。

R8C/15を使ってLEDの点灯を繰り返そうと思っています。
Timerを使わずに、ソフトウェアタイマ(for文のカウントアップで、
wait時間を作ろうと考えていました。
例えば1msecの時間をfor文で作ろうと思い、20Msecのクロック選択なので、
20MHzのクロックなので、1/20M=50nsecとなり、
20000倍にすれば1msec近くになると思っていました。
しかし、サイクル数のシュミレーションをみると、32768サイクル(約20msec)という結果になっていました。。。
単純に20msec/32768=610nなので1.6MHzがサイクル周波数となっています。
またシミュレータ同様にオシロでポートのON/OFFをオシロで確認すると、20msecぐらいかかっています。
クロックは初期化で20MHzに設定していると思うのですが、
何が原因は考えらますでしょうか?お手数ですがアドバイスいただけると幸いです。


参考までにプログラム(開発環境はHEW4.0)と実行時間結果の様子をのせておきます。
デバッガーが原因かと思い切り分けを行うためにRUNモードでも確認しましたが動作は同じになりました。

R8CデータシートURL:http://documentation.renesas.com/doc/products/mpumcu/rjj09b0176_r8c14hm.pdf

作成プログラム↓

======================================================
#include "sfr_r815.h"


// メインクロック切替関数 20MHz
void set_MainCLK(void)
{
 prc0 = 1;      // プロテクト制御(書き換え許可)
 cm13 = 1;      // Xin-Xout端子切り替え
 cm05 = 0;      // Xin-Xoutメインクロック発振
 cm06 = 0;      // 8分周以外(分周なし)
 asm("nop");     // 発振の安定待ち
 asm("nop");     //    (同上)
 asm("nop");     //    (同上)
 asm("nop");     //    (同上)
 ocd2 = 0;      // メインクロック選択
 prc0 = 0;      // プロテクト制御(書き換え禁止)
}

//メイン関数 Wait時間の確認 20000回のカウントアップで1msec
void main(void)
{
 int cnt;
 set_MainCLK();
 pd1_3=1;
 while(1)
 {
 p1_3=0;
 for(cnt=0; cnt<2000; cnt++); //wait 0.1msec
 p1_3=1;
 for(cnt=0; cnt<20000; cnt++); //wait 1msec
 }

}
======================================================

wait時間.pdf

 

 

  • ryuさん

    C言語の1行は(実際にCPUが実行する命令である)アセンブラでは複数命令で構成されています。
    そのためfor文などの処理には、実は20クロックくらいかかっている可能性があります。

    PS
    チョコさんと投稿かぶりましたね^^

  • チョコです。

    forループは1命令で実行できるわけではなく、複数の命令で実行されます。

    そのため、20MHzで動作時に20000回のループで1msecとなることはなく、

    遙かに長い時間が必要です。

    ループの実行時間を見積もるには、1ステートメントがどのような命令で構成

    されるかを確認して、そのうえで、概略の時間を見積もってください。

  • オンチップオシレータ32MHzの場合、こんな感じで大体1mSになるようです(CS+とE1で実験しました)。

    void DelayMsec(uint16_t cnt)

    {

    uint16_t i, j;

    for (i = 0; i < cnt; i++) {

    for (j = 0; j < 3541; j++);

    }

    }

    正確に調べたいのなら逆アセンブルしたソースを追いかける(それでも割込みが入れば変わるはず)・・・自分は面倒くさいからCS+の実行時間監視機能を使ったり、実際にプログラムを走らせてストップウオッチで30秒ほど計って「j<3541」の部分を調整してます。

    「LEDの点滅周期」と言う事なら実動作させて大体でOKって事でどうでしょう?

  • 皆様、

    アドバイスありがとうございます!!!!

    助かりました。

    さきほど、アセンブリコードをソフトウェアマニュアルをみてひとつひとつ命令文を確認してみました。

    実行サイクルは約18サイクルほどかかっているようです。

    このような確認の仕方はただしいのかわかりませんが、for文でのソフトウェアタイマは調整が必要なことが認識できました。

    今回はLEDの点灯のためと、今後のLCDモジュールやいろいろと簡易的なmsecのWait関数を作ろうと考えていましたので、

    今回の調査によりR8Cを使うときのカウント数は18倍を目安に考えたいと思います。

    ちなみに、他のマイコンでもソフトウェアタイマー作るときは同じぐらいの命令サイクルがかかるのでyそうか?

    最近よくARMマイコンが記事になったりしているのですが同じようなものなのでしょうか?

  • コンパイラの出力はコンパイルオプションで変わったりもしますし、いまどきのコンパイラでは最適化で空ループを削除したりもするのでお勧めできる方法ではないです。

    時間待ちはアセンブラで書くかインラインアセンブラを使えばコンパイラの最適化の影響は受けなくなるのでまだマシですが。

  • ryuさん

    はい、ARM系マイコンでも同様で、forループを回すには何クロックか必要ですね。

  • みなさん、

    ありがとうございます!!

    コンパイラの設定によりかわるとのことなので、いろいろと手を動かしてみていきたいと思います。