2012年06月18日

Arduino Mega ADKで「Error: OSCOKIRQ failed to assert」発生の対策を打つ

Arduino Mega ADKで遊んでいて、電源投入直後に以下のようなログが出て動作しない現象に数回出くわしたので、なんでかな〜と思いつつ、その内見かけなくなってたので忘れていたのですが、今日出たので少し調べてみました。

ログ内容
Error: OSCOKIRQ failed to assert

Arduinoスケッチは、以下のようなシンプルにテスト用に書いたスケッチ。Arduino 1.0.1と、先日Googleからリリースされたばかりの新しいADKのパッケージ「adk_release_20120606」を使用しています。

#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>

AndroidAccessory acc("Yasuhiro ISHII",
"dummyADK",
"",
"1.0",
"",
"0000000012345678");

void setup()
{
  Serial.begin(115200);
  acc.powerOn();
}

void loop()
{
  byte buffer[64];
  if (acc.isConnected()) {
    acc.read(buffer, 1, 1);
  }
}

この「Error: OSCOKIRQ failed to assert」ってログは、USB Host shieldのライブラリのMAX3421E::powerOn()の以下の部分で出力されています。

/* MAX3421E initialization after power-on   */
void MAX3421E::powerOn()
{
    /* Configure full-duplex SPI, interrupt pulse   */
    regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB ));    //Full-duplex SPI, level interrupt, GPX
    if( reset() == false ) {                                //stop/start the oscillator
        Serial.println("Error: OSCOKIRQ failed to assert");
    }

でもって、MAX3421E::reset()は、こんな感じ。rUSBIRQ.bmOSCOKIRQが立つまたは256回タイムアウトするまで待ちます。

/* reset MAX3421E using chip reset bit. SPI configuration is not affected   */
boolean MAX3421E::reset()
{
  byte tmp = 0;
    regWr( rUSBCTL, bmCHIPRES );                        //Chip reset. This stops the oscillator
    regWr( rUSBCTL, 0x00 );                             //Remove the reset
    while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) {          //wait until the PLL is stable
        tmp++;                                          //timeout after 256 attempts
        if( tmp == 0 ) {
            return( false );
        }
    }
    return( true );
}

で、ここの処理のお手本を確認するため、Maxim社が公開してる、Max3421e EVボード用のサンプルコードで見ると、無限に安定待ちビットが立つまで待つようです。データシートを読んでみたのですが、安定待ちに必要な時間を見つけることができませんでした。書いてないということはないと思うので、見落としてるかも、です。

というわけで、では上記ループ何回待ってたら安定待ち出来てたのか、適当ですが、以下のような改変をしてみてみました。
/* reset MAX3421E using chip reset bit. SPI configuration is not affected   */
boolean MAX3421E::reset()
{
//  byte tmp = 0;
short tmp=0; // 変更yishii
    regWr( rUSBCTL, bmCHIPRES );                        //Chip reset. This stops the oscillator
    regWr( rUSBCTL, 0x00 );                             //Remove the reset
    while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) {          //wait until the PLL is stable
        tmp++;                                          //timeout after 256 attempts
        if( tmp == 0 ) {
            return( false );
        }
    }
Seria.print("pll stabilized");//変更yishii
Serial.println(tmp);//変更yishii
    return( true );
}
すると、だいたい350回くらいのところでOSCOKビットが立ってました。
というわけで、もちろん上記のようなMAX3421E::resetに改造を加えても回避可能ですが、ライブラリの派生版のせいでいろいろスケッチに互換性を失うのも嫌なので、ここはシンプルに、スケッチ側でpowerOnを呼び出すタイミングを遅らせたいと思います。
MAX3421Eクラスのコンストラクタが実行されてから、MAX3421E::resetで安定待ちするまでに時間待ちをはさめば良いので、以下のようにしました。コンストラクタが実行されてから、実際にsetupが実行されるまでの時間は、処理系やArduinoのマイコンのスタートアップ処理に依存するので、こんなことしなくても問題無くUSB Hostの初期化できる環境もあると思いますが・・・。

#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>

AndroidAccessory acc("Yasuhiro ISHII",
"dummyADK",
"",
"1.0",
"",
"0000000012345678");

void setup()
{
  Serial.begin(115200);
  delay(5); // ★5ms遅らす
  acc.powerOn();
}

void loop()
{
  byte buffer[64];
  if (acc.isConnected()) {
    acc.read(buffer, 1, 1);
  }
}

これで認識してくれるようになりました。
簡単なことなのですが、知らないうちは、はまりました。。。

ところで新しいADKのライブラリ見るとArduino IDE1.0対応をメインの改変としていると思います。
でも一部気になる所が、、、
$ diff ADK_release_0512/firmware/arduino_libs/AndroidAccessory/AndroidAccessory.cpp
ADK_release_20120606/arduino_libs/AndroidAccessory/AndroidAccessory.cpp
86,87c86,87
<     if (protocol == 1) {
<         Serial.print("device supports protcol 1\n");
---
>     if (protocol >= 1) {
>         Serial.print("device supports protocol 1 or higher\n");
あれ、もしかして新しいADKのバージョンリリースされるのかな〜??と勘ぐってしまいました。^^;


Arduino Mega ADK
Arduino Mega ADK
posted with amazlet at 12.06.18
スイッチサイエンス
売り上げランキング: 20537
Arduino Leonardo(+Headers)
Arduino Leonardo(+Headers)
posted with amazlet at 13.01.17
GHEO SA
売り上げランキング: 43,094
posted by いしいっち at 15:06| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする