マイコン工作実験日記

Microcontroller を用いての工作、実験記録

BTstackのHFPを動かしてみる

2015-08-12 16:09:23 | FRDM
しばらく実験の時間がとれなかったので、間が空いてしまいました。

前回の記事までで、BTstackのSPP counterをFRDM-KL25で動かしてみました。その後、BTstack用のHFP/HSPのコードもgithubで公開されていることに気がつきました。どうやらまだ開発途中のようなのですが、SPP用に用意したUSB Transport層のコードをそのまま流用して HFPを動かしてみることができるはずですので、試してみました。音声を通すためには アイソクロナス転送のコードを追加する必要がありますが、その部分は後回しにすることにします。

HFPのコード本体はsrcディレクトリの下に含まれていましたが、サンプルのプログラムはexampleの下には無く、test/ptsの下に入っていました。PTSというのはプロファイルチューニングスイートのことですね。この試験ツールを使ってBTstackの検証を進めているのでしょう。

http_hf_test.cは、そのままではアドバタイズしないので、ちょっとコードに手を加えてスマホからデバイスを見つけられるようにしました。



それらしいCOD (Class of Device)も設定されているようで、ヘッドセットマークが表示されています。



ペアリングを開始すると、ちょっと時間がかかりはするのですが.....



メデタく接続成功!! なんかあっさりと動いてくれました。しかし、ためしに端末側から切断してみたところ、どういうわけか切断ができませんでした。端末側のBluetoothを落とすとちゃんと切れるのですが、HFP切断の手順が走ってくれていないようです。

接続時のログを採ってみると。



HFPのチャネル(#1)で RFCOMMが開いた後に、SLC (Service Level Connection)を確立するためのATコマンドが送受されている様子がわかります。AG側から受信したコマンドはデコードの様子として表示されています。

試しに着信を入れて、応答してみます。


応答にともなって SCO (Synchronous Connection)が開かれ、切断すると閉じられていることがわかります。このイベントを捕まえて、USBのアイソクロナス転送をおこなってやれてば、通話音声がひろえるはずです。着信の際のログが気になって調べてみましたが、相手側の発信者番号が通知されていないようです。SLCを開いたあとで、AT+CLIPを送っていないのが原因のようです。おそらく、HFPのスタックは最小限の機能になっているのでしょう。CLIPについてはアプリ側で実装してやる必要があるようです。

USB_LDDを使ってみる -- 解決編?

2015-07-26 15:17:11 | FRDM
前記事ではコントロール転送とインタラプト転送が同時に動かないで悩んでいたのですが、対処方法が見つかってあっさりと動いてしまいました。

SSPではコントロール転送、インタラプト転送に加えて、バルク転送も必要となるので、バルク転送のパイプも追加で開いて読み取りを始めたところ、なんと全ての転送が順調に動くようになってしまいました。もしかすると、インタラプト転送を使うためにはバルク転送も併用しないといけないというようなバグがドライバに潜んでいるのかもしれません。参考までに、各パイプを開くために使ったディスクリプタ定義を残しておきます。
LDD_USB_Host_TPipeDescr Pipe1Descr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    1,                  /* EP number */
    LDD_USB_DIR_IN,     /* EP direction */
    LDD_USB_INTERRUPT,  /* EP Transfer type */
    16,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    1,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

LDD_USB_Host_TPipeDescr Pipe2InDescr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    2,                  /* EP number */
    LDD_USB_DIR_IN,     /* EP direction */
    LDD_USB_BULK,       /* EP Transfer type */
    64,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    0,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

LDD_USB_Host_TPipeDescr Pipe2OutDescr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    2,                  /* EP number */
    LDD_USB_DIR_OUT,    /* EP direction */
    LDD_USB_BULK,       /* EP Transfer type */
    64,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    0,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

USB_LDDのAPIでは、インタラプト転送やバルク転送の読み取りは、転送が完了するかエラーが発生するとコールバックがかかります。デバイス側からの読み取りデータが無い場合にはNACKが返ってきますが、その場合にはドライバが次のフレームで再度INトークンを送出してくれます。この周期処理はドライバが面倒を見てくれますので、アプリケーションでは、転送が完了した場合には再度読み取りを開始してやればいいことになります。

こうして無事にBTstackが動いてくれました。

BTStackが立ち上がった状態では、ペアリング待ちになっていますので、スマホからペアリングしてやります。




ペアリングが完了したらスマホからSPPで接続してやります。。






SSP counterアプリケーションは、毎秒インクリメントしていく数字を出力するだけの単純なアプリですが、その動作を確認することができました。

SPP counterは比較的あっさりと動いてしまいました。当初、ペアリングの途中でハングしていたのですが、BTstackタスクに割り当てるスタックが不足していたのが原因でした。




USB_LDDを使ってみる -- その3

2015-07-20 20:53:29 | FRDM
USB_LDDをつかってBluetoothドングルのエニュメレーションまではできたので、いよいよBTstackを動かし始めます。入門編としては、SPPをつかうspp_counterというサンプルを動かしてみるというのがお約束のようなので、まずはこれを動かすことにします。

BluetoothのUSBトランスポートでは、コマンドの送信にコントロール転送、Bluetoothからのイベントの受信にインタラプト転送、ACLリンクのデータ送受にバルク転送、そしてSCOリンクの送受にアイソクロナス転送と、USBの各転送方式を全て利用しますが、SPPであればアイソクロナス転送は必要ありません。BTstackが動くとHCIでコマンドを送信して、それに対する応答がドングルからインタラプト転送で返ってきますので、まずはこの部分の動作を確認することにします。新たにインタラプト転送のパイプを開いてやり、そこからの読み出しを開始しておき、パイプ0にHCIコマンドを送ってやります。


ところが、最初の2つ、3つのコマンドに対してはちゃんと応答が返ってくるのですが、その先に進んでくれません。どうやらパイプ0にコマンドを送信した後の、送信完了コールバックが動いていないようです。

USBの動きとしては、1ms間隔でインタラプト転送によるイベントの読み出しがかかる中で、コントロール転送によるコマンド送信が発生するという動作になります。そこで試しに、コントロール転送でコマンドを送信する際には、進行中のインタラプト転送をUSB1_HostCancelTransfer()を使って いったん止めてからコマンド送信をするようにしてみました。すると、


初期化に必要な一連のHCIコマンドが送信され、それに対する応答が返ってきてBTstackがちゃんと立ち上がるところまで進みました。

このようにコントロール転送とインタラプト転送を同時に動かさなければちゃんとBTstackが立ち上がるのですが、この先ではACLリンクの送受もしたいので、やはり複数の転送を同時に動かさなければSPPを動かすことができません。Processor Expertの生成したドライバコードをざっと見たところでは、複数のパイプを同時に使うことを意図して作られているようですので、何か使い方が悪いのか、生成されたコードにバグが潜んでいるかのいずれかだろうと思われます。そういうわけで、USBのコードを追いかけることになってしまいました。

USB_LDDを使ってみる

2015-07-10 22:32:58 | FRDM
Kinetisでは、KSDKの一部としてUSBのプロトコルスタックが提供されています。実験的にプロジェクトの構成を試してみたのですが、RTOSとしてMQX Liteを選択するとメモリ管理プリミティブが不足しているために構成できないというエラーが発生してしまいます。どうやら、MQXかFreeRTOSを使う必要があるようです。KSDKのホストスタックにおいてもBluetoothのクラスドライバが用意されているわけでもないので、どのみちその部分は作らねばなりません。そこで、KSDSKを使わずともKDSのPEXコンポーネントとして用意されているUSB_LDD (USB Logical Device Driver)を使ってホスト機能を実装してみることにしました。




PEXを使ってUSB_LDDのコンポーネントを追加して、そのプロパティーを適切に設定した後、コード生成を行ってやれば、基本的なUSBホストドライバのコードが自動的に生成されます。ここまでは、非常にお手軽なのですが、問題はこのLDDの使い方について詳しい説明が無いことです。サンプルのプロジェクトとかがあればいいのですが、そのようなサンプルはみなKSDKに含まれるFreescaleのUSBスタックを使っており、USB_LDDとは別のAPIになっているようです。いちおう、USB_LDDのヘルプに簡単な使い方の例が示されているのですが、その例ではドライバの初期化とコントロール転送でSETUPを送るところまでの例しか示されていません。




このサンプルは、デバイスディスクリプタの最初の8バイトだけを読み取るというものなんですが、エニュメレーションの続きの具体例が示されているわけでもないので、自分でAPIの説明を読んで試してみるしかありません。とりあえず、例示されている部分のコードをそのまま書き写してビルド、実行してみたのですがPipe0を開こうとするとエラーになってしまいます。調べてみると、ホストスタックの初期化作業としてバスリセットをやっている際中にPipeを開こうとしてしまうのが原因でした。初期化後ポートの状態がリセット完了になるまで待つコードを追加してやると、正しくSETUPが送られて、ディスクリプタの最初の8バイトが読み取れることがわかりました。

出だしからこの調子なので、これはしばらく楽しめそうです。

FreemasterでScope表示してみる

2015-02-22 09:46:44 | FRDM
FRDM-KL25Zには3軸加速度センサーとしてMMA8451Qが実装されており、同センサーを用いた実験を簡単に行うことができます。センサーを用いてイベントを検出するには割り込みを発生させるための加速度閾値の設定などが必要となることもしばしばありますが、それらの設定値を求めるには検出したいイベントに対応する加速度出力値の変化を把握しておくことが重要です。そのため、センサーの出力値をモニタしてグラフ表示してくれるツールがあると便利です。以前MMA8452Qを実験した際には、いったんフラッシュに記録したデータを読みだしてExcelを使ってグラフを表示していました。今回、FreescaleがFreemasterというツールを提供していることを知ったので、これを使ってみました。下図のグラフはFreemasterを使って取得したものです。




Freemasterのおおまかな機能や使い方については、次のページが参考になりました。
わたしなりに説明させてもらうと、Freemasterはデバッガの変数Watch機能を独立したアプリとして仕立てて、その値のリアルタイムな変化をグラフ表示する機能を付け加えたものです。アプリのシンボル情報から指定された変数のアドレスを求め、デバック用インターフェースを介して、その値を定期的に読み取って表示してくれます。ターゲットとのデバックインタフェースは用意されているプラグインから選択することができ、次のような種類がサポートされています。



わたしはOpenSDAをJ-Link化しているのでJ-Linkを選択していますが、BDM Communication を選択すればもともとのOpenSDA Debugインターフェイスも使えるようです。またCMSIS-DAPに対応しているので多くのマイコンボードでも利用可能なんじゃないでしょうか。RS232シリアルも使えますが、この場合にはターゲット側で対応ドライバのコードを組み込むことが必要となるようです。

シンボル情報は、ELFファイルから取得できます。したがって、Freemasterを使うために特別な作業は必要ありません。ただし、アドレスを確定させるために、表示したい変数はグローバル変数でなければなりません。シンボル情報から自分が表示したい変数を選択して設定しますが、その手順の説明は省略。上述の参考リンクを参照してください。

実験には単純に800Hzでサンプリングした3軸加速度データをXout, Yout, Zoutという変数に格納するだけのアプリを作成しました。ビルドしたELFファイルデータをFRDM-KL25に書き込んだら、今度はFreemasterを立ち上げて上述のようにシンボル情報を読み込みます。値を表示したい変数を選択して、Freemasterとターゲットとを接続するボタンを押せば動き始めます。



手でボードを持って、Z軸方向に何度か振ってみた場合の動作時画です。右下のウィンドウに選択した変数 Xout, Yout, Zoutの値が表示されています。記事の最初に載せたグラフはHigh pass filterを有効にした際のものですが、こちらの例では無効にしています。そのためZoutの値が1024(1g)程度になっています。



X-Yモードでも表示もできます。この例ではボードを手に持ちほぼ平らな状態にしてから、X軸方向に +/-90ずつ回転、その後Y軸方向も同じように+/-90度回転させてみました。Z方向を横軸にとり、X, Y方向の重力加速度の変化が軌跡として表示されています。

このようにFreemasterを使うと簡単にデータを表示、視覚化することができます。
  • プログラム側では単にデータをグローバル変数として持てば良いだけであり、それ以外の準備は何もいりません。
  • 上記の例ではターゲットとしてFRDM-KL25Zを使っていますが、J-Link, CMSIS-DAPというJTAGインターフェイスに対応しているので、実際のところターゲットのマイコンはFreescaleのKinetisに限らず、なんでもいいことになります。これらのJ-TAGではFreemasterの持つコマンド送信機能などは使えないのですが、スコープ表示はできます。
  • LPCXpressoなどが生成するaxfファイルはそのままではFreemasterでは開けませんが、elfにrenameすれば開くことができます。
  • シンボル数が多かったり、おおきな配列がある場合に、シンボルの選択操作が使いにくいのが難点ではあります。最大の問題はWindowsでしか動かないということでしょうか。

手軽に使えて重宝しそうなツールです。お試しあれ。

RX-8025NB

2014-12-30 18:35:45 | FRDM
温度/気圧の記録で使用するために、RTCとしてRX-8025NBを追加しました。



KL25にはRTC機能が備わってはいますが、FRDM-KL25Zでこの機能を使うためには
  1. 外部の32KHz発振器をクロック源とする。
  2. 内臓の1KHz LPO発振器をクロック源として使用する。
のいずれかの方法をとる必要があるようです。KL25はクリスタル接続用の端子を一組しかもっていないので、メインのクロック発振用とRTC用のクリスタルのふたつを別々につなぐことができないためです。LPO発振器は時計として使うだけの精度はありませんので、やはりクリスタルを使いたいところです。FRDM-KL25Zではメインのクロックとしてすでに8MHzのクリスタルがつながっているので、RTC用のクロックは別に用意しなけれなならないのです。

32KHzの発振器を探してつなげればKL25Z内臓のRTC機能を使うことができますが、入手性と消費電流の少なさからRX-8025NBを使うことにしました。

どうやらKinetisではKLシリーズのMCUはどれも、クリスタル発振器はひとつしかつなげられないようです。KL25では32Kクリスタルを発振させてシステムクロックとして使用することも可能ですが、そうするとUSBに必要な48MHzが作れなくなってしまいます。

消費電流確認

2014-12-21 22:59:02 | FRDM
M24SRへの書き込みは問題無くできるようになったので、ボード全体の消費電流を確認しておくことにしました。これまでは動作状況確認用にOpenSDAの仮想COMポートを使ってメッセージの出力をおこなっていましたが、電池動作させるためにはこれを止めるようにせねばなりません。すでに先の記事にも書いたようにJ3のジャンパを用意してありましたが、この記事によればJ14とJ20もカットする必要があるとのことなので、対処しておきました。また、この記事と同じく内蔵CR発振器を使って生成したクロック4MHzで動作させ、VLPRモードで計測を実施しています。計測間隔は30秒に1回で、その間はSTOPモードに遷移してDeep Sleepさせています。

秋月の大気圧センサーモジュールには、通電されていることを表示するLEDが実装されていますが、消費電流の観点からすれば常時点灯するLEDなんて大飯ぐらいなので、除去しちゃいました。また計測時間待ちの間はセンサーもパワーダウンモードに設定することで消費電流を節約します。




消費電流はもう1枚のFRDM-KLZ25ボードから3.3Vを供給することで計測しました。



UART出力を使わなくなったこともあり、Deep Sleep時のボード全体での消費電流もおよそ13uAに抑えられています。これなら電池で動かしても心配ありません。

温度と気圧をメータ表示する

2014-12-10 12:25:08 | FRDM
M24SRへの書き込み方がわかったので、LPS25Hで計測した温度と気圧を書き込んでみました。単純にテキストで温度と気圧を表示しただけではつまらないので、チョットだけ手を加えてメータ風に表示してみました。Nexus 7をタグの上にかざすと、ブラウザが開いて温度と気圧をメータ表示してくれます。



M24SRに書き込んでいる内容は、Smart Poster形式のNDEFデータです。これは、タイトル文字列を持つテキストと、表示すべきページのURLのふたつのデータを持つ複合データ形式です。これをわたしのNexus 7で読み取ると、書き込んであるURLのWeb ページが表示されます。タイトルの方は表示されないのですが、あらかじめ起動しておいたアプリで読み取るとタイトルが表示されることもあるようです。

メータ表示はブラウザにやらせており、Nexus上に特別なアプリは必要ありません。実際にタグに書き込んでいるデータは次のようなURLです。

http://sirius506.chips.jp/ptest.php?temp=19.43&hpa=1017.54

サーバ上のPHPスクリプトに気温と気圧のデータを渡しているだけですので、マイコン側では何も描画に関わる処理はしていないことになります。あとはすべてサーバとブラウザにお任せというわけです。




サーバ側の処理も手抜きしてあります。メータ表示にはGoogle ChartsGaugeを使用しており、ほとんどサンプルコードをコピペしたようなものです。

現在10秒おきに計測をおこない、タグの内容を更新しています。室内の気温と気圧なんてそんなに頻繁に変化するわけではないので、30秒とか1分間隔でも充分かとも思います。M24SRにはRFでのセッションが開いたことを検出して割り込みをかける機能も用意されています。これを使えば、通常はスリープさせておき、割り込み信号でWakeupさせてから計測をおこなってタグデータを更新するという方法も考えられます。

M24SRを追加

2014-12-04 22:54:43 | FRDM
電池駆動のお膳立てはできましたが、前記事で書いたようにOpenSDAが使えないのでなんらかの出力表示方法を用意せねばなりません。そこで、今回のプロジェクトでは、こいつを投入することにしました。



積み基板となっていたM24SRです。I2CでつながるNFCタグです。今回は、LCDのような表示器は用意せず、気圧や温度のデータはNFCタグに書き込むことにします。それをスマホやタブレットで読めば、表示装置は不要になるというわけです。

以前、Bluetoothのペアリング用にTIのRF430CL330Hを使いました。TIのタグはRAMでデータを保持していたので、タグを動作させるためには電源を供給する必要がありました。M24SRは不揮発性メモリにタグデータを保持するうえに、RFで受ける電力だけで動作することができます。したがって、いったんタグデータを書き込んだら、マイコン側の電源を落としてしまってもかまいません。

M24SR基板を積み重ね。うーん、3段はチィっと見苦しいな。




M24SRへのデータの書き込み方を調べて、ソフトを書き始めたところです。

電池駆動の準備

2014-11-29 13:44:45 | FRDM
FRDM-KL25ZボードはCR2032電池でも動かすことができるようにPCBが設計されています。しかしながら、実際に電池で動かすためにはいくつかの部品の追加実装とジャンパ加工が必要となります。マニュアルを読めばちゃんと説明もあります。

まずはCR2032用の電池ホルダーを実装。BOMを確認するとKeystoneの3003という電池ホルダー用にPCBパターンが用意されています。探してみたところRSオンラインにて取り扱いがあったので、これを購入。ホルダー自体にはプラス電極側しかありません。マイナス電極はPCBパターンにて用意されているのですが、電池との接触を確実にするためにホルダーを半田付けする前に、PCBパターンのマイナス電極に薄くハンダをのせておくのが注意ポイントです。



つぎにD7のバリアショットキーダイオードを追加実装。こいつを入れないと電池がつながりません。大きさがパターンに見合うRB160M-30TRを使いました。



そしてR74を取り外して、J3にジャンパピンを実装。このジャンパをオープンにすることでOpenSDAへの電源供給を止めます。OpenSDAのUSBをPCにつないで動かした場合、このジャンパで電流を測ると約20mA流れています。電池で動かした場合も、このジャンパがクローズされているとOpenSDAのMCUは動いてしまい、約5.3mAを消費してしまいます。そのため、電池駆動時にはJ3をオープンにしておく必要があります。



OpenSDAが動かないとUSARTの仮想COMポートも使えなくなってしまいますので、気圧測定結果を出力する方法を別途用意せねばなりません。LCDを追加するのが一般的な方法ですが、今回は別の方法を取るつもりです。