« 2018年8月 | トップページ | 2018年10月 »

2018年9月の7件の記事

Arduino制御のDSPラジオ #7 ソースコード公開

 Arduino の .ino ファイルそのものです

「dsp_radio_Exp_20180912.zip」をダウンロード

20180912_seeking 実行するとシリアルモニタに左図のような文字列がプリントされてきます。単にR/WレジスタとROレジスタの主要な部分をマルチバイトリードしてプリントしているだけです。でもこれを見ただけでも DSP ラジオ M6951 の挙動がよくわかります。レジスタ20番が6Xになっていればseek, tuneは完了していて選局できてることになります。

 でレジスタ2,3番ではNHK2が選局されていますが、レジスタ20,21番を読むと1A7h(=1134kHz)文化放送が選局されています。これはseekupをした結果なのです。前回書いた通り、ユーザーが直接選局する際に使用したレジスタ2,3番にはシーク結果は反映されず、リードオンリーのレジスタ20,21番に出てくるのです。マイコン側で常時選局周波数を把握していたい場合はここに注意が必要です。

 さてソースコードに書いたライブラリ M6951 クラスについて説明します。ほぼ見たとおりですと言ってしまいたいところですがいくつかの関数があります。

 まずクラスなのでインスタンス宣言をsetup()の手前でやります。ソースコードではdspRadioというインスタンス名にしております。で setup() の中で、beginする前に必ず Wire.begin() を入れてください。その後delay100msec してから dspRadio.begin すると AMラジオとしてDSPラジオM6951 を初期化します。戻り値は Wire.endTransmission の戻り値をそのまま返しているので、I2Cの接続状況に応じてエラーになります。

 ReadRegs()関数はデバッグ用で、上述のようなレジスタをシリアルモニタに返します。

 loop()関数の中でやっている、tuneAM, tuneFMはそれぞれバンド指定と選局を直接行っています。周波数を書き込んだ値はレジスタ2,3番を読むことで見直すことができます。それと選局状態は isTuned 関数で確認。seekup() は現在の周波数を開始位置として高い周波数の方向にシークします。これは探す時間があるので、isSeeked関数を使いながら次のシークコマンドを書き込んでいいかどうかループの中で判断しています。

 初期化直後にFMラジオにしたい場合は m_fm_en=1;などとしておいてください。m_Chan12_8, m_Chan7_0は確実に選局できる周波数を選んでおくとデバッグが楽だと思います。遊んでみてください。

Arduino制御のDSPラジオ #6 機能の探求

 ラジオといえばシーク機能!

 AM/FM それぞれを M6951 で再生できた IYN は気をよくして、それまで謎だった tune 機能とか seek 機能を使ってみることにしました。レジスタ0番の seek とか tune に1 を書き込むとプロセスが始まるとだけマニュアルに記述があって、書き込んだ後何がどうなるかの説明は一切ありません。レジスタ20番のSTCが1が立つことでtuneやseekが終了するとあります。ということは、seekやtuneに1を書く→STC=1になるまで待つ、というコードを Arduino で書いてあげる必要がありますね。

 マニュアルとレジスタをいじってみてわかったことは以下の通りになります。

  • tune…選局ができているかどうかのフラグ(レジスタ20番のtuned)を立てる機能
  • seek…自動選局した結果をレジスタ20番の readchan に表示する機能

 レジスタ2,3番でChanを指定したときもtuneフラグは動いているようではあります。IYN のArduino ソースコードでは5秒ごとにシークアップをループするようにしているので、繰り返しシーク機能を読んでいます。ここで分かったことは、seekビットは0を書き込んで1を書くとやらないと繰り返し機能が使えないということです。それにシークした結果はレジスタ2,3 には反映されず、レジスタ20,21のreadchanにのみ反映されます。

 つまりシークした選局結果はレジスタ2,3のChanを読んでもわからないのです。I2Cマスターから書き込むレジスタは、たとえ状態が変わってもDSPラジオ側では更新しない設計なのです。その代わり、リードオンリーレジスタ側はDSPラジオが常に更新している値であり、I2Cマスター側からは書き込むことはできません。

シークされた結果をreadchanから読んでみると、FMは10局くらい、AMは電波の調子が良ければ5局くらい選局できました。シークにかかる時間もほぼ1秒くらいでとても速いです。途中の周波数がどのくらいなのかを読み取る手段がありませんが、ラジオの機能としては十分ではないでしょうか。

 そのほかの機能としては、ほかのリードオンリーレジスタを読むことくらいでしょうか。RFアンプのゲイン設定値だとか、選局した局の電波強度なんかが表示されています。それとCareer to Noise Ratio の値は見ていると楽しいかもしれませんね…。

 次回は実験に使ったソースコードを公開したいと思います。

Arduino制御のDSPラジオ #5 放送の再生

 やっと音が出せます

20180911_schematicsP_20180902_165301 今までは Arduino Leonard 単体で I2C の実験をやっていましたが、とうとう M6951 と接続する日が来ました。左図の通り I2C は3, 2番端子からCLK, DATの端子に接続。外部で3.3Vのプルアップをやった方が良いですが、ここは実用性は重視しないことにしました。P-ON端子は固定で3.3[V]をつないでもよかったのですが、配線を簡単にするため0番から出すことにしました。FMアンテナはここでは省略。AMアンテナは360uHのバーアンテナを使いましたが、インダクタンスを計測すると割とでたらめの値が出てきています。スピーカーはステレオ出力させたいつなぎ方です。

20180913_sketch Arduino 側は初期化関数 begin でレジスタの値を一通り書き込んでしまいます。初期値はAMバンドを選んで、入りの良かったNHK第二をデフォルトとして選局しています。i2cWriteの戻り値については0じゃなかったらエラー処理する、というのをも少し丁寧に実装してあげてもよいかもしれません。1バイトずつ書き込めるかどうか試した履歴をそのまま残してあります。さぁこれを動かして音が出るかどうか…?

 やった、やりましたよ!なにか語学講座のようなお話が聞こえてきました。でも都内だととても音質が悪いです。ほかの電子機器のノイズがすごい。直付けスピーカーの小さな音は遠目に耳を傾けると「ジクジク、ジクジク」とザラザラな音声だけが聞こえてきます。

4 そしてライトの波形を取得してみました。おお、ACKが立ってデータが書き込まれている。まさに前回示したようなタイミングチャート通りの波形です。でもやっぱりプルアップを Arduino に任せているせいかすごく時定数が出てなまっていますね。デバイスアドレス0x10 → レジスタアドレス0x00 → データ 0x80 が書き込まれています。

5 書き込んだデータが反映されているかリード側の波形も確認です。デバイスアドレス→レジスタアドレス→デバイスアドレス→レジスタ値の順に通信されていることが分かります。マルチバイトリードについては波形を取り切れなかったけれど、バッファにそれらしい値が入っているのでうまくいっていることでしょう。

20180913_sketch_tuning IYN は気分が良くなって AM バンド選局と FM バンド選局の関数もコーディングしてみました。tuneAM は整数で kHz で選局します。tuneFMは浮動小数点第1位までのfloatで局番を指定します。レジスタ0番でAM/FMを指定、レジスタ2,3番で直接選局をしているだけです。

 FM もこれでチューニングできたので早速 82.5 MHz を受信。ああ、AM より感度よく受信できますよ。アンテナも大してつけていないのに…。繰り返しいろいろなチャネルを選局しようとコードを何度もコンパイル&書き込みを繰り返していると、I2Cの初期化に失敗しがちになっていることに気づきました。

 それを回避するのには、Wire.begin()をした後 100ms くらい待ってからI2C通信を始めるとよいみたいです。Arduinoとの間でプルアップをさぼった影響がこんなところに出ているんでしょうね。

…しばらく悦に浸っていると I2C というインターフェースが簡単に使えるようになった自負心が芽生えてきました。これなら、まだ動かしていない seek 機能も簡単に動かせるんじゃないかと…。

Arduino制御のDSPラジオ #4 続・Wire.hライブラリ実装の理解

 リード手順の方が分かりづらいので…

6 aitendoのデータシートに記されているタイミングチャートを見ると、デバイスアドレスとレジスタアドレスを書き込んで、もう一度デバイスアドレスを書き込むとレジスタの値が帰ってくるという手順が見て取れます。Arduinoのwireの使い方のページを見ると、これと同様にしているコードが書いてありました。なんで二度もデバイスアドレスを送出しなきゃいけないんだろう、飲み込みづらい…。

 これをArduinoのコードに直すと、beginTransmissionでデバイスアドレスを書き、writeでレジスタアドレスを書き、すぐにendTransmissionして、requestFromを実行するとデータ待ち受け状態になるようです。requestFrom にもデバイスアドレスが引数になっていることから、二度目のデバイスアドレス送出もマスター側の仕事なんでしょう。理解している人にとっては当たり前なんでしょうが、どう同期をとっているのかパッと見わかりづらい気がしました。

20180908 上記のホームページを参考にシングルバイトリードi2cRead関数とマルチバイトリードi2cReadBytes関数とを作ってみました。結局この関数たちは最初に書いた通りで動いたのでそのままです。シングルバイトリードは戻り値が読んだ値、もしくは0を返すようにしています。マルチバイトリードについては Wire.h ライブラリが32バイトまでバッファを持っているとのことのなので、requestFromで複数バイトを指定しています。戻り値は実際に帰ってきたバイト数です。20-27番レジスタをリードする仕様で8バイト分読む実験が成功しました。

3 左図はArduino単体でi2cRead関数を読んでみた結果です。やっぱり ACK が立ってないのでレジスタアドレスの write は成されないです。そしてstop条件に一度もどる。おそらく、requestFrom が生成しているデバイスアドレスが二度目の生成と思われます。R/~Wが立っているのでこれは納得しました。

 さて、これで DSP ラジオ M6951 にデータを送る準備はできました。次回は実際にデータ転送を実行してラジオから音が出るかどうか試してみます。

Arduino制御のDSPラジオ #3 Wire.hライブラリ実装の理解

 Arduino だと I2C が簡単って本当?

 IYN は Arduino の Wire ライブラリの記事をパッと見でまねてレジスタを書き込むコードを書いて実行してみました。DSPラジオモジュール本体とは接続しなくてもコードが動くかどうか確かめたかったのでした。しかし…どうもデータシートのような波形が取れない、なんでだろう?とハマりました。

20180908_i2c_write i2cWriteという関数を作りました。お手本の真似をすると、m_addrがデバイスアドレスで、cReg がレジスタアドレス、cDat が書き込みたいデータそのものに相当する変数名です。戻り値は一応 endTransmission の値を返してみることにしました。ところが出てきた波形はデバイスアドレスの値だけ。どういうことなんだろうと M6951 のデータシートをじっくり見ることにしました。

7 いきなり詳細のタイミングチャート図を持ち出してきましたが、IYN なりの解釈をいろいろ書き加えてみました。I2C でおそらく最低限必要なのが、この図の用語になっている start, stop, R/W, ACK といったところでしょう。このデータシートでは信号の出どころがマスターなのかスレーブなのかわからないので推測で色を付けてみました。それと上の方に Wire ライブラリの各関数の働きがどう同期しているか推測してみました。

 start 条件、stop 条件はおそらくマスター側が出力してやってると思われます。そうしないと、シングルバイトライトとマルチバイトライトとの区別がつかなくなるからです。コードに書いた cDat はおろか cReg の値も出力しないなんて、これはいったいなぜなんでしょうか。ここで手掛かりになったのが endTransmission は戻り値2を返してきます。

 つまりデバイスアドレスが有効ではないという意味の戻り値です。これだけの実装でArduino がそんな賢いことなんてあるんでしょうか。

2_2 左の画像がIYNが取得した波形です。上段の黄色が SCK で下段の緑のプロットが SDAになります。データシートを読みると、デバイスアドレス, R/~W の次に ACK というビットがあるではありませんか。この ACK はスレーブから出てくるものなんだと波形を見てようやくわかりました。IYN の波形では単に Arduino が SDA を INPUT_PULLUP モードに切り替えただけになっているので ACK は読み取れません。

 ここからわかることは Wire ライブラリは beginTransmission 関数でデバイスアドレスを出力した際に、デバイス側から ACK が返ってこないとその後の Wire.write 関数は無効にする実装になっているということです。デバイスアドレスが不正なのにバスにデータを流してしまってはスレーブたちが混乱するわけで、それを防ぐ設計になっているのですね。その結果を認識するために endTransmission では stop 条件を作るだけでなく ACK が返ってこないタイミングによって戻り値を変化させているようです。

 なるほど。そう考えると Wire ライブラリの使い方もなんとなく見えてきましたね。レジスタをリードする場合については次回論ずることにしましょうか。

Arduino制御のDSPラジオ #2 レジスタ理解

 まずはデータシートから

20180830_dspradio IYN は I2C でレジスタをたたくコードを自分で書いたことがないのでとにかくそっちに気が向いてしまうのですが、今回はレジスタを理解することによってマイコンからどのように制御するかイメージを作ることを先にやることにしました。

 結論から言うと、触る必要があるのは ReadWrite レジスタである 00, 01, 02, 03, 06, 09 レジスタの5つであることが分かりました。Read Only レジスタ(20~)は、放送局を聴くだけなら大して重要ではなく、受信状況とシーク機能利用時に必要な情報を持っています。

 レジスタ0番…power_on これは端子にもP-ONがあるのにレジスタにもある理由がよくわからず。muteレジスタもあるから音を出す出さないはこちらで制御するはず。細かい省電力設定ができるんだろうか?fm_en で FM/AM を切り替えるので重要。tune, seek, seekupはシーク機能をトリガーするときに使用

 レジスタ1番…amband, fmband にしているする値は MW2, FM4 と、これは日本国内で使うためにあるような設定でしょう。初期化時に一度だけ書けばOK

 レジスタ2,3番…Ref_32k_mode はモジュールに乗ってるクリスタルの円筒形の形状から言って32kHzでしょう。Mode3Kは一応3KHz Step, Chan[12:8], Chan[7:0] についてはシークなしでいきなり局指定するときに書くものらしい。NHK第一を初期化時に指定することにしよう。594kHz / 3 = 00C6h

 レジスタ4,5番…きっとレジスタ1番でCustom configurationを選んだ時に指定する帯域のことでしょう。デフォルト値で使用。

 レジスタ6番…volumeは24-63の40値で指定。レジスタ9番の設定で有効になります。あと、ステレオスピーカーで出力したいので phase_inv は0。配線図にROUT-LOUTでスピーカーがつないであった理由はここにあったんですな。

 レジスタ7番…Bit7がデフォルト1で0がnormal operation とあってこれは予約ビットなので触らないことにしましたが、本当は0にして使うんだろうなぁ。音質をいじったりしないのでこのレジスタはデフォルト値で使用。

 レジスタ8番…選局時にしきい値指定するところ。受信品質はデフォルトのままでよしとする。

 レジスタ9番…pd_adc_vol これを1にしないとレジスタ6番で音量制御ができないらしい。osc_en, lv_enについてはデフォルト値にしておく。

 レジスタ20、21番…チューニング状態と選局番号。レジスタ1,2番をリードしていれば、これらのレジスタをアクセスしなくとも事足りるような気もする。後日解析しますが、おそらくシーク機能実行中でないと値が変化しないレジスタと思われる。

 ほかレジスタもちょいと気になる記述もあるのですが、とにかく音が出せるか確認するなら上記くらいの内容が理解できていればいいのではないかと思います。

 次回はさっそく Arduino Leonardo と M6951 モジュールとを接続して I2C 制御プログラム実装をしたいと思います。いきなり音を出そうとするのは焦りすぎじゃないかとも思いますが、I2C は ACK を返す相手がいないとどうやらプロトコルが成り立たないのでいきなりラジオ本体とマイコンをつないでさらにオシロで波形を取得するという作戦で行きたいと思います。

Arduino制御のDSPラジオ #1

I2Cを使いこなしたくて

 IYNは以前ブレッドボード上につくるDSPラジオキットを作ってその音質の良さに感動したことがありました。それ以来いつか aitendo の DSP ラジオチップでラジオを作ってみたいと思っていました。以前から DSP ラジオのチップ単体では入手できたのですが、どうも周辺パーツをたくさん必要とするチップでは手が進みませんでした。

 そんなところに M6951 というモジュール化されたDSPラジオがあることに気づきました。aitendoの技術情報をいかに読み解くかは一種のギャンブル要素がありますがそれも今回楽しんでしまうことにしました。

 早速 aitendo に行って買ってきて Arduino Leonardo に接続してみましたが、いろいろとちんぷんかんぷんなので地道に技術情報の解読をすることにしました。aitendo なので最悪動きませんという事態も想定しておく必要があります。多数のブログでラジオとして機能していることは明らかになっているので、確率的に自分もできると感じたのです。以下はその流れです。

  1. DSP ラジオのレジスタ理解
  2. I2CとArduino側の実装との対応について理解
  3. DSPラジオとのI2C通信
  4. DSPラジオの機能探求、シーク機能実現
 といった感じで一通りのことができることを楽しんでみようと IYN は計画してみました。それぞれ何をどれだけ楽しんだかブログ中で報告していきたいと思います。

« 2018年8月 | トップページ | 2018年10月 »

2022年3月
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
無料ブログはココログ