So-net無料ブログ作成
検索選択

PSoC 5LP で BULK 転送 (2) [PSoC]このエントリーを含むはてなブックマーク#

回路図

前回の記事では、 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 転送速度

プロジェクトが出来たら、転送速度を測定します。 "BULK-IN" は、 860kB/s でした。 前回の 850kB/s とほとんど変わりませんね。


BULK OUT 転送速度

"BULK-OUT" は、 690kB/s でした。 前回の 700kB/s よりも遅めになっています。

DMA を使っても転送速度が上がらなかったのは、扱っているデータが64バイトと DMA にとっては小さすぎるのが原因と考えられます。 もっと、パケットサイズが大きければ、効果があるのでしょう。


送受信転送速度

"BULK-IN" と "BULK-OUT" を同時に動かしたところ、双方とも 560kB/s になりました。 ステートマシンを使っても代わる代わる転送が行われる状況に変化はないようです。

以上、 "DMA" モードを使った場合の転送速度を測定しましたが、単純にパケットを送受信するだけでは、 "Manual" モードとの差は出ないという事がわかりました。 きっと、演算を行わせながら使うと、全体のスループットに貢献するのでしょう。

プロジェクトアーカイブ

この記事で作成したプロジェクトは、 このファイル の拡張子を "zip" に変更すると再現できます。

関連商品

CY8CKIT-059 PSoC 5LP Prototyping Kit

CY8CKIT-059 PSoC 5LP Prototyping Kit

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。