So-net無料ブログ作成

Mp3V5の32KHz時の負荷低減について [ds-DCCデコーダ]

 青春18きっぷを買ってみました。大学生の時以来ですね。でも、そういえば行くところすら決めていません。
 碓氷峠鉄道文化むらとか日帰りでいいかなあとか思います。東海道線が高崎まで直通で、朝6時に家を出ると10時に横川に着くようですし。
 さて、標題の話題ですが、
・Mp3V5で走行音を出すと若者にはモスキート音(16KHz)が聞こえる。
→理由は16KHzのパルスで音の波形を作っているため。そのパルスもアンプで強調されてしまうため。
・パルス周期を32KHzにすれば16KHzの音が小さくなるかもと思って、32KHzに変更した。
→マイコンの負荷が高くなって、DCCのパケットを取りこぼしやすくなったためか、走行時に暴走しやすくなった。との報告。(ごめんなさい。実車に乗せて確認してないです・・・。)
 で、どうすればマイコンの負荷低減ができて、DCCのパケットをもらうプロセスをたくさん回せるか(→暴走しなくなる)という話になっているかと思います。

 で、とりあえずVVVF部分の負荷を低減できるか実験してみました。すべて、VVVF_Sound.cppの話です。

 まずは、へのへのもへじ様やあやのすけ様からお聞きして、私もVVVF音部分の割り込み時どのくらい時間を占有しているかを確認してみるため、割り込み関数「void vvvf_int1()」の最初と最後に

PORTD ^= _BV(PD7);

を入れて、割り込み時にピンから信号を出力をさせて、Arduino7ピンからオシロで波形を見てみました。
 なお、上記をやるためにはスケッチの一番最初に、

pinMode(7, OUTPUT);

の、おまじないをしないと出力されません・・・。

 で、結果波形が以下です。まずはEL102bスケッチ(16KHzのもの)です。Lowの時が割り込み中です。
走行時
EL102b走行時.png

停止時
EL102b停止時.png

走行時は周期が62usぐらいで、割り込み時間は16.7usです。
停止時は周期が62usぐらいで、割り込み時間は0.8usです。

次に、EL102cスケッチ(32KHzのもの)です。16KHzごとにパルスDutyを変えるスケッチになります。
走行時
EL102c走行時.png

停止時
EL102c停止時.png

走行時は周期が31usぐらいで、割り込み時間は17.1us、0.8usを繰り返します。
停止時は周期が31usぐらいで、割り込み時間は1,3us、0.8usを繰り返します。

また、せっかくですから、割り込み関数内の各命令がどのくらい時間を食っているのかもついでに確認してみました。
中身ですが
(1)2回に1回だけ命令を実行するためのトグル関数・・・0.8us(7ピンの出力含む)
flg = !flg;
if(flg)
{
return;
}

(2)VVVF音を出すかどうかの条件分岐・・・0.5us
if (pwm_shift != 8)

(3)波形の計算・・・4.5us(ただしpwm_shiftの値で若干変わる)
a = ((pgm_read_byte_near(&WAV_DATA1 [pwm_state1 >> SHIFT_PWM]) * 3 + pgm_read_byte_near(&WAV_DATA3 [pwm_state3 >> SHIFT_PWM])) >> pwm_shift)

(4)波形をTimer1に書く・・・6.9us
Timer1.setPwmDuty(VVVF_SOUND_PIN,a);

(5)波形の次のポイントへの移動・・・2.5us
pwm_state1 += pwm_add1;
if((pwm_state1 >= (WAV_LENGTH1 << SHIFT_PWM)))
pwm_state1 -= (WAV_LENGTH1 << SHIFT_PWM);
pwm_state3 += pwm_add3;
if((pwm_state3 >= (WAV_LENGTH3 << SHIFT_PWM)))
pwm_state3 -= (WAV_LENGTH3 << SHIFT_PWM);

仕事の改善提案ではありませんが・・・、明らかに(4)のDutyをTimer1に書くところが
やっていることに対して時間をとりすぎな感じがプンプンします。
ということで、Timer1ライブラリのsetPwmDutyを眺めてみました。
すると、
void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
・・・
となっており、long型の掛け算をやっており、これは遅そうだと思いました。
 Timer1は16ビットのタイマーで、もともとTimer1の周波数を変更してVVVF音の音階を変えようと思っていたのですが、いろいろと試行錯誤をやっているうちに、パルス周期は一定で波形周期だけ変える形に変更したため、Timer1の高機能は現在いらなくなっています。32kHzだけ出ればいいんです。
 ということで、Timer1を取っ払ってしまうことにしました。
具体的には、
void VVVF_Setup()
{
//PWM出力ピン D9を出力にセット
pinMode(VVVF_SOUND_PIN, OUTPUT);
//Timer1使用
Timer1.initialize();
//初期設定
Timer1.pwm(VVVF_SOUND_PIN,0,0);
Timer1.attachInterrupt(vvvf_int1,current_period1);//interruptの設定
}
部分を、analogWriteでも使用している8ビットタイマーにしてしまっています。
以下になります。

void VVVF_Setup()
{
//PWM出力ピン D9を出力にセット
pinMode(VVVF_SOUND_PIN, OUTPUT);

//31KHzに設定(初期設定でPhaseCorrectPWMモードになっていると思う)
//D9,D10 キャリア周期:31kHz(分周無し)
TCCR1B &= B11111000;
TCCR1B |= B00000001;

//出力の設定
if(VVVF_SOUND_PIN == 9)
{
TCCR1A |= _BV(COM1A1);
}
else //10
{
TCCR1A |= _BV(COM1B1);
}

//interrupt設定
TIMSK1 = _BV(TOIE1);
}

で、割り込みはAVRでよく見る形に変えています。
関数名をポインタで指定するやり方がよくわからなくって・・・。
ISR(TIMER1_OVF_vect)
{
・・・
unsigned int a = ((pgm_read_byte_near(&WAV_DATA1 [pwm_state1 >> SHIFT_PWM]) * 3 + pgm_read_byte_near(&WAV_DATA3 [pwm_state3 >> SHIFT_PWM])));

if (VVVF_SOUND_PIN == 9)
{
OCR1A=a>>(pwm_shift + 2);
}
else//(VVVF_SOUND_PIN == 10)
{
OCR1B=a>>(pwm_shift + 2);
}
・・・
}

で、これでめでたく、割り込み時間が短くなりました。
EL102dスケッチ(こちら)になります。
走行時
EL102d走行時(Timer1やめ).png

停止時
EL102d停止時(Timer1やめ).png

走行時は周期が31usぐらいで、割り込み時間は10.4us、0.8usを繰り返します。
停止時は周期が31usぐらいで、割り込み時間は1,3us、0.8usを繰り返します。

 一応、世間的にいうと17.1us→10.4usなので「性能は1.5倍アップ!」です。
 でも、たぶん、割り込みのために、割り込み前、割り込み後に必要な退避とかがあるでしょうから、そんなにアップしてないんだろうなあとは思います。


コメント(2)  トラックバック(0) 

コメント 2

へのへのもへじ

こんにちは

私とは逆に、割り込み時間で比較されたのですね。
私も走行を始めると負荷が上がるので「DutyをTimer1に書くところが時間がかかる」のは想像していましたが、いろいろと手を加えても、大きくは変化しませんでした。

ちなみにTimer1はarduinoのanalogwriteで設定が上書きされているのかと、思っていました。「割り込み前、割り込み後に必要な退避」は私の測定とfujigaya2様の差でわかるかと思います。

なお、私はNゲージでの暴走が気になってこの件の調査をはじめたのですが、結局や32k/16kで大きくは変わらず、問題はDCCのパルスの取り込みが信号の割り込みででとりこんでいることかと想像しています。割り込みが入って1、0を判断する前にノイズで再度割り込みが多数入る現象が確認されています。

PICを使ったワンコインデコーダはたぶん仕組みが違うから暴走しないのかと思います。Nrmaライブラリを、タイマー割り込みだけで判断するような改善をするかどうか、考え中です。


by へのへのもへじ (2017-08-07 19:40) 

fujigaya2

コメントありがとうございます。

 へのへのもへじ様はシステムのパフォーマンスで確認されていたと思いますが、私の方は、その中で、(自分が主に作った)VVVF部分の影響がどのくらいかと、パフォーマンスのアップがどのくらい可能かという点で見ました。
 今までのデバッグは、作っては動かして、どうかなあという感じだったのですが、へのへのもへじ様、あやのすけ様のデバッグ用に信号を出力して確認する方法をお聞きして、(恥ずかしい話ですが)初めて、どのくらい占有しているかがわかりました。

あとは、「割り込み前、割り込み後に必要な退避」がかなりの時間占有していそうなこともわかりました。

by fujigaya2 (2017-08-07 21:01) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0