Topページに戻る
| ★Arduinoベースのスマイルデコーダの動作を見てみる |
各タスクの制御周期、処理時間をオシロスコープで観測してみました。
確認したソースファイルβ4のダウンロード を使用しました。

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再生の処理にかかりっきりになっています。

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 初版