PSoC 5LP で BULK 転送 (2)
前回の記事では、 USBFS コンポーネントを "Manual" モードで使ってみました。 今回は、 "DMA" モードを使ってみます。 DMA 使ったら、もっと速くなるよね。
コンポーネントの設定
回路図は、前回と同じなのですが、コンポーネントの設定を一か所だけ変えました。 "Device Descriptor" タブの "Descriptor Root" ノードで "Endpoint Buffer Management" を "DMA with Manual Buffer Management" に設定しています。
"Manual" モードでは、エンドポイントバッファと RAM 上のバッファとのデータ転送を CPU で行っていました。 "DMA" モードでは、この転送に DMA を用います。 CPU の代わりに DMA を使うのだから、当然、早くなるよね。
プログラム
DMA を使用すると、 CPU が介在することなく処理が進む時間が生まれます。 このような時間をムダにしないために、プログラムは、 "BULK-IN" と "BULK-OUT" を取り扱う二つのステートマシンとして実装しました。
#include "project.h" #define IN_EP (0x02u) #define OUT_EP (0x01u) #define BUFFER_SIZE (64u) uint8 buffer_in[BUFFER_SIZE] = "@@ABCDEFGIHJKLMNOPQRSTUVWXYZ"; uint8 buffer_out[BUFFER_SIZE]; uint16 length_out;
冒頭の定数とバッファの定義は、前回と同じです。
#define ST_ACKWAIT (1u) #define ST_READING (2u) #define ST_GETWAIT (3u) #define ST_DISCARDING (4u) #define ST_PREPARING (5u) uint8 state_in; // State code for BULK-IN uint8 state_out; // State code for BULK-OUT
今回のプロジェクトは、ステートマシンを取り入れたので、状態コードと状態変数を定義しています。 ふたつのステートマシンをひとつの状態コードで取り扱う横着な構成になっています。
int main(void) {
CyGlobalIntEnable; // 割り込みの有効化
USB_Start(0, USB_5V_OPERATION); // 動作電圧5VにてUSBFSコンポーネントを初期化
for (;;) {
// 初期化終了まで待機
while (USB_GetConfiguration() == 0);
USB_IsConfigurationChanged(); // CHANGEフラグを確実にクリアする
デバイスが SET_CONFIGURATION を受けて初期化を行う所までは、前回と同じです。
// BULK-OUT: OUTエンドポイントでホストからデータを受信する
state_out = ST_DISCARDING;
// BULK-IN: 初期状態を決定する
state_in = ST_PREPARING;
その後、双方のステートマシンの初期状態を決定しています。 前回のプロジェクトでは、 "BULK-OUT" エンドポイントをイネーブルする処理が入っていましたが、この処理もステートマシンの中に取り込んでしまっているので、完全に初期状態を決めるだけになりました。
for (;;) {
// 設定が変更されたら、再初期化をおこなう
if (USB_IsConfigurationChanged()) {
break;
}
内側のループで、 SET_CONFIGURATION を検出してループを脱出するところは前回と同じです。
// BULK-OUT ステートマシン
switch (state_out) {
case ST_DISCARDING:
// OUTバッファのデータを破棄する
USB_EnableOutEP(OUT_EP);
state_out = ST_ACKWAIT;
break;
case ST_ACKWAIT:
// ホストからのパケットの到着を待つ
if (USB_GetEPState(OUT_EP) == USB_OUT_BUFFER_FULL) {
state_out = ST_READING;
}
break;
case ST_READING:
// 受信バイト数を取得する
length_out = USB_GetEPCount(OUT_EP);
// OUTバッファからデータを取り出す
USB_ReadOutEP(OUT_EP, &buffer_out[0], length_out);
state_out = ST_GETWAIT;
break;
case ST_GETWAIT:
// OUTバッファからの転送を待つ
if (USB_GetEPState(OUT_EP) != USB_OUT_BUFFER_FULL) {
state_out = ST_DISCARDING;
}
break;
default:
break;
}
"BULK-OUT" のステートマシンは、よっつの状態から構成されています。 まず、 ST_DISCARDING では、"BULK-OUT" エンドポイントを有効にして次のパケットを受信できるようにします。 "Manual" モードでは、エンドポイントに届いたデータを USB_ReadOutEP() 関数で引き取るだけで次のパケットを受信できるようになりました。 "DMA" モードでは、明示的に USB_EnableOutEP() を呼んで、次のパケットを受け入れます。
ST_ACKWAIT では、ホストからパケットが到着するのを待ちます。 ステートマシンで構成してあるので、パケットが到着していない場合は到着を待たずに別の処理を行う事が出来るようになっています。
ST_READING では、到着したパケットを buffer_out[] に転送を始めるため USB_ReadOutEP() 関数を呼び出します。 この後、データの転送が DMA で実行されますが、その間、 CPU は別の処理を行う事ができます。
ST_GETWAIT では、 DMA 転送の終了を待ちます。 転送の終了は、 USB_GetEPState() で示されます。 転送が完了したら、次のパケットを待つために状態遷移します。
// BULK-IN ステートマシン
switch (state_in) {
case ST_PREPARING:
// 空きバッファにデータを準備する
buffer_in[0]++;
// INバッファのデータを送信する
USB_LoadInEP(IN_EP, &buffer_in[0], BUFFER_SIZE);
state_in = ST_ACKWAIT;
break;
case ST_ACKWAIT:
// ホストからのデータ受信確認を待つ
if (USB_GetEPState(IN_EP) == USB_IN_BUFFER_EMPTY) {
state_in = ST_PREPARING;
}
break;
default:
break;
}
}
}
}
"BULK-IN" もステートマシンで構成されています。 ST_PREPARING では、ホストに送信すべきデータをバッファに準備します。 USB_LoadInEP() によって DMA 転送が開始されて、 buffer_in[] に準備されたデータがエンドポイントに送られます。
ST_ACKWAIT では、ホストからの受信確認を待ちます。 DMA 転送が終わって、ホストから受信確認が到着したら、次のパケットの準備を行います。
転送速度の測定
プロジェクトが出来たら、転送速度を測定します。 "BULK-IN" は、 860kB/s でした。 前回の 850kB/s とほとんど変わりませんね。
"BULK-OUT" は、 690kB/s でした。 前回の 700kB/s よりも遅めになっています。
DMA を使っても転送速度が上がらなかったのは、扱っているデータが64バイトと DMA にとっては小さすぎるのが原因と考えられます。 もっと、パケットサイズが大きければ、効果があるのでしょう。
"BULK-IN" と "BULK-OUT" を同時に動かしたところ、双方とも 560kB/s になりました。 ステートマシンを使っても代わる代わる転送が行われる状況に変化はないようです。
以上、 "DMA" モードを使った場合の転送速度を測定しましたが、単純にパケットを送受信するだけでは、 "Manual" モードとの差は出ないという事がわかりました。 きっと、演算を行わせながら使うと、全体のスループットに貢献するのでしょう。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、 このファイル の拡張子を "zip" に変更すると再現できます。
関連商品

CY8CKIT-059 PSoC 5LP Prototyping Kit
- 出版社/メーカー: スイッチサイエンス
- メディア: エレクトロニクス
この記事へのコメント
お世話になっております。Eleven Tenthsの板野です。
先日ご連絡させていただいた電子部品のオンライン販売会社とのコラボレーションのご相談につきまして、ご検討状況はいかがでしょうか。
具体的な内容につきましてはご意向を伺いながら、ご相談させていただけますと幸いです。是非ご意向をお聞かせいただけましたら幸いです。
もし、ご検討にあたり不明点がございましたら、いつでもご連絡いただければと存じます。
ご協力いただけると大変光栄でございます。
ご連絡をお待ちしております。
Eleven Tenths 板野
Japanese SEO / Content Writer
seina@eleven-tenths.com