WFI32EによるUDP通信でのスループット計測

WFI32 Curiosity Development Board

概要

WFI32 Cutiosity Board とPC間のUDP通信において、スループットを計測してみます。なお結果に関しては構築環境によって大きく変わると思われますので、あくまでも参考程度に捉えて下さい。

WFI32 Cutiosity Boardについてはこちらで紹介しています。

全体構成

スループット計測するため、以下の環境を構成しました。

  • ONU & 無線LANルータ … アクセスポイント/DHCPサーバ/ルータ-等
  • PC … ソフトビルド用、UDPクライアント実行、パケット解析実行
  • USB-Uart変換ボード … WFI動作確認用
  • UDP/IPテストツール … UDPクライアント
  • WFI32 Curiosity Boad… UDPサーバ
  • WireShark … パケット解析用
(fig.1)UDPスループット計測構成

開発の進め方

1.GitLabからのサンプルプロジェクトダウンロード

GitHubのGitHub – マイクロチップ-MPLAB-ハーモニー/ワイヤレス:ハーモニー3ワイヤレスソリューションページから「UDPサーバ」をクリックし、TCPの時と同じようにダウンロードし、プロジェクトをコピーし開きます。

2.MPLAB X IDEでの操作

基本的にはTCPの時と同じで「Harmony」上で「Net Service」をクリックし以下の設定を行い、コード出力します。

項目
Instance 0チェック
IntfWIFI
Ip ProtocolUDP
ModeSERVER
Server Port3333
Host Name/ IP Address192.168.0.1(ここは適当で良い)
(fig.2) 最低入力項目

スループット計測のためのApp.cソース変更

スループット計測のため以下のようにApp.cのコードを変更します。

UDPクライアント側から「’S’」(Start)のメッセージを受信すると、 APP_Tasks()関数の中で512Byte固定のダミーメッセージを連続して送信し、「’P’」(stoP)の メをッセージを受信すると 、送信を停止します。またポートAの11bitをHigh/Lowさせて処理時間をモニタします。

#include "system/net/sys_net.h"



SYS_NET_Config      g_udpServCfg;
SYS_MODULE_OBJ      g_udpServHandle = SYS_MODULE_OBJ_INVALID;

#define RECV_BUFFER_LEN		1400
uint8_t recv_buffer[RECV_BUFFER_LEN + 1];

#define SEND_BUFFER_LEN		1400
uint8_t Snd_buffer[SEND_BUFFER_LEN + 1];

uint8_t Mode;

void UdpServCallback(uint32_t event, void *data, void* cookie)
{
    switch(event)
    {
        case SYS_NET_EVNT_CONNECTED:
        {
            SYS_CONSOLE_PRINT("UdpServCallback(): Status UP\r\n");
            while(SYS_NET_SendMsg(g_udpServHandle, (uint8_t *)"hello", 5) == 0);
            break;
        }

        case SYS_NET_EVNT_DISCONNECTED:
        {
            SYS_CONSOLE_PRINT("UdpServCallback(): Status DOWN");
            break;
        }

        case SYS_NET_EVNT_RCVD_DATA:
        {
            int32_t cumm_len = 0;
            int32_t len = RECV_BUFFER_LEN;
            while(len == RECV_BUFFER_LEN)
            {
                len = SYS_NET_RecvMsg(g_udpServHandle, recv_buffer, RECV_BUFFER_LEN);
                if(len>0)
                {
                    if(cumm_len == 0)
                    {

                        if (recv_buffer[0] == 'S')
                        {
                            Mode = 1;
                        }
                        if (recv_buffer[0] == 'P')
                        {
                            Mode = 0;
                        }
                    }
                }
            }
           
            break;
        }
        
        case SYS_NET_EVNT_LL_INTF_DOWN:
        {
            /* 
            ** User needs to take a decision if they want to close the socket or
            ** wait for the Lower layer to come up
             */
            SYS_CONSOLE_PRINT("UdpServCallback(): Lower Layer Down\r\n");
            break;
        }
        
        case SYS_NET_EVNT_LL_INTF_UP:
        {
            /* 
            ** The lower layer was down and now it has come up again. 
            ** The socket was in connected state all this while
             */
            SYS_CONSOLE_PRINT("UdpServCallback(): Lower Layer Up\r\n");
            break;
        }                
    }
}


APP_DATA appData;

void APP_Initialize ( void )
{
    memset(Snd_buffer,'1',512),
    Snd_buffer[512] = '\0';

    TRISAbits.TRISA11 = 0;
    
    SYS_CONSOLE_MESSAGE("APP_Initialize\n");
    
    appData.state = APP_TCPIP_INIT_DONE;
}

void APP_SYS_SRVC_Task()
{
    SYS_NET_Task(g_udpServHandle);
}



void APP_Tasks ( void )
{
    /* Check the application's current state. */
    switch ( appData.state )
    {
        case APP_TCPIP_INIT_DONE:
        {
            g_udpServHandle = SYS_NET_Open(NULL, UdpServCallback, 0); 
            if(g_udpServHandle != SYS_MODULE_OBJ_INVALID)
                SYS_CONSOLE_PRINT("UDP Service Initialized Successfully\r\n");

            
            appData.state = APP_TCPIP_WAITING_FOR_COMMAND;
            break;
        }

        case APP_TCPIP_WAITING_FOR_COMMAND:
        {
            LATAbits.LATA11 = 1;
            SYS_CMD_READY_TO_READ();
            if (Mode == 1)
            {
               SYS_NET_SendMsg(g_udpServHandle, Snd_buffer, 512);
            }
            LATAbits.LATA11 = 0;
        }
        break;
        
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
    APP_SYS_SRVC_Task();
}

結果

1.症状

当初WireSharkでパケットを分析すると、通信が非常に安定していない症状が発生しました。ピークでは2,700packet/sec × 512 = 11Mbps(ペイロード含めず)出ているにも関わらず、最低速の場合は200packet/sec = 820kbps/sec程度と13倍の速度差が発生しました。この原因を探ってみます。

(fig.3)WireSharkによるスループット計測

2.原因調査

まずはSYS_NET_SendMsg()関数の処理時間を計測します。

まず送信停止時はHigh ->Low間隔が128nsec、High→High間隔が3.3usecと安定して高速にループを回っている事が分かります。

(fig.4)停止時のPortA,11番ピンの状態

次に送信時ですが High ->Low間隔が最小50usec、 High→High間隔が最大50msec程度発生していました。何回か SYS_NET_SendMsg()関数を実行した後、長時間にわたって処理がブロッキングされています。

(fig.5) SYS_NET_SendMsg()関数 実行時間最小時
(fig.5) SYS_NET_SendMsg()関数 実行時間最大時

速度低下が大きい時はこのブロッキング時間が長くなり、高速に転送している時はこのブロッキング時間が短くなっています

次にWFI32をルータと同じ部屋(1F)に持って行って計測しました。グラフは数字が見切れていますが平均3,250パケット/秒程度 ≒14Mbpsで離れていた時より、安定して受信するようになりました。

(fig.6)スループット計測

これはMicrochipのWifi製品比較表 Wi-Fi Product Comparison Chart (microchip.com) によると、WFI32のUDPのUplink速度が14~18Mbpsとされているので、オーダー的にはこれ以上は劇的に速度向上することは無さそうです。

またスマホでネットワークテストを行った結果、赤矢印のように瞬間的に速度低下が見られました。また青色の部分に関しては、別のスマートフォンにて動画閲覧(1F)すると長時間速度低下が見られました。

当たり前といえばそうなのですが、今回改めてスループットを向上させるためには

まとめ
  • WFI32とアクセスポイント間の距離を短くする
  • 同時に無線を使用しない

という事が確認できました。

コメント

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