PIC32MZシリーズ②USB OTGモジュールの使い方

PIC32MZシリーズ

概要

PIC32MZシリーズは発売から約10年が経過しましたが、現在も現役のPICシリーズの中で高いパフォーマンスを誇るモデルです。その中でも特筆すべきは、USBハイスピード(480Mbps)に対応している点です。今回は、このUSBモジュールの活用方法についてご紹介いたします。

更新日更新内容
2025/3/23初版公開
2025/3/28誤記修正

関連記事

内部リンク

記事リンク先
第1回DMAモジュールの使い方PIC32MZシリーズ1①DMAモジュールの使い方 – ぴくおの電子工作的な何かWP
第2回(本記事)USBモジュールの使い方PIC32MZシリーズ②USB OTGモジュールの使い方 – ぴくおの電子工作的な何かWP

外部リンク

タイトルリンク先
MINI-32
プロダクトサイト
MINI-32 for PIC32MZ – compact PIC32MZ development board | MikroElektronika
MINI-32
回路図
mini-32-pic32-manual-v101.pdf (mikroe.com)
PIC32MZ1024EFH064
プロダクトサイト
PIC32MZ1024EFH064 | Microchip Technology
PIC32MZ1024EFH064
データシート
PIC32MZ Embedded Connectivity with Floating Point Unit (EF) Family Data Sheet

開発環境

項目リンク
ベースボードMINI-32 for PIC32ボードMINI-32 for PIC32MZ – compact PIC32MZ development board | MikroElektronika
統合開発環境MPLAB X IDE v6.25MPLAB® X IDE | Microchip Technology
コンパイラMPLAB XC32 v4.60MPLAB® XC Compilers | Microchip Technology
デバイスファミリーパックPIC32MZ-EF_DFP
1.4.168
(fig.1)MINI-32 for PIC32ボード外観

USBモジュールについて

概要

ユニバーサル・シリアル・バス(USB)モジュールは、アナログおよびデジタルコンポーネントを含んでおり、最小限の外部コンポーネントでUSB 2.0の組み込みホスト、デバイス、またはOTG(On-The-Go)実装を提供します。このモジュールは、Hi-Speed、Full-Speed、またはLow-Speedをすべての動作モードでサポートしています。ホストモードでは、このモジュールは組み込みホストとして使用されることを目的としており、UHCIまたはOHCIコントローラは実装していません。

USBモジュールは、RAMコントローラ、パケットのエンコード/デコード、UTM同期、エンドポイント制御、専用のUSB DMAコントローラ、プルアップおよびプルダウン抵抗器、レジスタインターフェースで構成されております。

USBモジュールの特徴

1.USB通信速度のサポート:
Hi-Speed、Full-Speed、Low-Speedに対応しており、ホストおよびデバイス両方で利用可能です。

2.OTG機能(On-The-Go):
一つ以上のHi-Speed、Full-Speed、Low-Speedデバイスと通信できるOTG機能をサポートします。

3.統合コンポーネント:
信号用抵抗器、アナログコンパレータ、USBトランシーバが組み込まれており、外部部品を最小限に抑えます。

4.ハードウェアによる通信管理:
トランザクションのハンドシェイキングがハードウェアで行われ、効率的なデータ転送を実現します。

5.DMA(Direct Memory Access)機能:
8チャネルのDMAが組み込まれ、システムのRAMやフラッシュメモリと高速でデータをやり取りできます。

6.エンドポイントのサポート:
最大7つの送信エンドポイント、7つの受信エンドポイント、およびエンドポイント0をサポートし、複数のデータストリームを処理可能です。

7.電力管理機能:
サスペンドおよび再開信号のサポートやリンク電力管理機能を提供し、効率的な電力使用を実現します。

8.FIFOメモリの動的管理:
FIFOのサイズが動的に変更可能で、必要に応じてメモリの使用を最適化します。

9.システムRAMの削減:
組み込みRAMを使用してFIFOを管理するため、外部システムRAMを使う必要がありません。

USBモジュールブロック図

USB OTGモジュールのブロック図を示します。
USBに関する知識は非常に複雑で、すべてを詳細に説明すると本一冊分にもなりかねませんが、本サイトではそのすべてを割愛し、USB通信ができることを目的に、簡単に説明しています。他サイトを参照すれば、USBのより深い技術的な詳細や、特定の実装方法について学ぶことができますが、本サイトでは、USB通信の基本的な理解を提供し、実際に通信ができる環境を構築するための情報を中心に紹介しています。

(fig.2)PIC32MZ Embedded Connectivity with Floating Point Unit (EF) Family データシート(S60001320H-page 210)より抜粋

レジスタ

USBに関するレジスタは非常に豊富なため、ここでは割愛いたします。
Harmonyが制御関数を作成してくれますので、レジスタの詳細を知らなくてもUSB通信を行うことは可能です。

1.送信スループット計測

目的

一般的に、マイコンとパソコン間で簡単に通信を行う際には、USB-UART変換ICなどのインターフェースが使用されます。扱いやすさが特徴ですが、通信速度は数Mbps(経験的に2~3Mbps)が限界です。低速なデータ通信では問題ありませんが、高速なデータ通信を行う場合、帯域が不足することがあります。

PIC32MZのUSBモジュールはUSBハイスピード(480Mbps)に対応しているため、理論的には100倍以上の高速通信が可能です。しかし、データ処理はマイコンで行うため、480Mbpsでの通信は現実的には難しいと考えられます。今回は、その実際の通信速度を調査してみたいと思います。

ブロック図

構成は以下の通りです。ステートマシンを使用してデータをひたすら送信し、PCで受信したデータとそのスループットを計測します。

(fig.3)ブロック図

プロジェクトの生成

①新規プロジェクトを生成します。

②MCCを立ち上げ、「CDC Function Driver」を追加します。追加後、複数のモジュール追加ダイアログが自動で表示されますので、RTOS以外の項目にはすべて「Yes」を選択してください。

細かい設定も有りますが、今回の仕様ではこれだけで大丈夫なので、「Generate」をクリックして、ソースコードを生成します。

③生成されたApp.hとApp.cをそれぞれ以下のコードと差し替えます。

■App.h



#ifndef _APP_H
#define _APP_H


// *****************************************************************************
// *****************************************************************************
// インクルードファイル
// *****************************************************************************
// *****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "configuration.h"
#include "definitions.h"

// *****************************************************************************
// *****************************************************************************
// Section: Type Definitions
// *****************************************************************************
// ***************************************************************************** 
#define APP_READ_BUFFER_SIZE                                4096

#define USE_TEST_SPI 0
#define USE_TEST_DMA 1


typedef enum
{
   /* アプリケーションの状態機械の初期状態 */
    APP_STATE_INIT=0,

    /* アプリケーションがデバイス設定を待機している状態 */
    APP_STATE_WAIT_FOR_CONFIGURATION,

    /* アプリケーションがスイッチが押されたかどうかを確認する状態 */
    APP_STATE_CHECK_SWITCH_PRESSED,

    /* 受信した文字を待機する状態 */
    APP_STATE_SCHEDULE_READ,

    /* ホストから文字が受信される状態 */
    APP_STATE_WAIT_FOR_READ_COMPLETE,

    /* TXの完了を待機する状態 */
    APP_STATE_SCHEDULE_WRITE,

    /* 書き込みの完了を待機する状態 */
    APP_STATE_WAIT_FOR_WRITE_COMPLETE,

    /* アプリケーションエラー状態 */
    APP_STATE_ERROR

} APP_STATES;




typedef struct
{
  /* デバイス層のオープン関数から返されるデバイス層ハンドル */
    USB_DEVICE_HANDLE deviceHandle;

    /* アプリケーションの現在の状態 */
    APP_STATES state;

    /* セットラインコーディングデータ */
    USB_CDC_LINE_CODING setLineCodingData;

    /* デバイスの設定状態 */
    bool isConfigured;

    /* ゲットラインコーディングデータ */
    USB_CDC_LINE_CODING getLineCodingData;

    /* 制御ライン状態 */
    USB_CDC_CONTROL_LINE_STATE controlLineStateData;

    /* 読み取り転送ハンドル */
    USB_DEVICE_CDC_TRANSFER_HANDLE readTransferHandle;

    /* 書き込み転送ハンドル */
    USB_DEVICE_CDC_TRANSFER_HANDLE writeTransferHandle;

    /* 文字が読み取られた場合はTrue */
    bool isReadComplete;

    /* 文字が書き込まれた場合はTrue */
    bool isWriteComplete;

    /* スイッチが押された場合はTrue */
    bool isSwitchPressed;

    /* スイッチの押下を無視する必要がある場合はTrue */
    bool ignoreSwitchPress;

    /* SOFイベントが発生したかどうかを決定するフラグ */
    bool sofEventHasOccurred;

    /* ブレークデータ */
    uint16_t breakData;

    /* スイッチのデバウンスタイマー */
    unsigned int switchDebounceTimer;

    /* スイッチのデバウンスタイマーのカウント */
    unsigned int debounceCount;

    /* アプリケーションのCDC読み取りバッファ */
    uint8_t * cdcReadBuffer;

    /* アプリケーションのCDC書き込みバッファ */
    uint8_t * cdcWriteBuffer;

    /* ホストから読み取ったバイト数 */
    uint32_t numBytesRead; 
} APP_DATA;


void APP_Initialize ( void );
void APP_Tasks ( void );


#endif /* _APP_H */

■App.C



#include "app.h"


uint8_t CACHE_ALIGN switchPromptUSB[] = "\r\nPUSH BUTTON PRESSED";
uint8_t CACHE_ALIGN cdcReadBuffer[APP_READ_BUFFER_SIZE];
uint8_t CACHE_ALIGN cdcWriteBuffer[APP_READ_BUFFER_SIZE];

APP_DATA appData;

/*************************************************************************************/
/**
 * @brief USB CDCイベントハンドラー
 * 
 * この関数は、USB CDCデバイスのイベントを処理します。イベントに応じて、デバイスに対する適切なアクションを実行します。イベントの種類には、ラインコーディングの取得、設定、制御ラインの状態設定、データの送受信、制御転送の完了などが含まれます。
 * 
 * @param index デバイスインデックス
 * @param event 発生したUSB CDCイベント
 * @param pData イベントに関連するデータ
 * @param userData ユーザーデータ(アプリケーションデータオブジェクトへのポインタ)
 * 
 * @return USB_DEVICE_CDC_EVENT_RESPONSE イベント処理の結果
 */
/*************************************************************************************/
USB_DEVICE_CDC_EVENT_RESPONSE APP_USBDeviceCDCEventHandler
(
    USB_DEVICE_CDC_INDEX index,
    USB_DEVICE_CDC_EVENT event,
    void * pData,
    uintptr_t userData
)
{
    APP_DATA * appDataObject;
    USB_CDC_CONTROL_LINE_STATE * controlLineStateData;
    USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE * eventDataRead;
    
    appDataObject = (APP_DATA *)userData;

    switch(event)
    {
        case USB_DEVICE_CDC_EVENT_GET_LINE_CODING:

            /**
             * @brief ホストが現在のラインコーディングを取得したい場合の処理
             * 
             * これは制御転送リクエストです。USB_DEVICE_ControlSend()関数を使用してデータをホストに送信します。
             */
            USB_DEVICE_ControlSend(appDataObject->deviceHandle,
                    &appDataObject->getLineCodingData, sizeof(USB_CDC_LINE_CODING));

            break;

        case USB_DEVICE_CDC_EVENT_SET_LINE_CODING:

            /**
             * @brief ホストがラインコーディングを設定したい場合の処理
             * 
             * これは制御転送リクエストです。USB_DEVICE_ControlReceive()関数を使用してデータをホストから受信します。
             */
            USB_DEVICE_ControlReceive(appDataObject->deviceHandle,
                    &appDataObject->setLineCodingData, sizeof(USB_CDC_LINE_CODING));

            break;

        case USB_DEVICE_CDC_EVENT_SET_CONTROL_LINE_STATE:

            /**
             * @brief ホストが制御ラインの状態を設定した場合の処理
             * 
             * 制御ライン状態を読み取り、このリクエストを受け入れます。
             */

            controlLineStateData = (USB_CDC_CONTROL_LINE_STATE *)pData;
            appDataObject->controlLineStateData.dtr = controlLineStateData->dtr;
            appDataObject->controlLineStateData.carrier = controlLineStateData->carrier;

            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);

            break;

        case USB_DEVICE_CDC_EVENT_SEND_BREAK:

            /**
             * @brief ホストが指定した期間のブレーク信号を送信するリクエスト
             * 
             * ブレークの期間を読み取り、その後ZLP(ゼロ長パケット)を送信して制御転送を完了します。
             */
            appDataObject->breakData = ((USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK *)pData)->breakDuration;
            
            /* Complete the control transfer by sending a ZLP  */
            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
            
            break;

        case USB_DEVICE_CDC_EVENT_READ_COMPLETE:

            /**
             * @brief ホストからデータが送信された後の処理
             * 
             * データが正常に受信されると、受信完了フラグをセットし、読み取ったバイト数を更新します。
             */
            eventDataRead = (USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE *)pData;
            
            if(eventDataRead->status != USB_DEVICE_CDC_RESULT_ERROR)
            {
                appDataObject->isReadComplete = true;
                
                appDataObject->numBytesRead = eventDataRead->length; 
            }
            break;

        case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

            /**
             * @brief 最後の制御転送のデータステージが完了した場合の処理
             * 
             * 現在は受け取ったデータをそのまま受け入れ、制御転送の完了を通知します。
             */

            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
            break;

        case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_SENT:

            /**
             * @brief GET LINE CODINGのデータが有効であることを通知する場合の処理
             * 
             * このデモでは特に処理を行いません。
             */
            break;

        case USB_DEVICE_CDC_EVENT_WRITE_COMPLETE:

            /**
             * @brief データ書き込みが完了した場合の処理
             * 
             * 次の読み取り処理をスケジュールします。
             */

            appDataObject->isWriteComplete = true;
            break;

        default:
            break;
    }

    return USB_DEVICE_CDC_EVENT_RESPONSE_NONE;
}
/*************************************************************************************/
/**
 * @brief USBデバイスイベントハンドラー
 * 
 * この関数は、USBデバイスのさまざまなイベントを処理します。イベントに応じて、デバイスの状態を更新したり、LEDの状態を変更したり、CDCアプリケーションイベントハンドラーを設定したりします。イベントには、SOF、リセット、設定、電力の検出/削除、サスペンド、再開、エラーなどが含まれます。
 * 
 * @param event 発生したUSBデバイスイベント
 * @param eventData イベントに関連するデータ
 * @param context ユーザーデータ(アプリケーションのコンテキスト)
 */
/*************************************************************************************/
void APP_USBDeviceEventHandler 
(
    USB_DEVICE_EVENT event, 
    void * eventData, 
    uintptr_t context 
)
{
    USB_DEVICE_EVENT_DATA_CONFIGURED *configuredEventData;

    switch(event)
    {
        case USB_DEVICE_EVENT_SOF:

            /**
             * @brief SOF (Start of Frame) イベント
             * 
             * このイベントはスイッチのデバウンス処理に使用されます。フラグはスイッチ
			 * 処理ルーチンによってリセットされます。
             */
            
            break;

        case USB_DEVICE_EVENT_RESET:
            /**
             * @brief リセットイベント
             * 
             * デバイスがリセットされたことを示します。LEDの状態をリセット状態に
			 * 更新します。
             */

            appData.isConfigured = false;

            break;

        case USB_DEVICE_EVENT_CONFIGURED:

            /**
             * @brief デバイス設定イベント
             * 
             * デバイスの設定が行われた場合に発生します。設定を確認し、設定が1で
			 * あればCDCデバイスアプリケーションイベントハンドラーを設定します。
             */
            configuredEventData = (USB_DEVICE_EVENT_DATA_CONFIGURED*)eventData;
            
            if ( configuredEventData->configurationValue == 1)
            {
                /* CDCデバイスアプリケーションイベントハンドラーを設定します。
                 * appDataオブジェクトのポインタがユーザーデータとして渡されます */

                USB_DEVICE_CDC_EventHandlerSet(USB_DEVICE_CDC_INDEX_0, APP_USBDeviceCDCEventHandler, (uintptr_t)&appData);

                 /* デバイスが設定されていることをマーク */
                appData.isConfigured = true;
            }
            
            break;

        case USB_DEVICE_EVENT_POWER_DETECTED:

            /**
             * @brief 電力が検出された場合
             * 
             * VBUSが検出され、デバイスをアタッチできる状態になります。
             */
            USB_DEVICE_Attach(appData.deviceHandle);
            
            break;

        case USB_DEVICE_EVENT_POWER_REMOVED:
            /**
             * @brief 電力が削除された場合
             * 
             * VBUSが利用できないため、デバイスをデタッチし、設定状態を解除します。
             */
            USB_DEVICE_Detach(appData.deviceHandle);
            
            appData.isConfigured = false;
            
            break;

        case USB_DEVICE_EVENT_SUSPENDED:
            /**
             * @brief サスペンドイベント
             * 
             * デバイスがサスペンド状態に入った場合に発生します。LEDをサスペンド
			 * 状態に変更します。
             */
            // LEDの状態をオフに更新
            
            break;

        case USB_DEVICE_EVENT_RESUMED:
        case USB_DEVICE_EVENT_ERROR:
        default:
            
            break;
    }
}
/*************************************************************************************/
/**
 * @brief デバイスのリセット状態を確認し、リセット処理を実行する関数
 * 
 * この関数は、デバイスがリセット状態にあるかどうかを確認し、必要な場合はリセット
 * 処理を行います。リセット処理では、状態を「APP_STATE_WAIT_FOR_CONFIGURATION」に
 * 変更し、読み取り/書き込み転送ハンドルを無効にし、通信のフラグをリセットします。
 * リセットが成功した場合は true を返し、リセットが不要な場合は false を返します。
 * 
 * @return bool リセットが行われた場合は true、それ以外の場合は false
 */
/*************************************************************************************/
bool APP_StateReset(void)
{
    /* この関数は、デバイスがリセットされた場合に true を返します */
    bool retVal;

    if(appData.isConfigured == false)
    {
        appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
        appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
        appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
        appData.isReadComplete = true;
        appData.isWriteComplete = true;
        retVal = true;
    }
    else
    {
        retVal = false;
    }

    return(retVal);
}
/*************************************************************************************/
/**
 * @brief アプリケーションの初期化処理
 * 
 * この関数は、アプリケーションの状態を初期化します。状態機械を初期状態に設定し、
 * デバイスの設定、読み取りおよび書き込み転送ハンドルの初期化、ラインコーディングの
 * 初期設定、スイッチのデバウンスカウンタのリセットなど、必要なすべての初期化を
 * 行います。これにより、アプリケーションが正常に動作するための準備が整います。
 * 
 * @note この関数は、アプリケーションが開始されると最初に呼ばれるべきです。
 */
/*************************************************************************************/
void APP_Initialize(void)
{
    /* アプリケーションの状態機械を初期状態に設定 */
    appData.state = APP_STATE_INIT;
    
    /* デバイス層ハンドルの初期化 */
    appData.deviceHandle = USB_DEVICE_HANDLE_INVALID ;

    /* デバイス設定状態の初期化 */
    appData.isConfigured = false;

    /* 初期ラインコーディングの状態設定 */
    appData.getLineCodingData.dwDTERate = 9600;
    appData.getLineCodingData.bParityType = 0;
    appData.getLineCodingData.bCharFormat= 0; 
    appData.getLineCodingData.bDataBits = 8;

    /* 読み取り転送ハンドルの初期化 */
    appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;

    /* 書き込み転送ハンドルの初期化 */
    appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;

    /* 読み取り完了フラグの初期化 */
    appData.isReadComplete = true;

    /* 書き込み完了フラグの初期化 */
    appData.isWriteComplete = true;

    /* スイッチ無視フラグの初期化 */
    appData.ignoreSwitchPress = false;

    /* スイッチデバウンスカウンタのリセット */
    appData.switchDebounceTimer = 0;

    /* その他のフラグをリセット */
    appData.sofEventHasOccurred = false;
    
    /* スイッチの状態を知るためのフラグ */
    appData.isSwitchPressed = false;

    /* 読み取りバッファの設定 */
    appData.cdcReadBuffer = &cdcReadBuffer[0];

    /* 書き込みバッファの設定 */
    appData.cdcWriteBuffer = &cdcWriteBuffer[0];       
}


/*************************************************************************************/
/**
 * @brief アプリケーションのタスク処理
 * 
 * この関数は、アプリケーションの状態機械を更新し、現在の状態に応じた処理を実行します。
 * 状態に基づいてデバイスの初期化、読み取りおよび書き込み処理をスケジュールします。
 * また、必要に応じてUSBデバイスのイベントを処理し、エラー状態に遷移する場合が
 * あります。
 * 
 * @note この関数は、アプリケーションのメインループ内で呼ばれるべきです。
 */
/*************************************************************************************/
void APP_Tasks(void)
{
    /* 現在の状態に基づいてアプリケーションの状態機械を更新 */
    int i,ascc;

    switch(appData.state)
    {
        case APP_STATE_INIT:

            /* 初期状態: デバイス層をオープン */
            appData.deviceHandle = USB_DEVICE_Open( USB_DEVICE_INDEX_0, DRV_IO_INTENT_READWRITE );

            if(appData.deviceHandle != USB_DEVICE_HANDLE_INVALID)
            {
                /* デバイスイベントハンドラを登録 */
                USB_DEVICE_EventHandlerSet(appData.deviceHandle, APP_USBDeviceEventHandler, 0);

                appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
            }
            else
            {
                 /* デバイス層が準備できていない場合、後で再試行 */
            }

			ascc = 21;
			for(i = 0; i < 4095; i++)
            {
                appData.cdcWriteBuffer[i] = ascc++;
				if (ascc > 126) ascc = 21;
            }
			
            break;

        case APP_STATE_WAIT_FOR_CONFIGURATION:

            /* デバイスが設定されるのを待機 */
            if(appData.isConfigured)
            {
                 /* 設定が完了した場合、書込み処理を開始 */
                appData.state = APP_STATE_SCHEDULE_WRITE;
            }
            
            break;

        case APP_STATE_SCHEDULE_READ:
			/* 読み取りスケジュール */

            if(APP_StateReset())
            {
                break;
            }

            /* 読み取りが完了している場合、次の読み取りをスケジュール */

            if(appData.isReadComplete == true)
            {
                appData.isReadComplete = false;
                appData.readTransferHandle =  USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;

                USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
                        &appData.readTransferHandle, appData.cdcReadBuffer,
                        APP_READ_BUFFER_SIZE);
                
                if(appData.readTransferHandle == USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID)
                {
                    appData.state = APP_STATE_ERROR;
                    break;
                }
            }
			appData.state = APP_STATE_SCHEDULE_WRITE;
            break;

        case APP_STATE_WAIT_FOR_READ_COMPLETE:
			/* 読み取り完了を待機 */
            if(APP_StateReset())
            {
                break;
            }

             /* 読み取りまたはスイッチの押下状態をチェック */

            if(appData.isReadComplete )
            {
                appData.state = APP_STATE_SCHEDULE_WRITE;
            }

            break;


        case APP_STATE_SCHEDULE_WRITE:
			/* 書き込みスケジュール */
            if(APP_StateReset())
            {
                break;
            }

            appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
            appData.isWriteComplete = false;
            appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;


			USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
					&appData.writeTransferHandle,
					appData.cdcWriteBuffer, 2048,
					USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);

            break;

        case APP_STATE_WAIT_FOR_WRITE_COMPLETE:
			/* 書き込み完了を待機 */
            if(APP_StateReset())
            {
                break;
            }

            /* 書き込み完了フラグをチェック */
            if(appData.isWriteComplete == true)
            {
                appData.state = APP_STATE_SCHEDULE_WRITE;
            }

            break;

        case APP_STATE_ERROR:
        default:
            /* エラー状態: LEDを更新してエラーステータスを表示 */
            break;
    }
}

結果

シリアル通信のスループットを計測する適切なツールが見当たらなかったため、C#を使用して次の機能を持つアプリケーションを作成しました。

1.)データの受信および結合
2.)1秒間の受信スループットを表示

USB_DEVICE_CDC_Write関数の4番目の引数には、送信するデータのバイト数を指定します。この引数に256、512、1024、2048といった値を設定した結果、最大で200Mbps近いデータ転送速度が達成できることが確認されました。

USB_DEVICE_CDC_Write(
 USB_DEVICE_CDC_INDEX_0,
 &appData.writeTransferHandle,
 appData.cdcWriteBuffer, 
 2048,
 USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);

記事についての注意点

本記事は慎重に内容を検討し正確さに努めておりますが、内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント

タイトルとURLをコピーしました