背景
USB MIDI I/F を M5Stack CoreS3 に接続してアレコレやりたくて M5Stack用MAX3421E搭載 USBモジュール なるものを購入。
S3で使用できるかよく分からなかったが、「DIPスイッチにより異なるホストを調整可能」と書いてあるので何とかなるだろうと思い購入。
案の定そのままでは動作しなかった。
M5Stack Basic では USB Host Shield Library (https://github.com/felis/USB_Host_Shield_2.0) が使用可能だったため何の問題もなかったが、M5Stack CoreS3ではビルドできずダメだった。
調査
USB_Host_Shield_2.0のソースコードを調べてみたところ、M5Stack Basic では if defined(ESP32) のところに引っかかって正しいピンアサインになるようだ。
MAKE_PIN(P19, 19); // MISO
MAKE_PIN(P23, 23); // MOSI
MAKE_PIN(P18, 18); // SCK
MAKE_PIN(P5, 5); // SS
MAKE_PIN(P17, 17); // INT
M5Stack用MAX3421E搭載 USBモジュールのPIN MAPは以下にある通り
※スイッチサイエンスページから
INTだけはMAPに出てこないが他はPIN MAP通り。
M5Stack CoreS3は PIN MAPより MOSI 37, MISO 35, SCK 36 にする必要があるが、avrpins.h にはそのような定義値はないようなので追加する。
まず、M5Stack CoreS3でビルドするとき定義されているdefine値を調べた。
ビルドオプションに -DARDUINO_M5STACK_CORES3 と指定されているようなので
if defined(ARDUINO_M5STACK_CORES3)
が使えるとわかった。気をつけないといけないのが、ビルドオプションに-DESP32も指定されている点。順序を間違えるとavrpins.hの中でif defined(ESP32)のところに入ってしまい、PINがM5Stack BASICと変わらないという罠に一度だけハマった。
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
~
~
#elif defined(ARDUINO_M5STACK_CORES3)
#elif defined(ESP32)
~
PIN設定
~
#endif
こんな感じ。
対策
ということで、#elif defined(ESP32)の手前に追加した部分だけ抜粋したソースコードを以下に。
#elif defined(ARDUINO_M5STACK_CORES3)
// Workaround strict-aliasing warnings
#ifdef pgm_read_word
#undef pgm_read_word
#endif
#ifdef pgm_read_dword
#undef pgm_read_dword
#endif
#ifdef pgm_read_float
#undef pgm_read_float
#endif
#ifdef pgm_read_ptr
#undef pgm_read_ptr
#endif
#define pgm_read_word(addr) ({ \
typeof(addr) _addr = (addr); \
*(const unsigned short *)(_addr); \
})
#define pgm_read_dword(addr) ({ \
typeof(addr) _addr = (addr); \
*(const unsigned long *)(_addr); \
})
#define pgm_read_float(addr) ({ \
typeof(addr) _addr = (addr); \
*(const float *)(_addr); \
})
#define pgm_read_ptr(addr) ({ \
typeof(addr) _addr = (addr); \
*(void * const *)(_addr); \
})
// Pinout for ESP32 dev module
MAKE_PIN(P0, 0);
MAKE_PIN(P43, 43); // TX0
MAKE_PIN(P17, 17); // TX1
MAKE_PIN(P44, 44); // RX0
MAKE_PIN(P21, 21); // SDA
MAKE_PIN(P22, 22); // SCL
MAKE_PIN(P35, 35); // MISO
MAKE_PIN(P37, 37); // MOSI
MAKE_PIN(P36, 36); // SCK
MAKE_PIN(P1, 1); // SS
MAKE_PIN(P14, 14); // INT
#elif defined(ESP32)
#elif defined(ARDUINO_M5STACK_CORES3)
typedef MAX3421e<P1, P14> MAX3421E; // ESP32S3 boards
#elif defined(ESP32)
#elif defined(ARDUINO_M5STACK_CORES3)
typedef SPi< P36, P37, P35, P1 > spi;
#elif defined(ESP32)
DIPスイッチは変更なし(全てON)。
これでM5Stack用MAX3421E搭載 USBモジュールをM5Stack CoreS3で使えるようになった。USB Host Shield 2.0のサンプルが動作するようになったので、usbh_midi.h を使いMIDI I/Fを接続してイベントのやり取りができるようになった。
おそらく、M5Stack Core2も同様にやれば動くのだと思う。
※冒頭に「DIPスイッチにより異なるホストを調整可能」と書かれていたと書いたが結局何も変更しなかった。
なお、ちょうど下記PRで似たような変更を実施した形跡があるので参考に。
2024/11/12 追記
出来たと思っていたが、USB Host Shield 2.0のWiimote系サンプルでBluetooth dongleが認識せず。Core2でも同様。M5Stack Basicだと動作するので上記対応だと何かまだ問題があるようだ。
2024/11/14 追記
M5Stack CoreS3用バッテリーボトムを付けるとUSB機器を認識しなくなることがわかった。また一度取り付けて認識しなくなると、リセットはおろか焼き直しても駄目であることもわかった。Pin Mapを見る限り競合しているPinはないように見えるのだが…真因までは特定できていない。M5BurnerでUIFlow2.0を焼いて、また焼きなおすと直った。焼くときはリセット長押して焼きモードにすること。
またArduino IDEを開きながらM5Burnerで焼くときにはシリアルモニタを閉じることを忘れずに。
2024/11/14 追記その2
さらにわかったこと
焼いた後にバッテリーボトム付け替えはしてはいけないようだ。
USB Module, バッテリーボトムを接続した状態で M5Burner で CoreS3 UserDemo を焼き、その後目的のスケッチを焼き直すことで バッテリーボトムを付けたままUSB機器は認識されるようになった。
2024/11/14 追記その3
さらにわかったこと
やはりバッテリーボトムは付けてはいけない。追記その2一時期はできたがすぐにできなくなった。液晶画面も消えたりするので相性が悪いのか、やめた方が良い。
もしバッテリーが欲しかったらUSB Moduleにバッテリーを直接挿せば良い。