以前にFTDIのVinculumUを紹介しました。VinculumUはUSBホスト機能を備えたマイコンで最大2つのUSBポートを使用することができます。開発環境のVinculum II Toolchainを使用することで書き込むプログラムによって様々な機能のUSBホストを実現することが可能です。
今回はVinculumU を用いてSPIマスタのパフォーマンスを評価してみました。最終的にはUSBから取得したデータをVinculumU のSPIマスタを介して外付けメモリに転送することを検討しています。検討に際して想定よりもパフォーマンスが出ないことが分かったため、設定による違いをまとめてみました。
前提条件としてvos_initではVOS_Q=10、VOS_TICK=1、NUMBER_OF_DEVICES=4、VOS_48MHZ_CLOCK_FREQUENCY、VOS_IOCTL_SPI_MASTER_SET_DATA_DELAY=0で実験しています。また、CSとCLKを測定して1回のSPI通信サイクルを確認しました。
まず、DMAを無効化した状態で8byteのデータをSPIマスタから書き込む操作を行いました。
vos_dev_write(hSPI_MASTER, wcmd, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);
vos_dev_write(hSPI_MASTER, data, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);
vos_dev_write(hSPI_MASTER, data, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);
■DMA未使用
VOS_IOCTL_COMMON_DISABLE_DMA、クロック3MHz
VOS_IOCTL_COMMON_DISABLE_DMA、クロック3MHz
黄色がCLK、赤がCSです。CSが0の期間は約820usecとなりました。1byte毎に分かれて送出されていることが分かります。また、各byte毎に50usec程度の間をおいてから次のbyteが送出されています。また、4byteの書き込み後、次の4byteを書き込むまでに200usec以上要していることが分かりました。
■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック3MHz
DMA転送を有効にしてDMAモードをDMA_ACQUIRE_AS_REQUIREDで同様に書き込みを行いました。
DMAを有効にすると1byte毎でなく、4byteまとめて送出されてるようになりました。CSが0の期間は約750usecとなりました。
■DMA使用DMA_ACQUIRE_AND_RETAINモード、クロック3MHz
DMAモードをDMA_ACQUIRE_AND_RETAINで同様に書き込みを行いました。
DMA_ACQUIRE_AND_RETAINモードでは4byteと次の4byteとの間隔が短くなり、CSが0の期間は約500usecとなりました。
■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz
SPI通信のクロックを上げてDMA_ACQUIRE_AS_REQUIREDモードで同様に書き込みを行いました。
クロックを上げると4byteと次の4byteとの間隔が短くなり、CSが0の期間は約380usecとなりました。
■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み
4Byteを2回書き込みでなく、8byteを1回の書き込みに変更してみました。
vos_dev_write(hSPI_MASTER, data, 8, &num);
vos_dev_read(hSPI_MASTER, dummy, 8, &num);
CSが0の期間は約200usecとなりました。
■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み、Writeのみ
VinculumUのSPIマスタは書き込み関数と読み込み関数がそれぞれ分かれています。通常は書き込み関数と読み込み関数の2つを使用してSPI通信の読み書きをします。書き込みのみの場合はvos_dev_write関数のみで構いませんが、読み込みの場合はvos_dev_write関数を実行してからvos_dev_read関数で値を読み込む必要があります。今回はメモリ書き込みのみを想定した場合、厳密には読み込み処理は不要です。書き込み関数のみにして同様に測定しました。
vos_dev_write(hSPI_MASTER, data, 8, &num);
//vos_dev_read(hSPI_MASTER, dummy, 8, &num);
CSが0の期間は約100usecとなりました。
■結果まとめ
以上の結果からSPI通信を短時間で実行するためにはDMA転送の有効化、DMA_ACQUIRE_AS_REQUIREDよりもDMA_ACQUIRE_AND_RETAIN、クロックを高速にすることが重要であることが分かりました。また、vos_dev_write関数、vos_dev_read関数を細切れに呼び出すよりも分けずにまとめて呼び出すことが同様に短時間化に重要だと分かりました。
VinculumUは独自RTOSで実装されており、各処理の切り替え、関数呼び出しのオーバーヘッドが大きいようです。最後の結果でもCSが下がってからクロックが出るまで約40usec要しています。同様にクロックがで終わってからCSが上がるまでに約50usec要しています。VOS_Q、VOS_TICKの値を様々に変更してタイムスライスを小さくしても劇的な変化はありませんでした。VinculumU のSPIマスタは関数呼び出しのオーバーヘッドが非常に大きいことを考慮する必要があることが分かりました。
なお、今回の結果とは別に書き込みのみで書き込みデータを増やしてCSが0の区間を測定すると下記のような結果になりました。
書き込みデータ | 8byte | 192byte | 384byte | 512byte | 640byte | 800byte | 944byte |
処理時間 | 100usec | 200usec | 260usec | 310usec | 350usec | 410usec | 460usec |
CS変化前後の処理オーバーヘッドの時間は変わらず、データ数の増加に合わせて処理時間が長くなる結果となりました。
これらのことからVinculumU のSPIマスタは高速な読み書き用途としてあまり向いていないことが分かりました。実装する際は関数呼び出しのオーバーヘッドを考慮してコーディングする必要があると分かりました。特にUSBのIsochronous転送の場合、最短1msecごとにデータが転送されます。少なくとも1msecより短い時間で1回の転送データを書き込む必要があり、SPI通信の処理速度が求められます。今後はIsochronous転送でどれくらいのデータ処理ができるか検討したいと思います。