USBHostのインタラプト転送間隔について

28 Feb 2016

LPC1768でUSBHostライブラリを使い、XboxONEのコントローラと通信したいです。 一応はできているのですが、通信でデータを受け取る間隔がパソコンとの通信と比べ長いのです。 パソコンとの通信では最短8msおきにデータを受信できていたのですが、mbedとの通信だと最短でも32msおきにデータを受信します。 その影響で受信できないパケットがあり、困っています。 手持ちのマウスとの通信も試してみたのですが、パソコンとの通信だと最短8msおきにデータが受信できたものが、mbedとの通信だと32msおきにしかデータを受信できませんでした。 プログラムは下記のものを使用し、パソコンとの通信間隔はWiresharkで、mbedとの通信間隔はプログラム中のTimerで計りました。 何故32msおきにしかデータを受信できないのでしょうか、また、解決するためにはどうすればよいのでしょうか。

#include "mbed.h"
#include "USBHostMouse.h"

Serial pc(USBTX, USBRX);
DigitalOut led(LED1);
Timer timer;

void onMouseEvent(uint8_t buttons, int8_t x, int8_t y, int8_t z) {
    printf("buttons: %d, x: %d, y: %d, z: %d\r\n", buttons, x, y, z);
    std::printf("timer=%f\r\n", timer.read());
    timer.reset();
    timer.start();
}

void mouse_task(void const *) {
    
    USBHostMouse mouse;
    
    while(1) {
        // try to connect a USB mouse
        while(!mouse.connect())
            Thread::wait(500);
    
        // when connected, attach handler called on mouse event
        mouse.attachEvent(onMouseEvent);
        
        // wait until the mouse is disconnected
        while(mouse.connected())
            Thread::wait(500);
    }
}

int main() {
    pc.baud(115200);
    pc.printf("----------\r\n");
    Thread mouseTask(mouse_task, NULL, osPriorityNormal, 256 * 4);
    timer.start();
    while(1) {
        led=!led;
        Thread::wait(500);
    }
}
08 Mar 2016

こんにちは。

現象が再現したので、こちらで調べてみました。

インタラプト転送の間隔については、OHCI仕様書の「4.4.2.1 HccaInterruptTable」に説明があるように、32エントリの HccaInterruptTable テーブルに格納されたポインタが使用されるようです。このエントリに1つのみリストが含まれている場合は、32ms の周期でポーリングされ、32すべてにリストがあれば、1ms 周期になるようです。

現状の mbed USBHost ライブラリは、このテーブルの先頭のエントリのみを使用する実装になっているため、最少が 32ms の転送間隔になります。

これを強制的に最少 8ms の転送間隔にするには、USBHALHost_LPC17.cpp の updateInterruptHeadED() 関数を以下のように変更します。

void USBHALHost::updateInterruptHeadED(uint32_t addr) {
    usb_hcca->IntTable[0] = addr;
    // 以下のコードを追加
    usb_hcca->IntTable[8] = addr;
    usb_hcca->IntTable[16] = addr;
    usb_hcca->IntTable[24] = addr;
}

この変更は、ご提供していただいたテストコードでのみ動作を確認しています(なので、かなり無理やりです)。本来は、Endpoint Descriptor 構造体の bInterval を参照して適切に設定されるべきだと思います。

09 Mar 2016

返信ありがとうございます。 なるほど、やはり32ms周期固定だったのですね。 ご教示いただいた通りに転送間隔を変更し、全データを受け取れるようになりました!