■ホビーロボット部品の製造・販売 
  モータコントローラ、センサ、音声、画像、無線モジュールなど、
■ホビーロボット制作記事のページ (各種マイコン、PCとの接続事例)
■特殊メイク、特殊材料の販売 ※特殊メイクのコーナーはこちらに移りました。
Top(お知らせ) 製品紹介 使い方とサンプルプログラム 通信販売 リンク ロボット掲示板 会社案内
 Easy Robotics for all enthusiastic people!!!  ---HOBBY ROBOT PARTS SHOP ASAKUSAGIKEN---   Since 2003...

A33Fで音声入出力

(DCI(PCM)/I2Cの使い方)

はじめに

 
dsPICマイコンボードA33Fには携帯電話などに使われるオーディオサブシステムIC「LM4930」が実装されています。音声データはdsPICのDCI機能でPCMデータをやりとりします。また、LM4930の設定はI2Cインターフェイスを使って行います。

 

 ※このページで紹介する内容はあくまでも一例です。個別の作成のご相談ご質問はお答えできませんのでご了承下さい。このページと同じ内容についてのご質問についてはロボット掲示板にてお願いいたします。

 ※以下の情報は2007年11月現在のものです。ご注意ください。



注意)

音声入出力を行うには、A33Fマイコンボード以外に、マイク(ノートPC用か携帯電話用)とスピーカー(8オームスピーカー、もしくはD級アンプなどの音声出力装置)が必要です


オーディオサブシステムIC LM4930の概要


 LM4930は主に携帯電話向けに作られたオーディオICで、マイクからの音声をデジタルデータに変換したり、デジタル音声データを変換してスピーカーを直接駆動したりすることができます。また、入出力のゲイン(増幅率。この場合ボリュームのようなもの)もコントロールできます。よって、ロボット作成時の耳や口の機能を作ることが可能となります。

 以下、概略です。

・16ビット分解能48kHzDAC(チップ自体はステレオですが、A33Fではモノラルのみ接続)
・16ビット分解能8kHz音声コーデック
・設定はI2Cで行う
・音声はPCM音声データシリアルインターフェイスで行う(dsPICのDCIと接続可能)
・8オームスピーカーアンプ(300mW)
・32ステップのボリューム調整が可能なアンプ出力
・マイクロフォンアンプのゲイン設定が可能

 下はLM4930のブロック図です。ピンクの部分がA33Fで使用できる部分です。


 LM4930のデータシートはこちら

 LM4930のデータシート

 開発経験のある方でしたらデータシートと回路図を参照すれば使い方はわかるかと思います。このページではビギナー向けに、音声の入出力を行う場合のサンプルプログラムをご紹介します。


回路図

 A33F上の回路はこのようになっています。

※回路が変更になり、マイク端子の1番にMC-Nが、マイク端子の2番にMIC-P端子がつながれており、マイク端子3番はNCになっています。製品に添付の回路図が正しいのでそちらを参照願います。



 dsPICのDCIインターフェイスと、LM4930のPCMインターフェイスがつながっています。ここで音声データをやりとりします。I2CはdsPICからLM4930を設定するのに使います。その他に、マイク入力端子とスピーカー出力端子が出ています。
LM4930にはヘッドフォン端子や、I2S端子もありますが、これらはA33Fでは未接続になっています。ステレオでの音声の取り扱いはできません。


LM4930の設定方法

 LM4930はI2C(アイ・スクエア・シーと読む)インターフェイス経由で設定を行います。I2Cはクロック線1本とデータ線1本で行う同期式シリアル通信の一種で、主にマスタ側から子機の設定を行う場合によくつかわれるもので、LM4930には設定用レジスタが3個ありますのでそれらに対して値をセットして設定を行います。I2Cの具体的な通信については後ほど説明します。

 LM4930には次の3つの設定用レジスタがあります。

レジスタ名 アドレス番号(*1) 機能
BASIC CONFIG 0010000 動作モードと、PCMのデータ形式を設定
VOICE/TEST CONFIG 0010001 サイドトーン(*2)、ミュートなどの設定
GAIN CONFIG 0010010 スピーカーとマイクのゲイン設定(*3)

(*1)LM4930のADDR端子はハード的にLOWになっていますので、このアドレスで固定です。7ビットの2進数で表しています。変更不可。ADDR端子についてはLM4930のデータシートを参照願います。
(*2)サイドトーンは電話や会議システムで使うもの(マイクに入った自分の声をヘッドフォンに少し出して話しやすくするもの)なので、設定は可能ですがA33Fのハードウェア構成では意味がありません。
(*3)ヘッドフォンのゲイン設定もここで行いますが、ヘッドフォン端子は接続されておりません。

以下、データシートよりレジスタの設定部分を抜き出して若干編集したものです。









 I2Cのタイミング波形。詳しくは後ほど。
 



はじめてdsPICのI2C機能を使う場合

 I2Cは初めて使う方もいるかと思います。dsPICのドキュメントの場合、ハード的な部分はdsPIC33Fのデータシートに書いてありますが、I2Cの説明及びどのような手順で初期設定したらよいかは「dsPIC30Fリファレンスマニュアル」の方に書いてあります。現時点では33Fのリファレンスではなく30Fの方しかないようです(このあたり、結構ハマる要因。)30Fと33FのI2Cは同じ構造のようですが、レジスタ名が若干(I2CxxxがI2C1xxxとなるパターンが多い)違ったりします。このページではLM4930を設定するだけの部分を紹介しますが、詳しくは下の2つのメーカーのドキュメントを参照願います。

 dsPIC33FDataSheet.pdf

 dsaPIC30FReference.pdf



I2Cの説明

 I2Cはフィリップス社が開発した通信方式で、主にEEPROMなどの基板上のIC同士のような近距離を通信する用途のクロック同期式シリアル通信です。マスタとスレイブにわかれて、マスタが主導で通信をおこないます。1ラインに複数の装置を接続して通信することもできます(今回は1対1の通信)。通信速度は100Kbps又は400Kbpsに決まっています。

 I2Cの端子はSCLとSDAの2本があります(その他にGNDを共通にする)。SCLはクロック信号で、通信のタイミングを制御します。SDAはデータ線です。SDAはマスタからスレーブへ通信することもあり、スレーブからマスタへデータを返すこともできる双方向な信号線となっています。

 概略図は下の通り。SCL、SDAとも双方向通信をする(このページではSDAだけ双方向)ために端子はオープンドレインになっております。オープンドレインなので線はプルアップ(抵抗を付けて通常はHIGHにする)する必要があります。

 

 ということで、待機時はどちらの線もHIGHに固定されています。下の図はdsPIC30Fリファレンスの図21-3です。21章はI2Cについて書かれています。この(I)が待機時の部分です。どちらもHIGHになっています。待機=IDLEなので(I)?

 

<スタートコンディション>
 通信は、マスタ側でSDAをHIGHからLOW(SCLはHIGHのまま)に変化することで開始されます。これを「スタートコンディション」といいます。上図の(S)の部分です。

<データ通信>
 データ(アドレス)は(D)のようにSCLがHIGHの時の値が有効となります。逆に(Q)のようにSCLがLOWのときはSDAの値を切り替えるタイミングです。

<エラー判定>
 データは通常8ビットで送られます。大抵のI2C機器では初めの8ビットは7ビットアドレスプラス、読み込みか書き込みかを表す1ビットを追加したもの、という仕様が多いです。8ビット送信を終えると送信側はSDAラインの制御をを受信側にあずけます。受信側は正常通信された場合はSDAをLOWにします。これをACK(アックと読む、アクノリッジの略。OKの意味)と言います。信号線はプルアップされていますので、意図的にLOWにしないとHIGHになったままです。つまり、受信側が実はつながっていかったり動作していなかった場合はこのACKを返せないのでSDAはHIGHになったままです。問題があり、SDAをLOWにできなかった状態をNACK(ナックと読む、ノンアクノリッジ、NGの意味)と言います。

 場合によってはこの後、再度スタートコンディションにして次のデータを送る、という場合もあります(スレーブのチップ仕様による。)。今回のLM4930の場合はACKの後、さらに続けてデータを送信します。

<ストップコンディション>
 通信が終了したら、SCLがHIGHの状態でSDAをLOWからHIGHに変化させます。上図の(P)の部分です。これをストップコンディションと言います。

 ここで、もう一度LM4930のI2Cの波形を見てみます。LM4930は3つの16ビット幅の設定用レジスタがあり、これらは”書き込み専用”となっています。レジスタのアドレスは7ビット構成です。下の図を見ると、3バイトのデータ送信でレジスタの設定をするということが読み取れます。
1)まずスタートコンディションを作り、
2)レジスタのアドレスと、リード/ライトビットを送り、
3)データの8−15ビットの部分を送り、
4)データの0−7ビットの部分を送る。
というのが1設定のサイクルのようです。
この図ですが、ちょっと誤解しそうな書き方ですが、書き込み(Write)の場合はR/W(Wの上に線がある)の表記のように1のときRで0のときWです。波形はR/WのときにHIGHになっているような波形になってますが書き込み(W)は0なのでLOWです。同じく、ACKも図では波形が立ち上がってますが、LOWがACKなので注意してください。

<LM4930のI2Cの波形>


 これは、後で行うプログラムの実行時のSDAとSCLの波形です。通信速度は100Kbpsに設定されています。例として、BASIC CONFIGレジスタ(アドレス:0010000)に0x0402の値を書き込んでいます。最初の1バイト目はレジスタのアドレスにR/Wの1ビットを追加したものです。上の図と下の波形写真はSCLとSDAの位置が上下逆になってますので注意してください。
 

 通信に問題があると、ACKが出ない、つまりACKのタイミングのビットが0にならない状態になります。次は通信ができない場合の波形です。信号線はプルアップされているので、相手先に接続されていない場合もこのようにNACK状態となります。
 


dsPICのI2Cの使い方

 daPIC33FにはI2C1とI2C2の2つのI2Cポートがあり、LM4930にはI2C1が接続されています。I2C1を動かす場合に使う特殊レジスタには次のものがあります。

レジスタ名 名称 機能
I2C1BRG ボーレートレジスタ 通信速度を設定
I2C1CON1 制御レジスタ 設定、(S)や(P)コンディションを発行など
I2C1STAT 状態レジスタ I2C1の状態を表示
I2C1RCV 受信バッファ 受信時に使用
I2C1TRN 送信バッファ 送信時に使用
I2C1ADD アドレスレジスタ スレーブとして動く場合のアドレス(今回は使用しない)
I2C1MSK アドレスマスク スレーブとして動く場合に使う(今回は使用しない)

 今回、dsPICとLM4930は1対1でつながっており、dsPIC側でコントロール、つまりdsPIC側がマスタとなります。dsPICがマスタとして動かす場合の手順は30Fリファレンスの21章の「21.5シングルマスター環境でマスターとして通信」のところに詳しい動作フロー(流れ)が書いてありますのでこちらを参照願います。また、dsPIC33Fのレジスタとその中身の名称は33Fデータシートに書いてありますのでそちらを参照願います。

 以下、LM3940の設定(書き込み)をする場合に必要な部分を抜き出して紹介します。

<初期設定>

 I2C1CONレジスタの値は起動後は全部0になっています。この状態ではI2C1は動かない状態ですが、I2CCON1のSENビットを1にすることでI2C1を使えるようになります。その他はデフォルト(初期)設定のまま0でかまいません。ちなみに、アドレスビットはdsPICの場合7ビットか10ビットに設定できます。LM3940のレジスタアドレスは7ビットなので7ビットに設定します(起動時は7ビットなのでそのまま)。

 次に通信速度の設定をします。通信速度はI2C1BRGに下の計算式でもとめた値を書き込みます。FCY=36.85MHzです。(FCY:動作クロックについては前の方のページに書いてあります。)
(33Fデータシート18章より)
FSCLが通信速度なので、たとえば100Kbpsの設定だとすると
((36.85x1000x1000)/(100x1000)) - ((36.85x1000x1000)/(1111111)) - 1 = 約334 となります。

 ということで作った初期化関数が次のようになります。init(ial)は初期化の意味です。
 


<LM4930のレジスタへ値を書き込む>

 次は指定したアドレスへの送信です。

 まず、スタートコンディションを発行します。これはI2C1CONレジスタのSENビットに1を書き込めば自動的に実行されます。スタートコンディションが発行し終わったらSENは自動的に0クリアされますので、SENに1を書き込んだ後にSENが0になるのを監視していればスタートコンディションが発行し終わったかどうかが判定できます。

 データを送る場合はI2C1TRN送信バッファに値を書き込むと自動的に8ビット分のデータが送信されます。データ送信時はI2C1STATレジスタのTRSTATが1になります。8ビット分送信して、さらにACKを受け取るクロックを1つ発生させたらTRSTATが0になり、送信終了が判定できます。きちんとACKが帰ってきたかどうかは、I2C1STATレジスタのACKSTATに結果が入ります(ACKなら0、NACKなら1)のでそれで判定できます。(今回はこの部分は省略。)

 ICの種類によっては、1データを送ったあとに再度スタートコンディションを発行する仕様のものもありますが、LM4930はそのまま2バイト目を送るようです。上と同じ手順で、つづけて2、3バイト目を送信します。

 全て送信終了したら、ストップコンディションを発行します。これはI2C1CONレジスタの
PENビットに1を書き込めば自動的に実行されます。スタートコンディションが発行し終わったらPENは自動的に0クリアされますので、PENに1を書き込んだ後にPENが0になるのを監視していればストップコンディションが発行し終わったかどうかが判定できます。

 LM4930は、2バイトの設定値を受け取ると、すかさずその値により動作モードを変えるなどの設定を実行します。
 
 この部分をプログラムにしたのが次の部分です。
 

 全体のプログラムについては後ほど。


音声データのやりとり、PCMについて

 音声データはPCMというものでやりとりします。PCMはPuls Code Modulationの略で、音声などのアナログ信号をサンプリングしてデジタル値に直して記録する、というものです。たとえば、マイクからの音声信号はマイコン内部のデジタル信号とは違い、波打ったような波形になっています。それを決められた時間の間隔ごとにアナログデジタル変換(ADC)して数値データにします。

 A33Fに搭載されているLM4930は常時PCM信号を出しています。設定にもよりますが、マイクからの音声信号を1秒間に8千回の間隔で16ビットの数値に直して出力しています。また、PCMポートへ一秒間に八千回の間隔で16ビットデータを元にスピーカー駆動信号を発生させます。
 一秒間に何回測定するか、をサンプリングといい、この場合は一秒間に八千回なので「サンプリング8KHz」となります。

 下は実際にLM4930から出ている波形の一部です。緑が同期信号でデータの送信開始を表しています。黄色が常にLM4930からdsPICに対して出されている信号です。このクロックはLM4930につながっている12.288MHzの水晶を元に作られています。緑の方の同期信号の間隔を見ると、約124uS毎、つまり 1/124x1000x1000 = 約8KHz の間隔で16クロックのデータつまり16ビットのデータを送っている(受け取っている)のがわかります。
  

 下はLM4930のデータシートからの抜粋です。PCM_SYNCというのが同期信号(上の緑)で、この図を見るとPCM_SYNCの次のクロックからデータを送信(受信)し始め、MSB(最上位ビット)から送信されるというのがわかります。データはクロック(PCM_CLK)の立ち上がりで変化し、立下りの時に1ビットを送信(受信)動作すればよいことがわかります。
 


dsPICでのPCMデータの扱い、DCIについて

 dsPICにはデータ変換器モジュール「DCI」というものがあり、PCM、I2S、AC-Link方式のデータをやりとりすることができます。このデータのやりとりはdsPICのCPUの動作とは切り離して自動的に行うことができるのでCPUを占有することなく音声データを録音したり再生したりすることができます。実際には、1データ(16ビット)を送信(受信)終えた段階で割り込みが発生しますのでその瞬間だけ、データをセットしなおしたり受け取ったデータをメモリに記録したりします。

 dsPIC33FのDCIの使い方もdsPIC33Fデータシートを読んだだけでは足りず、dsPIC30リファレンスマニュアルの方も見ないと使いこなすことはできません。2つのドキュメントにはPCM以外の方式についても多数書いてありますので読みきるには非常に労力がかかりますのでここではLM4930を使う部分だけを抜粋して説明します。


 DCIを使うには次のレジスタを使います。


 DCICON1 : DCIの基本的な設定

 DCICON2 : 
DCIのワード長などの設定

 DCICON3 : dsPICがマスタの時に出すクロックの制御(今回はdsPICはスレーブなので使わない)

 DCISTAT : SCIの状態レジスタ

 RSCON : 受信スロットの選択

 TSCON : 送信スロットの選択


 詳しくは各ドキュメントを参照してください。以下ポイントだけ説明します。

 基本的にはDCICON1、DCICON2、TSCON、RSCONを設定し、割り込みを使う場合は割り込みを許可(IEC3レジスタのDCIIEを1にするとDCI割り込みが発生)して、DCIをONにします。DCIを動かすにはDCICON1レジスタのDCIENを1にします。A33FではdsPICのDCIポートは音声処理ICのLM4930のPCMポートにつながっていますので、DCIはPCMの設定にします。LM4930のPCMはサンプリング8kHzで16ビットデータになります。このあたりの設定は次のプログラム例で説明します。

 DCIがどのようなタイプのデータを扱うかはDCICON1のCOFSMビット(2ビット)で設定しますが、ここにはPCMとは書いてありませんが、マルチチャンネルモードの仕様がPCMと同じなのでマルチチャンネルモードを選びます(初期設定でマルチチャンネルモードになっていますが)

 ドキュメントにはdsPICがマスターの場合を中心に解説されていますが、A33Fの場合はLM4930が8kHzのフレーム同期クロックを生成しますので、dsPIC側がスレーブになります。DCICON1のCOFSDを1にするとdsPICのフレーム同期端子が入力になり、自動的にスレーブになります。

 LM4930がフレーム同期パルスを出すと、dsPICの方で割り込みが発生します。割り込みが発生した時点でその前データがRXBUF0に入り、TXFBUF0にセットした値がLM4930に送信されています。LM4930ではデータを受け取るとその数値に対する電圧をDAC(ADCの逆の動作をする)から出力し、その電圧はスピーカ端子に出力されます。

 スピーカ端子には常に一定の電圧がかかっており、+端子からはDACの電圧を加えた電圧が、−端子からはDACの電圧を引いた電圧(つまり逆の波形)が出ます。これでスピーカを駆動しています。



音声入出力プログラム例


 では実際に音声入出力を行ってみましょう。まず、A33Fにマイクとスピーカをつなぎました。
 スピーカは電子部品店で販売している安価なものにケーブルを取り付け、先端に2550コネクタ(浅草ギ研で販売)を取り付けました。コネクタは2.54mmピッチのものでしたらなんでもよいと思います。A33F側にはヘッダピンを取り付けています。
 マイクは、通販で購入したノートPC用のものです。1500円ぐらいでした。端子が3.5mmジャックのモノラルマイクならなんでも使えます。マイクによっては「プラグインパワー専用」というのもありますが、それも使えます。ちなみにステレオマイクを差し込んでも音声は取れますがL側しか使えません。
 


 実際のプログラムは次のようになりました。(対象を右クリックで保存)

 PCM.c


 プログラムの説明をしますが、I2CとSPIの部分は説明済みですので割愛します。
 
 まず、DCIの設定の部分が長いので関数化しました。行81〜98の部分です。
 行86でDCIのクロックピンを入力にしています。クロックはLM4930から供給されます。
 行87でフレーム同期端子を入力にしています。フレーム同期信号を出す方がマスタとなりますのでこの設定をすると自動的にdsPICはスレーブになります。
 行88で、クロック立下りでサンプリングに設定しています。これはLM4930のデータシートを読むとクロック立下りでデータのやりとりをしていると載っているのでその通りにします。
 行89でデータフレームは1ワードに設定しています。音声データの種類によっては1フレームに複数ワードがある場合があります。また、複数の音声システムをつないでいる場合は1フレーム内で複数のデータがやりとりされる場合もあります。しかし、今回のハードウェア構成では1フレームに1ワードとなります。
 行90でワードサイズを指定します。LM4930のPCM信号は16ビットなので0x0Fに設定します(値+1がビット数になる)。
 行91でマルチチャンネルモードを指定しています。dsPICのマルチチャンネルモードはPCMと同じ仕様ですのでこれを選びます。
 行92〜94で割り込み設定をしています。
 今回、1フレームに1ワードなので、1フレーム1スロットとなりますのでTSCON,RSCONどちらも1に設定します。スロットとは、複数の音声システムをつないでいた場合、1フレーム中に複数ワードを送受信し、自分のデータは何番目かを決めるというものです。今回は複数のシステムは無い(1対1)なので「スロット番号0番だけでデータをやり取りする」という設定になります。(よくわからなかったらLM4930のデータシートについても詳しく読んでみてください。スロットが理解できなくても下記の設定ならA33Fは問題なく使えます。実質的にはスロットは使っていないので。)
 
 割り込み部は、今までのページのようにして宣言します。割り込みフラグは自動的にクリアされないので割り込み内でクリアするのを忘れないで下さい(行106)。
 設定で1フレーム信号ごとに割り込みが発生しますので、8kHzの間隔でこの割り込みルーチンに入ります。
 今回はとりあえずサンプルとして、グローバル変数v_flgを用意し、この値がRECだったらあらかじめ用意しておいたvoice[]配列にデータを書き込み、PLAYだったら書き込んだデータをLM4930へ送信しています。
 dsPIC33FのRAMは3Kなので、音声データを入れる配列は2400個(8kHzで0.3秒分)までしか用意しませんでしたが、データをRAMではなくmicroSDなどに入れられればもっと長いデータを入出力できるかと思います。

 メイン部はこのようになっています。
 
 行177でLM4930のBASICCONFIGレジスタを設定しています。I2C経由。この設定はすぐには反映されないようなので、念のため行178で設定が確実になるまで少し待ってます。
 行179はゲイン(ボリュームのようなもの)を設定しています。スピーカのゲインは最大でやっと普通のラジオぐらいになるので、最大にしています。
 行180〜193で1秒おきに300mS間録音して録音したデータを1秒後に再生しています。

 ということで実行した結果、問題なく音声が録音/再生されました。


 音声データは単純に音声波形を16ビット値で表したものなので、これを計算して使う(音声認識や、音声の出力のトーンを変えたり)ということも可能です。



おわりに

 とりあえず、これでA33Fで使える機能は一通りご説明しました。これらの機能を使いこなすには実際にシステム、つまりロボットを組んでみて、本ページなどを参照に何度かプログラムを組んでみる必要があると思います。


2007年11月8日

 
(C)Copylight 2003. 有限会社浅草ギ研 | 通信販売の法規(訪問販売法第8条)に基づく通信販売業者の表示