Topページに戻る

Arduinoベースのスマイルデコーダの動作を見てみる

各タスクの制御周期、処理時間をオシロスコープで観測してみました。
確認したソースファイルβ4のダウンロード を使用しました。



loop処理時間


void loop() の最初と最後に D5をON/OFFさせるコードを追加しました。

■ソースコード
void loop() {
digitalWrite(5, HIGH);
    
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  Dcc.process();

  if( (millis() - gPreviousL5) >= 100){
    //Headlight control
    HeadLight_Control();
    //Reset task
    gPreviousL5 = millis();
  }
digitalWrite(5, LOW);
}

loopが呼ばれるのは、約50kHz(20us)周期で、HIレベルになっている間はloop関数を処理している時間になります。



実際の処理時間(IDLE時)は、11usくらいです。



Arduinoはノンプリエンティブの為、adpcmを再生すると、adpcm再生処理が最優先されます。
HIレベルになっている期間、adpcm再生の処理にかかりっきりになっています。



HeadLight_Control処理時間


void HeadLight_Control() の最初と最後に D6をON/OFFさせるコードを追加しました。

■ソースコード

//------------------------------------------------------------------------------
// Motor control Task (10Hz) */
//------------------------------------------------------------------------------
void HeadLight_Control()
{
digitalWrite(6, HIGH);
    uint16_t aPwmRef = 0;

    if( gState_F0 > 0){
        aPwmRef = HIGH;
    }
    else {
        aPwmRef = LOW;
    }

    //PWM出力
    //進行方向でPWMのABを切り替える
    if( gDirection > 0){
        digitalWrite(MOTOR_PWM_B, LOW);
        digitalWrite(MOTOR_PWM_A, aPwmRef);
    }
    else {
        digitalWrite(MOTOR_PWM_A, LOW);
        digitalWrite(MOTOR_PWM_B, aPwmRef);
    }

    //再生が終わっていたらここで関数を完了する
    if( gSound_played != 0) {
digitalWrite(6, LOW);
        return;
    }

    if((SoundState == 1) && (gSound_playnext == 1)) {    // DCS50Kは常にファンクッションコマンド送り続けるため、そのガード。
        //Horn (Long)
        gSound_played = 1;
        sample = 64;          // dataまでのオフセット
        ndata = 0;        // IMA ADPCM の block を初期化 
        SoundState = 0;     // 再生終了
        gSound_Length = (uint16_t)(readSoundRom(gSound_played,57)<<8 | readSoundRom(gSound_played,56));  // RIFF No56,No57
        imad.val = (int16_t)(readSoundRom(gSound_played,61) << 8 | readSoundRom(gSound_played,60));   // Get 1st sample value of the block
        imad.idx = readSoundRom(gSound_played,62);
        startPlayback();
        delay(2100);        // このdelayの間、鳴らしている?
        stopPlayback();
    }

    else if((SoundState == 1) && (gSound_playnext == 2)) {  // DCS50Kは常にファンクッションコマンド送り続けるため、そのガード。
        //Horn (Short)
        gSound_played = 2;
        sample = 64;          // dataまでのオフセット
        ndata = 0;        // IMA ADPCM の block を初期化 
        SoundState = 0;  // 再生終了
        gSound_Length = (uint16_t)(readSoundRom(gSound_played,57)<<8 | readSoundRom(gSound_played,56));  // RIFF No56,No57
        imad.val = (int16_t)(readSoundRom(gSound_played,61) << 8 | readSoundRom(gSound_played,60));   // Get 1st sample value of the block
        imad.idx = readSoundRom(gSound_played,62);
        startPlayback();
        delay(400);
        stopPlayback();
    }

    else if((SoundState == 1) && (gSound_playnext == 3)) {  // DCS50Kは常にファンクッションコマンド送り続けるため、そのガード。
        //Deactivate break
        gSound_played = 3;
        sample = 64;          // dataまでのオフセット
        ndata = 0;        // IMA ADPCM の block を初期化 
        SoundState=0;     // 再生終了
        gSound_Length = (uint16_t)(readSoundRom(gSound_played,57)<<8 | readSoundRom(gSound_played,56));  // RIFF No56,No57
        imad.val = (int16_t)(readSoundRom(gSound_played,61) << 8 | readSoundRom(gSound_played,60));         // Get 1st sample value of the block
        imad.idx = readSoundRom(gSound_played,62);    
        startPlayback();
        delay(1200);
        stopPlayback();
    }

digitalWrite(6, LOW);
}
PDS5022では10Hzの定周期+短いパルスは表示しきれないようです。
右側の周波数カウンタでは、10Hzを測定しています。



PCMを再生すると、HeadLight_Control()内で処理するため、処理が占有されます。



ISR(TIMER1_COMPA_vect)処理時間


ISR(TIMER1_COMPA_vect) の最初と最後に D6をON/OFFさせるコードを追加しました。

■ソースコード
//------------------------------------------------------------------------------
// This is called at 8000 Hz to load the next sample.
//------------------------------------------------------------------------------
ISR(TIMER1_COMPA_vect) {
digitalWrite(5, HIGH);

    static uint8_t foo;
    static uint8_t hilow = LOW;  // add aya:最初は下位

    if(ndata == 252) {    // 11/9 1 block 再生終わったら、val,idxを再セットする
        ndata = 0;
        imad.val = (int16_t)(readSoundRom(gSound_played,sample+1) << 8 | readSoundRom(gSound_played,sample)); // Get 1st sample value of the block
        imad.idx = readSoundRom(gSound_played,sample+2);
        sample += 4;
    } 

    if (sample >= gSound_Length) {            // プチッという音を出さないようにするフェードアウト処理
        if (lastSample == 0) {              // 音を0まで絞りきったら終了
            stopPlayback();        // 終了処理
        } else {
            if(speakerPin==11){
                // Ramp down to zero to reduce the click at the end of playback.
                OCR2A = lastSample;
            } else {
                OCR2B = lastSample;
            }
            lastSample = lastSample - 1;                // ボリュームを1つさげる
        }
    } else {
        if(speakerPin == 11) {
            OCR2A = ima_decode(&imad,readSoundRom(gSound_played, sample), hilow); // aya add:IMA ADPCM DECODE処理
        } else {
            foo = ima_decode(&imad,readSoundRom(gSound_played, sample), hilow); // aya add:IMA ADPCM DECODE処理
            OCR2B = foo;
            if (sample == gSound_Length - 1) {          // 最後の音をlastSampleに代入
                lastSample = foo;
            }
        }
    }

    if(hilow == HIGH){     // add aya : IMA ADPCM は1byteに4bit*2のデータがあるからね。
        hilow = LOW;
        sample++;         // 再生アドレスをインクリメント
        ndata++;            // IMA ADPMC 1BLOCKカウントをインクリメント
    } else {
        hilow = HIGH;
    }
digitalWrite(5, LOW);
}
adpcmを再生する為に、8kHz(125us)周期で割り込みが入ってきます。



テーブルから読み出して、IMA ADPCMからPCM変換する処理時間は24usくらいです



わかったこと

・Arduino OS?は、ノンプリエンティブタイプのOSだという事。
・loop()タスクは約50kHz(20us)周期で呼び出されるが、ADPCM再生時はアクセスされない。


2015/11/20 初版