Mbed x PlatformIOで手動バージョンアップ ~これだからPIOは~

この記事は慶應義塾大学ロボット技術研究会アドベントカレンダー2021の17日目です。

皆さんこんにちは。

思ったよりもみんな面白いことを投稿していて若干ビビっているOyakiです。

皆さん、Mbedは使っているでしょうか?そう、使いやすいようで使いにくいARMマイコン向けフレームワークのあいつです

今まで3年間関数ばっかのArduinoしか触れてこなかった人としては、あらゆるものがClassベースになっているあの環境は大変素晴らしいのですが、バージョン過渡期がF3RCの開発にぶち当たった結果初見殺しに見事に引っかかりまくりました

というわけで、そんなMbedの初見殺しの紹介と、その対処法を解説していこうと思います

CANは割り込み受信できなかった(過去形)

CAN通信、使っていますか?

MbedでCANを受信する殆どの人は標準ライブラリでcan.read()していることでしょう。ただ他の通信系ライブラリと同じように、CANにはcan.attach()という割り込み登録メソッドが生えています

当然「割り込みで受信する」という発想が生まれ、割り込み関数のなかでcan.readをするわけですが、これが面倒なことに実行時エラーを生みます

can.read()はMutexを使用するため、割り込み関数内で使用できないのです

Mutex: 0x20000152C. Not Allowed in ISR context. Error status: 0x80010133  Code 307 Module 1 - Bugs - Arm Mbed OS support forum
親の顔より見た実行時エラー (Mbedフォーラムより)

Mutex: マルチスレッド処理時に同時に同じ変数やペリフェラルにアクセスしないように制限を掛ける機能。マルチスレッドをしないF3RCでは全く恩恵はない

この仕様はSerialなど他の通信系にもあるのですが、SerialにはUnbuffered SerialというMutexを使わない別クラスが用意されています。しかしCANにはこのような機能はありませんでした

このようなときには割り込み関数内で受信指示フラグ的なものを立てて、別スレッドで受信すればいいのですが、ここでSTM32独自の仕様が関わります

STM32にはcan受信の割り込みの場合、CAN受信キューが空になるまで割り込みが入り続けるという謎仕様があるのです

参考: https://github.com/ARMmbed/mbed-os/issues/6714

割り込み内でcan.read()できないわけですから、CAN受信キューが空になることなどありえません

これにより、割り込み関数を登録し、1つでもCANメッセージが届いてしまえば最後、Nucleoは突然うんともすんとも言わなくなるという怪奇現象が起こります

Nucleoを使用しているロ技研では完全に詰みました。CANをなるべく早く受信するにはメインルーチンでポーリングするしかありません。というわけでF3RCではギブアップすることにしました…

RawCANとMbedOSのバージョン

F3RCのあとで調べると、7月ごろにMutexを使用しないCANライブラリの”RawCAN”が、MbedOS6.13に追加されたということがわかりました。

MbedOSのGitHub Releaseより

早速使ってみようとしたのですが、よく考えるとPlatformIOにはMbedのバージョンを指定する方法がありません

今のバージョンを知ることができるのはコンパイル開始時のメッセージぐらいです。そこを確認してみると…

MbedOSのGithub Releaseより

ふっっっっっっっっっっっっっっっっっる

3月から更新サボってるのはいくらOSSとはいえひどすぎるのでは…

手動でバージョンアップする方法

あまりにもやってられないのでフォーラムに手動アップデートの方法を投稿している人がいました。他の人が公式リファレンスにやり方を追加すると言っていたのですが、そのプルリクエストはまだマージされていません…

参考: https://community.platformio.org/t/support-for-mbed-os-6-stable-and-mature-apis-cloud-services-support-enhancements-to-the-bare-metal-profile/15079/9

というわけでここでまとめたいと思います

  • MbedOSをclone
    https://github.com/ARMmbed/mbed-os からリポジトリを適当な場所にcloneする
  • PlatformIO公式のMbedOSをPlatformIOに読み込ませるプラグインをZIPで落とす
    https://github.com/platformio/builder-framework-mbed からリポジトリをZIPで落として来る
  • cloneしてきたフォルダをコマンドプロンプトorターミナルで開き、gitでv6.15.1まで戻す
    リリース版じゃないと不安定かもしれないので戻す
git checkout -b v6.15.1 mbed-os-6.15.1
  • cloneしてきたMbedOSに“platformio” フォルダを作り、ZIPの中身を全部入れる
  • MbedOSのフォルダにpackage.jsonを作り、以下を書き込む
{
  "name": "framework-mbed",
  "version": "6.15900.210318",
  "description": "Arm Mbed OS is a platform operating system designed for the internet of things",
  "keywords": [
    "framework",
    "os",
    "arm",
    "hal"
  ],
  "homepage": "http://mbed.org",
  "repository": {
    "type": "git",
    "url": "https://github.com/ARMmbed/mbed-os"
  }
} 

  • 適当なPlatformIOプロジェクトのplatformio.iniに以下を書き込む
  • VSCode右下の”NewTerminal”をクリックし、“pio system info” を実行して”Python Executable”のパスをコピーする
  • “<Python Executableのパス> -m pip install jinja2 intelhex future prettytable six jsonschema” を実行する

  • PlatformIOプロジェクトをコンパイルする

これでエラーが出なければ問題ありません

エラーが出たとき

  • コンパイルを始めたら突然エラーが出たとき
    MbedOSのパス指定が間違えているか、package.jsonの場所や内容が間違っています
  • ちょっと進んでから “ModuleNotFoundError: No module named ~~”と怒られるとき
    ~~のPythonライブラリが足りていません。New Terminalを開き、
    “<Python Executableのパス> -m pip install ~~”
    を実行してみてください

まとめ

いや…面倒すぎるでしょ…

まあともかくこれでMbedOS 6.15.1は使うことができます。これより上のバージョンを使いたい場合はPythonライブラリが追加で必要になるかもしれないので、適宜追加してください。

こんなことしてまでPlatformIOで開発したくないのですが、VSCode自体が快適過ぎてMbedStudioに移れないんですよね…慣れって辛い。

これからもPlatformIO運営にアップデートをお願いしつつ、使わせていただこうと思います

それではよいMbedライフを!

コメントを残す