文書の過去の版を表示しています。
ハイハイスクールアドベンチャー Raspberry Pico + LCD版
概要
ハイハイスクールアドベンチャー PicoCalc版を作ったついでといったら何ですが、PicoCalc のコアである Raspberry Pi PicoにLCDとかSDカードスロットとかキーボードとか繋げたら、別に PicoCalcじゃなくても遊べるじゃん? と、いうことで、ソースコードにちょいちょい手を入れて、仕立て上げたのがこれです。
pico1_lcd28 または pico2_lcd28 を選んでビルドすれば uf2ファイルが出来上がりますので適宜インストールしてください。
現状、Pico-ResTouch-LCD-2.8に、OTGアダプタをかませたUSBキーボード1)をサポートしています。
あれこれ
例によって、すぐ動くはずが、なかなか動かなかったあれこれを。
Pico-ResTouch-LCD-2.8
STT7789 という、よくあるコントローラで 240×320の液晶(タッチパネル/TFカードスロット込み)です。 LovyanGFX であっさり動くだろうと思っていたら、全然表示が来なくて大変苦労しました。
原因はバックライトのコントロールにありました。 LovyanGFXが用意してくれているのはGPIOピンからPWM制御で明るさをいじれる、そういうインターフェイスだけなのですが、こいつは、ずばりONかOFFかしかない様子。
今でもこのやり方が正しいのかわかりませんが、ピンにデジタルでHIGH/LOWを出すだけのバックライトインターフェイスを作成してそれを使うようにしたら、あっさり表示が来ました。
まあ、描画はされていたけれど、バックライトが真っ暗で何も見えていなかっただけというのが実際だったわけです。
namespace lgfx { inline namespace v1 { //---------------------------------------------------------------------------- class Light : public ILight { public: struct config_t { uint32_t freq = 1200; int16_t pin_bl = -1; uint8_t pwm_channel = 0; bool invert = false; }; const config_t& config(void) const { return _cfg; } void config(const config_t &cfg) { _cfg = cfg; } bool init(uint8_t brightness) override; void setBrightness(uint8_t brightness) override; private: config_t _cfg; uint8_t _slice_num; }; } }
namespace lgfx { inline namespace v1 { //---------------------------------------------------------------------------- bool Light::init( uint8_t brightness ) { gpio_init( _cfg.pin_bl ); gpio_set_dir( _cfg.pin_bl, GPIO_OUT ); gpio_put( _cfg.pin_bl, 1 ); setBrightness(brightness); return true; } void Light::setBrightness( uint8_t brightness ) { if (_cfg.invert) brightness = ~brightness; // uint32_t duty = brightness + (brightness >> 7); if (brightness == 0) digitalWrite(_cfg.pin_bl, LOW); else digitalWrite(_cfg.pin_bl, HIGH); } //---------------------------------------------------------------------------- } }
USBキーボード
BLEキーボード
Pico W/Pico 2WはWiFiとBTをサポートしていて、SDKにも btstack-1.6.2 2)が同梱されているので、理屈の上ではBLEのキーボードを、M5ATOMなんかと同じように接続できるはずなんです。
線がのたくりまわるのは好きではないので、最初にこっちを実装しようとしたのですが、サンプル見ても、Web界隈で調べても、例によってマイコンをBLEセントラルとして使っている事例は少ないんですよね。
実は未だ動いてないので、コードは同梱していませんが、とりあえず、色々実験はしているので、ここまでで得た知見を。
ビルド
そもそも、btstackはSDKに同梱になっているので、ヘッダだけインクルードしときゃ良しなにやってくれるだろうと思っていたら大間違いでした。 いえ、コンパイルは大体通ります。 ただ、山ほどリンクエラーが出て、最初ここで心が折れました。
ビルドするには以下シンボルを定義してないとダメらしいです。
-DPIO_FRAMEWORK_ARDUINO_ENABLE_BLUETOOTH -DPIO_FRAMEWORK_ARDUINO_ENABLE_BLE
接続の手順
まず、いろんなことがいろんなところに書いてあったりAIにいわれたりしますが、Pico W/Pico 2Wの場合、loop()の中ですることは特にはありません。
勝手に良しなにやってくれるので、やることは、初期化とあとはコールバック伝いに、Notificationを受け取るまでがやるべきことです。
手順としては以下のようになります。
- 初期化
- GATT Advertisementのスキャン-接続要求
- Characteristicsの取得
- CharacteristicsのDescriptorの取得
- 必要なサービスのCCCDに対して、Notification を要求する。
- Notificationの処理
簡単に見えるのですが、ちょっとメンドクサイのが、何かを要求すると、大体の場合、レポートがコールバック経由で渡され、これが COMPLETEのイベントが発生するまで続くので、次の要求はCOMPLETEを待たないといけない、ということと、COMPLETEのイベントが、GATTの場合はGATT_EVENT_QUERY_COMPLETE で大体が共有されいてるので、statusをどっかにとっておいて、今何をしているのか見て、処理を分けるか、リクエストごとに処理するコールバックを変えるかしないと何がなんだかわからなくなります。
Building a Bluetooth GATT Client on the Pi Pico Wという大変参考になるサイトがあるのですが、ここではGATTのコールバックを一つにまとめる代わりに state という変数で、今何の処理をやっているのかを管理して、イベントハンドラをコントロールしています。
わたしは、あんまりこういうやり方が好きじゃない3)ので、コールバックを分ける方法にしましたが、要するに、要求→レポート→COMPLETE→次の要求→……という流れなのを押さえておけば大丈夫です。
AIに聞くと、なんか動きそうなコードをくれるんですが、レポートの中で次の要求を出してしまうので大体動きません。 最初、AIとわたしで組んでいたのでわからなかったのですが、上のサイトのおかげでようやく原因がわかりました。
セキュア接続
さて、BLEキーボードの大半はセキュアな接続でないとキー入力のNotificationを送ってくれません。 要求を出すと、state=154)で失敗してしまいます。
わたしの手元にあるバッファローのBLEキーボードとM5 CardputerのおまけでついてくるBLEキーボードだけがセキュア接続でなくてもつながるキーボードなので、つまりは、大体の場合セキュアじゃないとダメなのです。5)
さて、世間には、実は Pico W + btstack でセキュア接続をして BLE Centralとして動作させているという事例があまりないようだし、AIもいろいろ教えてくれるんですが、簡単にいうと、セキュア接続要求がstate=8で失敗して先へ進めないのが現状です。
まあ、セキュアじゃなくてもつながるキーボードなら多分つながるのでそれでよしとするというのもありでしょうけれど、なんかあとちょっとの工夫で動くんじゃないかっていう気がするので、あきらめがつきません。
識者の見解を待ちます!