アナログ信号をマイコンに取り込む場合、内蔵ADCを使用することが多いですが、入力電圧範囲、分解能、精度、絶縁、同時サンプリングといった制約でADCを外付けすることが必要な場合があります。低速な外部ADCの場合はI2C(~1MHz)やSPI(~数10MHz)の通信帯域で十分ですが、マルチチャンネルで高速なADCの場合はSPIでも帯域が足りないため、パラレルバスを採用したADCが多くなります。
一方、AnalogDevicesのLTC2358、LTC2458といった高速ADCではSPIと互換性を保ちつつ、パラレルバス接続するインターフェースを採用しています。具体的には一般的なSPI接続のCS、CLK、MOSI、MISOに加えて、MISO2、MISO3といった具合にMISOがパラレルになっています。MISOをパラレルにして増やすことで1回の通信時間を短くし、高速サンプリングを実現しています。今回はMISOがパラレルになっている外付けADCをどうSTM32マイコンと接続するか検討してみました。
検討に際してざっと思いつく通信方式を並べてみました。
方法@ QSPIを利用
方法A FMC/FSMCを利用
方法B GPIOで個別制御(bit-bang)
方法C 内蔵ADCでSDO読み込み
方法D SPIを複数接続
方法@ QSPIを利用
STM32マイコンの一部にはQSPIインターフェスがあります。QSPIは主にNOR Flash接続するインタフェースとして使われています。QSPIは通信ラインが双方向です。一方、今回のインタフェースは通信方向は常に一定で決まっており、双方向ではありません。QSPIは次にデータを書き込むのか読み込むのかマスターからコマンドを送って通信方向を決定します。QSPIを個別にレジスタで制御して通信方向を決定できれば実現可能かもしれませんが、STM32マイコンのQSPI HALライブラリがNOR Flash用になっているため、あまり適切ではなさそうです。
方法A FMC/FSMCを利用
LCDや外付けRAM、パラレルバスとしてFMC/FSMCインタフェースがあります。FMCとFSMCの違いはFSMCにSDRAMリフレッシュ機能等をつけたのがFMCでFMCの方が高機能です。LCDのように一方的にマイコンからLCDに書き込む場合やメモリのようにリードライトを切り替えて処理する場合にFMC/FSMCが最適です。今回の場合はパラレルインタフェースでありながら、ADCに変換指令を送信しつつ、ADC変換結果を受信するため、同時に送受信を行う必要があります。FMC/FSMCがパラレルバスの同時送受信に対応しているか確認が必要です。また、既にバスラインをSDRAMで使用する予定があるため、この方法も厳しいと判断しました。
方法B GPIOで個別制御(bit-bang)
GPIOを個別に制御してソフトウェアSPIを実現する方法です。この方法であれば、MISOがパラレルになっている外付けADCでも対応可能です。ただ、課題として個別にGPIOを制御するために時間がかかるため、数MHzは容易に実現できそうですが、数10MHz以上のクロックを実現できるか分かりません。STから
パラレルバス用のDMA転送ライブラリが提供されており、DMA転送もできなくはなさそうです。GPIOの個別制御は最終手段として取っておきたいと思います。
方法C 内蔵ADCでSDO読み込み
SPIでCS、CLK、MOSI、MISOの通信に加えて、それ以外のMISO2、MISO3といったバスをADCで同時に取り込んでデジタル化する方法です。邪道な方法ですが、STM32マイコンのリソースを活用して実現するという意味では実現できそうです。問題点として取り込んだアナログ値をデジタル化するために処理が必要で連続で取り込むためにはRAMの制約を大きく受けます。ADCで取り込むことはできなくはなさそうですが、マイコンのリソース制約を大きく受けるため非現実的だと思いました。
方法D SPIを複数接続
STM32マイコンではSPIが複数利用できます。1つのSPIを送受信マスタとしてADCと接続し、それ以外を受信専用スレーブとしてのADCのSDOxと接続します。具体的には下記のような配線になります。複数SPIを同時に利用するためにDMA転送は必須です。事前に受信専用スレーブをDMA受信設定してから、マスタSPIから送信することで同時通信を実現します。
また、MISOがパラレルになっている外付けADCで今回使用予定のLTC2458はSDOのレーン数を常に8ライン使用する必要はなく、2レーン、4レーン選択できるようになっています。SPIが8つなくても、2つ、4つであれば、中規模以上のSTM32マイコンであれば搭載されているため、十分実現できそうです。
SPIの機能をそのまま使用しているため、通常はSPIを1レーンで使用し、帯域が必要な場合にのみ複数レーンを使用するといった切り分けが容易に実現できます。
実際に方法D SPIを複数接続で検討してみました。下記のようにDMA転送のPriorityを設定しました。また、SPIはNSS Signal TypeのHardwareを選択しました。
処理をprintfで出力すると下記のようになりました。STM32F411で検証した結果、Priority設定にもよりますが、SPI2が先に呼び出される前にSPI4、3が呼び出されました。
Init OK
Rx Cplt Callback:SPI4
Rx Cplt Callback:SPI3
RxTx Cplt Callback:SPI2
Rx Cplt Callback:SPI5
LTC2458は下記のように各SDOから順番循環して各チャンネルのAD変換結果が出力されます。1レーンで使用する場合はSDO0から1x8回データ取得し、2レーンの場合はSDO0とSDO4から2x4回データ取得、4レーンの場合はSDO0、SDO2、SDO4、SDO6の4x2回データ取得する感じです。
SDO0:[CH0]、[CH1]、[CH2]、[CH3]、[CH4]、[CH5]、[CH6]、[CH7]...
SDO1:[CH1]、[CH2]、[CH3]、[CH4]、[CH5]、[CH6]、[CH7]、[CH0]...
SDO2:[CH2]、[CH3]、[CH4]、[CH5]、[CH6]、[CH7]、[CH0]、[CH1]...
.
.
.
8回分のAD変換結果を書き出した結果が下記の通りになり、同じ値が循環して取得できていることから複数のSDOを読み込めていることが確認できました。
SDO0: 10459, 55041, 8220, 1782, 133, 64062, 62606, 61580,
SDO2: 8220, 1782, 133, 64062, 62606, 61580, 10459, 55041,
SDO4: 133, 64062, 62606, 61580, 10459, 55041, 8220, 1782,
SDO6: 62606, 61580, 10459, 55041, 8220, 1782, 133, 64062,
海外サイトでも同様の議論があり、実際に動いたかどうかまで書かれていませんでしたが、方法D SPIを複数接続で実現できることが確認できました。SPIの機能をそのまま利用しており、DMA転送や数10MHz程度のクロックを容易に実現できるため、DMA転送を利用した方法D SPIを複数接続は外部高速ADC接続方法として良いと思いました。