ラベル SPI の投稿を表示しています。 すべての投稿を表示
ラベル SPI の投稿を表示しています。 すべての投稿を表示

2016年1月11日月曜日

ESP-WROOM-02でSPI接続のADCから取得したデータをUDPで送出


緑のマイク基板と赤いESP基板の間にあるのがMCP3002。赤い基板上で右側のLEDがうすぼんやりと点灯しているのは、SPIのDIN信号。

50kspsでサンプリングしたデータをUDPに激しく送信中。

■SPI接続のADC■

ADCもいろいろありますが、数十Ksps以上のシリアルはSPI接続のものが多いです。

今回、MCP3002という精度10bit、入力2chのADCを使います。これは5v電源なら200kspsまで動き(2.7vだと75ksps)、そのわりに秋月で180円という大変おトクなチップです。マイクをつなげばお手頃な音声入力などが可能です。

SPIはあまり使ったことがないので、こちらの記事(ESP8266 (ESP-WROOM-02) でセンサーを扱う)を参考にさせていただきました。ありがとうございます。

SPIドライバはこちらからダウンロードします(MetalPhreak/ESP8266_SPI_Driver)。通常のArduinoライブラリとは形式が異なるので、以下の作業でArduino IDEが認識できるようにします(もっといい方法をご存知の方、ご教示いただければ幸いです)。

  • ダウンロードしたらzipを解凍する
  • フォルダの名前をESP8266_SPI_Driverに変更する
  • フォルダの中のspi_register.h, spi.h, spi.cをESP_SPI_Driver直下に移動
  • Arduinoのlibrariesフォルダ直下へ移動
  • Arduino IDEを再起動

動作させてみたところ、1回のデータ取得に要する時間は11-12μ秒程度でした(関数を100回呼び出して計測)。

■ESP-WROOM-02からUDP■

1回のデータ送信に要する時間は60-70m秒程度でした(関数呼び出し)。

■ESP用のソース■

なるべく一定の速度でサンプリングしつつ、UDPで送信しなければならないのですが、両者のスピードが違いすぎるので何らかのマルチタスクっぽい仕組みが必要です。Arduinoではこういう場合Tickerを使うのですが、Tickerは最小単位がミリ秒なので、1秒間に1000データしか取れません。それではせっかく高速のSPIを使う意味がありません。

幸いなことにESPにはos_timer_arm_usというμ秒単位のインターバルが用意されていますので、これを使います。なお、これを使う場合には、setupの始めの方でsystem_timer_reinit()を使って初期化し直す必要がありますので、ご注意を。これを使わないとミリ秒でしか動いてくれません。

ということで、おおまかな構成としては

  • 初期化ルーチンでWifi接続してから、20μ秒ごとのインターバルを開始
  • インターバルで呼ばれたらSPIからADCのデータを取り込みバッファにしまう
  • バッファが一杯になったらフラグを立てて別のバッファに切り替える
  • loop()ではバッファ一杯になったかどうかのフラグをチェックし、いっぱいになっていたらUDPでデータを送信します。



■検証用のJavaコード■

UDPでちゃんとデータを送り出せているのかを検証するために受信側のコードをJavaで作りました。UDPを受信して、連番と最小値/最大値などを表示するだけです。グラフ化したり音声を出力する根性がなかったので値だけです。

こちらの記事を参考にさせていただきました。ありがとうございます。
http://k-hiura.cocolog-nifty.com/blog/2011/07/java-6e01.html


■ハマりどころ■

  • 自家製ESPモジュールからIO15が出てない。IO15のプルダウン抵抗近くのviaホールにハンダ付けして引っ張り出す。
  • SPIが動かない。これは当初参考にしていた記事の配線図が間違っていたため。私の2時間を返せ。ということで著者さんには間違ってますよ、とメールしておいた。まだ直ってないなぁ。
  • 接続直後にESPが暴走する。あれさっきまで動いてたのに…?? と思ったら、初歩的なC言語的間違い。30年ぶりぐらいにやらかした。
      char **buf; buf[0] = ptr1; buf[1] = ptr2; 
  • ESPはos_timer_arm_usってAPIでマイクロ秒単位のTickerを使えるはずなのに、ミリ秒単位でしか動いてくれない。改めてSDKマニュアルを読んだら、system_timer_reinit()で初期化しないとダメよと書いてあった。
  • Javaの符号なし整数にまたハマってしまった。いい加減覚えろよ>俺

2015年9月22日火曜日

スペクトルアナライザー by MSP432P401R+Energia MT

ピンぼけじゃないもん影だもん(趣味:写真)

■Energia MT=マルチタスク■

EnergiaはArduino互換の開発環境ですが、MSP432P401R版はマルチタスクに対応しています。

マルチタスクというにはあまりにも単純でセマフォとかメールとかまったくありません。でも、今までのArduinoと比べれば格段に作りやすくなりました。

使い方は単純で

  • Energia IDEでタブを開き適当な名前を付ける
  • メイン同様setupとloop関数を用意するが、setupDisplay(), loopDisplay()のようにタスク名が後に続くようにするとsetup+loopのペアを別タスクとして認識する
  • メインに置いたヘッダやメイン上のGlobal変数は別タスクでも認識される

排他などについては厳密な排他制御は無理、暫定的にGlobal上にフラグを置いて自分で制御するしかありません。また、プリエンプションやタスク優先度がどうなっているのかも不明。その辺まったく情報がありません。まぁそのうち何とかなるでしょう。

ということで、とりあえず毎度お馴染みのスペクトルアナライザーをマルチタスクで作ってみました。

■材料

MSP432P401R、アンプ付きマイクAE-MICAMP、超小型グラフィック液晶AQM1284A、ブレッドボード、ジャンパ線…すべて秋月で揃います。合計4000円ぐらい? USBシリアルなども不要なのでArduino uno正規品を買うより安いです。

マイクはアナログ出力なのでドライバ等不要です。液晶についてはAQM1284AのコントローラIC ST7565RのライブラリをAdafruitさんが公開しているので、それを少し改造して使います。

FFTは大浦先生のライブラリそのままですが、M4F対応としてdoubleをfloatに置換して使用します。

以上です。

■配線■

マイクはGND, Vcc(5vが推奨されていますが出力電圧が大きくなりすぎるので3.3vにします)を接続し、OUTをEnergiaのP5.0に接続します。

AQM1284Aは以下の通りです。


AQM1284AEnergia MSP432P401R
VDD3V3
CSP3.0 / 18
RESETP2.5 / 19
RSP5.7 / 17
SCLKP1.5 / 7
SDIP1.6 / 15
GNDGND

■使い方■

各ソースは末尾に掲載します。長くてすみません。

Energiaは最新の16を使用してください。起動する前に、ST7565という名前のフォルダを作り、その中にST7565.cppとST7565.hを入れ、Energiaのlibraryフォルダに入れます。

Enegiaを起動したら、新しいプロジェクトを作り、FFTGraph_MTをコピペします。次に、ウィンドウ右上にある下向き三角をクリックして「新規タブ」を選び、TaskLCDという名前を付けてTaskLCDをコピペします(名前は何でも良いです)。

配線の点検をすませたらMSP432をマイクロUSBで接続し、Energiaでcmd+M、ビルドとプログラムの転送が終わるとグラフィック液晶に表示が出る…はずです。

なお、この作り方は厳密にいえば正しいマルチタスクではありません。TaskLCDが表示している最中にメインスレッドが表示バッファを書き換えてしまうこともありえます。でも、表示中にスペクトルが変わったとしても人間の目で追える変化ではないので、大目に見てやってください。

■毎度お馴染みのハマり■

Adafruitのライブラリの移植は、コンパイルエラーが出る→つぶす→ビルド→エラー→潰す…を淡々と繰り返すだけですが、それで終わらないのがコントラスト設定とpagemapでした。

コントラスト設定は秋月版との液晶の違いかAdafruit版だと真っ黒になってしまうのですが、Voltage Resistor Setを指定して回避できました。

pagemapはコントローラ上のページと液晶の表示位置を対応させるための表ですが、配布されているものと秋月のでは仕様が異なるようで、こんなのが出ました。左上隅から右下隅への直線がちょっと下にずれてます。64ドットで8ページ、たぶん2ページずれているのでしょう。


何度かの途中試行錯誤を経て

逆だ

なんだこれ

最終的にちゃんと表示が出ました。ここまで約1時間。



その次はマイクからの入力が常にゼロという現象が。そんなお行儀のいいアナログ入力はありえないのでしばらく頭を抱えていたのですが、これはanalogRead対応のピンにつないだつもりがanalogWriteのピンだった、というオチ。そりゃ値ゼロだわorz

FFTライブラリはつい最近使ったものなので問題なし。マルチタスク対応に関しては、奇跡的にも一発で動きました。何も難しいことしていないので当たり前ですけども、簡単なところで引っかかるのがこの私orz

でも、「自作補聴器」に今までで一番近づいたなぁ。すごいぞM4F、偉いぞM4F。