マイコン工作実験日記

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

パワーダウンを使ってみる

2016-04-26 06:36:52 | SLIC
これまでAg1171のPD端子はオープンで使っていましたが、オンフック時の消費電流を削減するためにSTM32につなげてやりました。

PD端子をLレベルにすることでパワーダウンすることができますが、この端子はHレベルにしてはならないことになっているので、上図のようにダイオードを入れて使います。

オンフックを検出したならば、PD信号をLレベルにすることでAg1171はパワーダウン状態に入ります。しかし、パワーダウン状態ではオフフックの検出ができません。そこで時折パワーダウンを解除して、フッキング状態が変化していないか確認してやる必要があります。しかも、パワーダウンを解除してから信号の状態が安定するまでには50msを要します。オフフックされたことを速やかに検出するためには、頻繁にパワーダウン状態から抜け出さねばならなくなります。

今回はパワーダウン期間を350msにしてみました。その後50msのウエイトを置くのので、オンフック時には400ms間隔で状態確認を行うことになります。実際に試してみると受話器を耳に当てて、ちょっとしてからダイアルトーンが聞こえる感じですが、まぁいいことにしよう。



電流を測ってみると、当然のことながら数値が変化します。テスターでは少ない時で63mA程度。70mAほど減ったようです。

パルス数を数える

2016-04-04 23:20:53 | SLIC
すでにDTMF検出はVinTask内で実装していましたが、パルスダイアルのためのパルス検出機能は未実装でした。そこでSlicTaskにパルス検出機能を追加してみました。

パルスダイアリングのパルス信号は下図に示したようにAg1171のSHK信号を解析することで検出します。SHK信号の立ち上がりでパルス数をインクリメントしてゆき、一定時間(T1)オフフック状態が続いたならばひとつのパルス列が終了したとみなします。

SHK信号の立ち下がりでは、T2タイマを起動して一定時間Lの状態が続いた時点でパルス信号ではないと判断し、オンフックされたことを確定することにしました。



実験に使っている電話機は10pps対応のものです。受話器に備わっている設定スイッチをP側にすることでパルスダイアル信号を生成しますが、途中で ’*’キーを押すとトーン信号に切り替えることができます。実際に動作確認してみた結果は次のとおりです。



パルスでもDTMFでも、どちらでも正しい数字を検出できることが確認できました。次は、ダイアルした番号で発呼できるようにするかな。

制御タスクを追加する

2016-03-31 23:25:49 | SLIC
これまでの作業で基本的な機能パーツが揃ってきましたので、これらを制御して電話として機能させるための制御タスクを用意することにしました。全体は、下図に示すように5つのタスクで構成することにしました。



VinTask音声信号の入力処理タスク。DTMFの検出も行う。
VoutTask音声信号の出力処理タスク。トーンの生成も行う。
SlicTaskフッキング検出並びに着信鳴動を生成するタスク。
WT32TaskWT32の音声入出力ならびにイベント解析を行うタスク。
PhoneTask全体の制御を行うタスク。LCDへの出力も行う。


VinTask, VoutTask, SlicTask, WT32Taskの各タスクはこれまでの実験で作ってきたものです。そして今回、全体を制御するタスクとしてPhoneTaskを作り始めました。

まずはトーン生成機能の追加。VoutTaskではダイアルトーンのような単一周波数のトーンを連続して生成する機能を持っていますが、ふたつの高さの音を繰り返して生成することはできません。そこでPhoneTaskから2つの周波数を切り替える指示をVoutTaskに送ることでこれを実現してみました。トーンの生成は、フッキングがトリガとなって開始、終了します。



HFP接続が無い状態でオフフックした場合には、400Hzと600Hzを交互に出すことでエラー通知とします。オンフックされたならば、トーン生成を止めます。



HFP接続が確立した状態ではオフフックを検出すると、400Hzを連続して生成することでダイアルトーンを出力します。

WT32をつなげる -- SAIの設定

2016-02-28 19:54:50 | SLIC
随分と前になってしまいましたが、前記事ではWT32をUARTにつなげたので、次はPCM信号をI2SでSTM32L476につなげます。もともとSTM32ではSPIがI2S機能をサポートしていましたが、近頃の新しめのデバイスではSAI (Serial Audio Interface)という機能が備わっているので、こいつを使うことにします。SAIにはPCM u-Law/A-Lawの圧縮/伸張機能も備わっていたりするので、W-SIMのようなデバイスをつなげるのにも適しているのですが、W-SIM自体が無くなってしまったのが残念なところです。

SAIはBlok AとBlock Bで一組になっており、片方をもう片方に同期して使えばSAI_CLKとSAI_FSを共有することができます。SLIC側とつなぐADC/DACも同じPCM_SYNCで外部トリガをかけて変換動作をすることで、WT32側とSLIC側の処理が同期して進み、音声が流れることになります。SAI, ADC/DACは全てDMAを使って動かします。SAIで受信したデータを直接 DMAでDACに渡すことはできませんし、この記事で述べたようにPCM信号の符号反転処理も必要になるので、間にバッファを置いて処理を行います。

この方針でSTM32CubeMXを使ってSAIの設定をしようとしたのですが..



Output ModeでMonoを選択できません。I2SなのでHFPの音声がステレオのフォーマットで送られてきますが、そのうちの片方のデータだけを受信してDACに送りたいので、SAIではMono modeを選択したいところなんです。SAIの設定としては、Monoを選択するには、Slot数を2にしておかねばならないようなのですが、そのようにしてもOutput ModeではStereoしか選択できません。どうやら、CubeMXのバグのようです。

CubeMXの生成する .ico ファイルを修正すれば何とかなるだろうと考えたのですが、ico ファイルを見てもそれらしいパラメータが出力されていません。コード生成された main.c を開いて SAIの初期化コードを修正して対応するしかなさそうです。

WT32をつなげる

2016-02-13 19:22:55 | SLIC
しばらく作業時間が取れなかったSLICを使ったプロジェクトを再開。次の段階として、WT32を使ったHFP通話をSLICとつなぐことにします。まずは、WT32をSTM32L476のUSARTと接続。





改めてSTM32のUSARTの仕様を確かめると、FIFOがないんですね。SPIやSAIにはFIFOが用意されているのですが、USARTにはFIFOが無いのは従来のデバイスとの互換性を考慮してのことでしょうか。あるいはDMAを使うことを前提としており、FIFO無しで構わないということなんでしょうか。STM32L476にはDMAが14チャネルもあるので、迷うこともなくDMAを使ってUSART送受信することにします。STM32L4のDMAにはサーキュラーモードがありますので、これを使うだけでリングバッファへの受信処理が実現できてしまいます。

ただし、USART受信においてDMAを使う場合にはタイムアウト処理が必要となります。受信バッファが一杯になった場合には、DMA完了割り込みでそれを知ることができますが、バッファが一杯になる前に相手からのデータ送信が止まった場合には、 タイムアウトにて受信待ちを打ち切らないとせっかく受信できたデータを処理することができません。今回は、FreeRTOSを使っているのでイベント待ちをタイムアウトすることで、受信待ちを打ち切ることにします。

タイムアウトが発生したら、どこまでDMAが進んだかを調べれば、受信バッファのどこまでデータを受信できたのかがわかります。STM32L4ではDMA_CMARxがDMA転送先のメモリアドレスを示しますが、このレジスタはDMAの先頭アドレスをを示すだけで、DMAが進んでも更新されるわけでは無いということに気づかずにハマってしまいました。DMAがどこまで進んだかを調べるには、転送数を示すDMA_CNDTRxの値から求める必要があります。

こうしてWT32の出力するイベントメッセージをUSARTでDMA受信した内容を、まずはそのままRTTを使って出力してみました。




なお、受信DMAのタイムアウト処理に関しては、AN3109にても言及されており、ここではUSART_RX端子をタイマーの入力キャプチャー端子につないで、入力のアイドル時間を監視するという方法が紹介されていました。機会があれば、試してみようかな。

DTMFを拾ってみる

2015-12-27 19:39:47 | SLIC
DACを使ってのダイアルトーンやモデム信号の生成はできるたので、今度はADCの番です。音声受信の前段階として、まずは電話機からのDTMF信号を拾ってみます。Ag1171sのVout出力はSTM32L476のPA3につなげているので、ADC2_IN8でこれを受けます。ADCにはオーバサンプリング機能が用意されているようなので、これを使ってみようということで次の設定を用意。



8倍のクロックでサンプリングしたものを8で割って平均を取った値をサンプル値とします。クロックはTIM6を使って64KHzを生成してこれをトリガとしてADCに変換を開始させます。結果として8KHzでのサンプリング値が得られます。



変換結果はDMAを使ってメモリに転送。DACと同じくサーキュラーモードを使って、バッファの半分の転送が終わったところで割り込みをかけてDTMF検出処理を動かします。

DTMF検出については、Keilのサイトにとても良いサンプルコードがあったので、これをそのまま流用することにしました。Keilのツールとともに使うことが使用許諾条件になっているので、これには違反しているんですが。。。このコード、STM32用と題してあり8KHzサンプリングされたADCデータ(12ビット右詰め)を処理することが前提となっていますが、信号処理部分は大きくハードに依存しているわけでもないので、異なるMCUを使う場合でも簡単に移植できるでしょう。



何の問題もなくあっさりとDTMF検出が動きました。

ナンバーディスプレイ信号を生成する -- モデム信号編

2015-12-19 10:48:59 | SLIC
シーケンス全体の制御は容易でしたので、肝心かなめのモデム信号部分の生成です。モデム信号はV.23 1200bpsに準拠していますが、発信者番号情報を電話機に対して送信すれば良いだけであり、受信処理はありません。また変調方式はV.23 1200bpsの固定となっていますので、ネゴの手順も必要ありません。FSK(周波数変調)と言ってもデジタル信号の変調ですので、送信するデータの内容に応じて bit 0を2100Hz, bit 1を1300Hzの周波数で送出すれば良いだけということになります。

送信すべきデータの内容はNTTが公開している技術参考資料で説明されています。以下のフォーマットはその資料からの引用です。



60ms以上のマークビットに続いて、定められたフォーマットで発信者番号を送出してやる必要があります。この図ではビット送出順序も表現されており、情報データ部分の各オクテットは最下位のb1から送出することになっていますが、最後の2オクテット(16bit)のCRC部分については最上位ビットから送出することになっています。また、bpはパリティビットを示していますので、データ部分については偶数パリティを付けて、最下位ビットから送出してやる必要があります。



データ部分ならびにCRCの各オクテットは上図のようにスタートビットとストップビットをつける必要が有ります。つまりはUARTで送信するのと同じように送信せよということですね。UARTの出力を使って変調をかけることを意識しての設計になっているのでしょうか。しかし、今回はDACでの出力が必要ですので、ソフトウェアでデータビットに対応した周波数の相当のDACに出力すべきデータ列を生成してやります。

CRC部分についてはSTM32L476にCRC演算機能が備わっているので、これを使ってみることにしました。STM32CubeMXでの設定は次のとおり。生成多項式の係数を指定できるようになっています。X16の項はお約束の部分なので省略して指定するようです。



生成するモデム信号は1200bpsですので、24KHzでサンプリングした場合には1ビット分に相当するサンプル数は24000/1200 = 20サンプルとなります。スタート/ストップを含めると元データの1バイトの送出には10ビットが必要ですので、 200サンプル(400バイト)分のDAC出力信号に展開してやり出力すればいいことになります。マークビットの長さも、これに合わせて10ビットの倍数である80ビットを選択。これで66ms相当の信号となり、NTTの定める仕様(60ms以上)を満足することができます。




こうして生成した出力サンプルデータをDMAを使ってDACへ送信してやると、Ag1171sを介して電話機にモデム信号が出力されて、めでたく電話機に数字を表示することができました。




上図に実際のシーケンス全体の信号の様子を示します。試験プログラムでは、呼び出し信号に応答(オフフック)後にダイアルトーンを送出しています。モデム信号が送出される前にはオフフックしていますので、ナンバーディスプレイに対応していない電話機(あるいは設定でナンバーディスプレイ機能を無効に設定した電話機)を接続すれば、実際に流れるモデム信号を耳で聞くこともできます。




モデム信号部分を拡大してみました。左1/3くらいはマークビットの部分です。ビット1が連続しているので、1300Hzの波形が続いています。その後ろがDLEから始まる実際の信号部分の頭の部分です。頑張れば目視によるデコードもできるかも?

ナンバーディスプレイ信号を生成する -- シーケンス編

2015-12-09 21:31:04 | SLIC
Ag1171sを使っての電話機接続も、フック検出から始まって、着信音とダイアルトーンの生成までできました。ここで、ちょっと寄り道して、ナンバーディスプレイ信号を生成する実験をすることにします。生成できるトーンの周波数を2つ追加して、これまで組んできた処理を組み合わせてやれば、ナンバーディスプレイに必要な信号を生成できるからです。



まずはNTTの技術参考資料から上図に示したナンバーディスプレイのシーケンスを確認しておきましょう。ぎょうぎょうしいNTT用語が並んでいますが、情報受信端末信号は普通の着信鳴動と長さが違う呼び出し信号にすぎませんし、応答信号と受信完了信号は、それぞれオフフックとオンフックのことを示しているにすぎません。これらをAg1171sの信号名とその変化に読み替えてやれば、下図のようになります。



呼び出し信号のケーデンスを変更してやるだけで情報受信端末起動信号は生成できますので、追加でMODEM信号を生成して発信者番号情報を送ってやれば、ナンバーディスプレイ対応の電話機に表示ができることになります。ナンバーディスプレイで使われるモデム信号はV23の1200bpsと定められています。V23はFSK変調で送信データを変調して送信しますが、デジタル信号の変調ですので送信データのビット0に対して2100Hz, ビット1に対応して1300Hzのトーンを必要な長さだけ生成してやれば良いだけということになります。したがって、STM32のDACを使って簡単に生成することができます。

ダイアルトーンの生成

2015-12-06 11:27:53 | SLIC
Ag1171sを使った電話機とのインタフェース。着信音生成の次はダイアルトーンの生成です。オフフックしたら、400Hzのダイアルトーンを送出することにします。今後幾つかの周波数の信号を生成することを考えているので、sinのテーブルを用意しておき、それを参照して必要な周波数の信号を生成してDACに送ることにします。sinテーブルなんて自分で作ってもいいんですが、CMSIS-DSPに含まれているだろうと思い確認したところsinTable_q15があったので、これを使うことにしました。

サンプリングは24KHzで行うこととし、STM32L476のTIM7を使ってタイミング生成。DAC1のトリガーソースとしてTIM7のトリガーイベントを選択して、DMAで送信することにしました。400サンプル分のバッファを用意しておき、これをダブルバッファリングで使用。半分のデータを送信している間に、残りの半分のバッファに次に送信すべきデータを準備してやります。基本的なドライバのコードはSTM32CubeMXを使って生成しています。





DMAにCircular modeというのがあることを知ったので、これを使うことにしました。一度、DMAを開始すると繰り返し同じバッファからのDMA送信をおこなってくれます。バッファの半分まで送信が終わった時点と全ての送信が終わった時点で割り込みがかかってコールバックが呼ばれるので、そのタイミングで送信が終了したバッファに次の送信データを用意してやることで、繰り返し400Hzの波形を出力してやります。

sinTable_q15のデータは符号付の16bitデータです。そのため、このデータを直接DACに出力しても正しい波形にはなりません。0x8000~0xffffの値は負の値ですが、このままDACに送ってしまうと、逆に出力電圧が高くなってしまいます。そこで、0x8000とXORをとって符号を反転しておきます。STM32のDACは12bitなので16bitデータを4bitシフトしてやる必要がありますが、DACへの書き込み時に左詰め/右詰めしてくれる機能があるので、この機能を使えばソフトでは4bitのシフト処理は不要となります。CubeMXの設定を探しても左詰め/右詰め指定の設定をする箇所がないので戸惑いましたが、この指定はHALのAPIを呼び出す際に指定する仕様になっています。今回は左詰めを指定。符号を反転させた波形データはフルスイングした信号となっていますので、音声として再生すると音が大きすぎます。2bit右シフトして出力してやると丁度加減が良いようです。


ダイアルトーンの生成が確認できたので、次は異なる周波数も生成する実験をやってみるべく作業中です。

着信音を鳴らしてみる

2015-11-28 14:56:19 | SLIC
フック検出ができたので、続いて着信音を鳴らしてみます。

着信鳴動させるには、RM信号をHレベルにして、FR信号でオン/オフを繰り返して鳴動させます。NTTの仕様では、着信時に極性反転することになっていますから、鳴動時にはFR信号を反転してLレベルにしてやり、オフフックが検出されたらFR信号をHレベルに戻してRM信号もLレベルにすることにします。FR信号には、PA2/TIM15_CH1を割り当てましたので、TIM15をカウンタモードで使い、compare matchにてCH1をトグルすることで鳴動させます。RF, RM, SHKの各信号の動作をSaleaeで確認してみました。まずは全体の様子。




3回、着信音が鳴ったところで受話器をオフフックしましたのでSHKがHレベルに変化しています。オフフック時にチャタリングが発生しているのが見えます。RM信号はFR信号をトグルしてベルを鳴らす期間だけHレベルにすることで、消費電流を抑制します。




ベルの鳴り方はNTT仕様に準じて1秒鳴らして、2秒休止としています。




ベルの鳴動周波数も16Hzとしており、標準的な周波数です。FRのトグル開始と終了の時にタイマーの動作設定を変更しているのですが、その際にヒゲが出てしまっているようです。動作上は問題なさそうなのですが、ちょっと気に食わないのでできれば修正したいところです。