質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

Q&A

解決済

4回答

3528閲覧

受信したMIDIデータを取りこぼしてしまう

退会済みユーザー

退会済みユーザー

総合スコア0

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

0グッド

0クリップ

投稿2018/03/14 20:01

編集2018/03/14 20:04

前提・実現したいこと

 私は,エレクトーン(ELD-02C)と Nucleo F446RE を使用して,エレクトーンのMIDIデータを読み込んでいます.読み込んだ値によって,LEDを光らせています.一度にたくさんの鍵盤を押して,MIDIデータを読み込むと,取りこぼしてしまいます.

発生している問題・エラーメッセージ

一度にたくさんの鍵盤を押して,MIDIデータを読み込むと,取りこぼしてしまいます.ノイズということも考えて,フォトカプラと,抵抗を入れましたが,変わりません.Mbedでリングバッファを自作して確認したため,バッファ漏れということはないと思われます.

下記に自作リンバッファのプログラムを載せておきます.プログラムが汚くてすみません,試作中なので,コメントアウト等が多くあります.間違い等ありましたら指摘お願いします.

色々調べた結果,MIDIの割り込みすら起きていないと思います.

該当のソースコード

C++

1//省略 2RawSerial midi(A0,A1,31250); 3 4//省略 5 6volatile char getData__[256] = {0}; 7volatile int writePos__ = 0; 8volatile int readPos__ = 0; 9volatile int available__ = 0; 10 11 12void Midi_RX(); 13int getData(); 14int peekData(); 15 16//省略 17 18int main() 19{ 20 //省略 21 midi.attach(Midi_RX_, RawSerial::RxIrq); 22  //省略 23} 24 25char read_() 26{ 27 //while(midi.readable() == 0) {} 28 //return midi.getc(); 29 //while (available__ == 0) {} 30 readPos__++; 31 if (readPos__ > (BUFFER - 1)) readPos__ = 0; 32 char a_ = getData__[readPos__]; 33 //available__ = writePos__ - readPos__; 34 available__--; 35 //if (available__ < 0) available__ = writePos__ + ((BUFFER - 1) - readPos__); 36 //printf("++%d:%d:%d++\n\r",a_,readPos__,writePos__); 37 return a_; 38} 39 40char peek_() 41{ 42 //while(midi.readable() == 0) {} 43 //return midi.peekc(); 44 //while (available__ == 0) {} 45 //available__ = writePos__ - readPos__; 46 //if (available__ < 0) available__ = writePos__ + ((BUFFER - 1) - readPos__); 47 //printf("++%d:%d:%d++\n\r",readPos__,writePos__,available__); 48 int readPos__m = readPos__ + 1; 49 if (readPos__m > (BUFFER - 1)) readPos__m = 0; 50 return getData__[readPos__m]; 51} 52 53void write_(char *a_,int b_) 54{ 55 for (int i_ = 0 ; i_<b_; i_++) midi.putc(a_[i_]); 56} 57 58void Midi_RX_() 59{ 60 writePos__++; 61 if (writePos__ > (BUFFER - 1)) writePos__ = 0; 62 getData__[writePos__] = midi.getc(); 63 //printf("%d\n\r",getData__[writePos__]); 64 //available__ = writePos__ - readPos__; 65 //if (available__ < 0) available__ = writePos__ + ((BUFFER - 1) - readPos__); 66 available__++; 67 if (available__ > 100) printf("Over 100"); 68} 69 70//省略 71

補足情報(FW/ツールのバージョンなど)

使用器具

  • エレクトーン(ELS-02C)
  • Nucleo F446RE
  • TLP2630F

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

勘違いなされてるようなのでちと解説しておきます
__NOP関数を使っているということをトラブルの原因としているようですが、それはおそらく間違いです
LEDテープへのSPI送信ルーチンをプログラムでループ回して実装していたため、そこで処理時間が取られてしまい、シリアル受信が追いつかなくなってしまった、ものと思われます。

結果、SPIデバイス駆動ルーチンを使うことで、ここでの処理時間が劇的に減ったため、シリアル受信が間に合うようになった、というのが真相だと思われます

まー、実際のコードは提示されてないので、これもあくまで私の推測でしかないですが、不具合の原因究明はきちんとしておかないと、あとあとトラブルことになりかねません。

投稿2018/03/18 23:51

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/19 00:09

https://os.mbed.com/users/bridadan/code/WS2812/ このライブラリを使っていました。__NOP()をコメントアウトしただけ(for文は消していません)で、取りこぼしは解消したのですが、ループの処理時間の問題ということなのでしょうか?
y_waiwai

2018/03/19 00:27

__NOP関数は何をする関数なのか、をしっかり調べてみましょう。 決して、シリアル受信を阻害する(原因を作るような)関数ではありません。 木を切るときにナイフもってきてダメだったからとナイフがダメな原因だ!と言ってるのと同じように、そーじゃないんだよなーってはなしなんですよね
退会済みユーザー

退会済みユーザー

2018/03/20 07:09

わかりやすい例え。ありがとうございますm(__)m このようなことを頭においてこれからも考えるようにしたいと思います。
guest

0

リングバッファと言っても、追い越しの制御はしていなくて、available変数でデータ量を監視しているだけですね。大丈夫かな?
F446ならメモリ沢山あるでしょうから、一旦バッファを数KBとか沢山確保して、available__の最大値がどのくらいまで行くのか、データを取ってみるということも出来るかと思います。これが256を超えるようだったら、今よりはバッファを増やさないと取りこぼしは仕方ない、ということになってしまいます。

それと。とても気になるのが、割り込みハンドラのMidi_RX__関数中でprintfを呼んでいること。割り込み中からprintfみたいなIO関数って、ちょっと怖いです。念の為'mbed printf interrupt'でググってみたら、 Debugging with printf() calls なんてのが引っかかりました。これが、kamekyameさんの環境ではクラッシュに至らないまでも取りこぼしの原因になる、というのは考えられなくはない仮説だと思います。直接printfを呼ぶのでなく、フラグを立てるだけにしてメインタスクの方で機会を見つけてprintfを呼ぶとかにしませんか?

投稿2018/03/18 07:31

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

取りこぼしとは関係ないですが、ちと気になるところとしては、
MIDI_Rxルーチンで、いきなりmidi.getcを呼んでいますが、受信データが来ていない場合はここで待ちに入ってしまいます
ここはまず、受信データが有るかどうかを判断し、ない場合は以下の処理をパスするようにするほうがベストですね

RowSerialクラスというのはどうやらビジーループを使った送受信ユニットのようです
これは、他の処理で受信操作の実行が遅れると取りこぼしが発生します
まず、他の処理をコメントアウトし、MIDI_RXルーチンだけを無限ループで実行させ、取りこぼしが出るかどうかを見てみてください。

これで取りこぼしがなく、その他の処理を入れると取りこぼしが発生するという場合は、
その処理を分割して、取りこぼしが発生する時間間隔より早い周期で受信操作(リングバッファの格納)を行う必要があります
そこらへんの対策はオシロスコープなどで、どこで時間がかかるか、どこで分割するかというのを見ていく必要があります

それができない、という場合は、シリアルポートの送受信ルーチンを割り込み対応として作り直すってことになってしまいますね。

投稿2018/03/14 23:30

編集2018/03/14 23:48
y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/14 23:58

y_waiwai さん.回答ありがとうございます. 質問なのですが,受信割り込みでMidi_RX_を実行させているのですが,その場合,受信データが来ていないということはあるのでしょうか.
y_waiwai

2018/03/15 00:04

そのCPUを使ったことないんではっきりしたことは言えませんが、受信エラーの発生のときにも受信割り込みを発生させるCPUもあったりしますんで、そこらへんはCPUのデータシートを参照ください。 それがないという場合は、受信割り込みでは受信データは来ている(はず)、ということは言えると思います。 MIDI_RXを割り込み上で実行させるという場合は、割り込み/メインルーチン間で輻輳が発生しますんで、双方で使用している変数の取扱いには注意する必要があります
guest

0

ベストアンサー

皆さん、回答ありがとうございます。

MIDI取りこぼしの原因がわかりましたので、記させていただきます。

光らせるLEDがシリアルLEDテープで、それ用のライブラリを使っていたのですが、そのライブラリは、__NOP()関数を使っていて、それが取りこぼしの原因ということが分かりました。

__NOP()を使うライブラリから、SPIを使うライブラリにしたところ、すべてが解決しました。

y_waiwai さん、THOR_V6 さんの回答も、勉強になりました。ありがとうございました。

投稿2018/03/18 21:30

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問