シーケンス全体の制御は容易でしたので、肝心かなめのモデム信号部分の生成です。モデム信号は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から始まる実際の信号部分の頭の部分です。頑張れば目視によるデコードもできるかも?
送信すべきデータの内容は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から始まる実際の信号部分の頭の部分です。頑張れば目視によるデコードもできるかも?