Raspberry Pi PicoでのMicroPythonのC拡張機能

これは、Raspberry Pi Pico上でMicroPythonの基本的なC拡張を書いて実行する方法についてのガイドです。MicroPythonを拡張する理由、拡張モジュールの書き方、コンパイルの仕方、Picoへのインストールの仕方を説明します。このトピックについてもっと読みたい方は、以下を参照してください。 https://docs.micropython.org/en/latest/develop/extendingmicropython.html

はじめに

なぜMicroPythonを拡張するのか?

MicroPythonを拡張したいと思う理由はいくつかあります。MicroPythonはPythonの縮小版なので、(Pythonのような)計算量の多いタスクにはあまり適していません。一方で、C言語はそのようなタスクにとても適しています。Micropython用のC言語拡張は、C言語を使って計算を行い、その結果をMicroPythonで利用することができます。これにより、いくつかの処理は桁違いに速くなります。

もう一つの理由は、C言語のAPIを使っているハードウェアをMicroPythonでインターフェースしたいということです。 

MicroPython C拡張の種類

MicroPythonを拡張するにはいくつかの方法があります。外部Cモジュールと.mpyファイルのネイティブマシンコードです。

外部のCモジュールを実行するには、それをMicroPythonファームウェアに再コンパイルする必要があります。これはかなり複雑な作業なので、このガイドでは2つ目の方法を紹介します。この方法に興味がある方は、以下のページで詳細をご覧ください。                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

.mpyはコンパイル済みのネイティブマシンコードを格納したファイルで、動的にリンクすることができます。これにより、MicroPythonのファームウェア全体を再コンパイルする必要がないため、柔軟性が高くなります。

拡張モジュールの書き込み

拡張モジュールを書くことは、MicroPythonを拡張する上で最も簡単なことです。簡単な例を見ながら、その方法を紹介します。まず始めに、新しいディレクトリを作成します。 ファクトフィブ.新しいターミナル・ウィンドウを開き、新しいディレクトリにcdし、次のような新しいファイルを作成する。 FACTFIB.C.Dekstop配下のRaspberry Piでディレクトリを作成した場合、コマンドは以下のようになります。

cd ~/Desktop/factfib

touch factfib.c

オープン FACTFIB.C をテキストエディタで開き、以下のコードを入力する:

#include "py/dynruntime.h

STATIC mp_int_t factorial_helper(mp_int_t x) {
   if (x < 1) {
      return 1;
   }
   return x*factorial_helper(x-1);
}

STATIC mp_obj_t factorial(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = factorial_helper(x);
   return rslt;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

STATIC mp_int_t fibonacci_helper(mp_int_t x) {
   if (x <= 0) {
      return 0;
   }
   else if (x == 1) {
      return 1;
   }
   else {
      return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
   }
}

STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = fibonacci_helper(x);
   return mp_obj_new_int(rslt);
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
   MP_DYNRUNTIME_INIT_ENTRY

   mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
   mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));

   MP_DYNRUNTIME_INIT_EXIT
}

上のコードを説明しましょう。MicroPythonやPythonでは、すべての変数はオブジェクトです。そのため、C言語では以下のように表現します。 mp_obj_t.しかし、CプログラムはC型の変数でしか動作しないので、オブジェクトをC型に変換する必要があります。これはマーシャルと呼ばれ、MicroPythonにはオブジェクトから任意のC型を抽出する関数が用意されています。

オリバー・ロブソンのこのウェブページは、マーシャルにとても役立ちます。 https://mpy-c-gen.oliverrobson.tech/.さらに、MicroPythonのドキュメントにマーシャルの例があります。 https://docs.micropython.org/en/latest/develop/natmod.html.さらに詳しい説明が必要な場合は、この記事を読むことをお勧めします。

エクステンションの構築

Makefileを使って、拡張機能を.mpyファイルにビルドします。しかし、その前にいくつかのことを設定する必要があります。ターミナルが ファクトフィブ ディレクトリを作成します。そして、MicroPythonのGitHubリポジトリをクローンします。

sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi

git clone --recurse-submodules https://github.com/micropython/micropython.git

pip3 install 'pyelftools>=0.25'

これらのインストールには時間がかかりますが、時間を節約したい場合や自分のやっていることがわかっている場合には、micropythonのリポジトリから/pyと/toolsディレクトリをクローンして、それらを マイクロパイソン の中のフォルダです。 ファクトフィブ フォルダを作成します(2つ目のコマンドは省略)。

インストールを実行している間に、Makefileを書くことができます。単に

touch Makefile

をクリックし、新しく作成したファイルをテキストエディターで開きます。

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

を設定していることに気付いたかもしれません。 アーチ への変数です。 armv7m とはいえ、ピコは armv6m.これをしなければならないのは armv6m のアーキテクチャは、(この記事を書いている時点では)サポートされていません。 dynruntime.mk ツールを使用しています。

しかし、幸いなことに、Pico 用の拡張機能をコンパイルすることができます。そのためには dynruntime.mk の下にあるはずのファイルです。 micropython/py/dynruntime.mk。 それを開き、armv7mのArchitecture configurationの下にあるCFLAGS変数を見つけます(64行目のはず)。変更 -mcpu=cortex-m3 にしています。 -mcpu=cortex-m0 をクリックして保存します。

chnge -mcpu=cortex-m3 to -mcpu=cortex-m0

そして、すべてがインストールされた後に

make

とのことです。 ファクトフィブ.mpy ファイルが作成されます。

エクステンションのインストールとテスト

最後のステップはインストールとテストだ。このために、MicropythonがRaspberry Pi Pico上に作成するファイルシステムを利用します。これを行う最も簡単な方法は、Thonny IDE(Raspbian/Raspberry Pi OSにプリインストールされている)を使うことです。

Raspberry Piを使ってPicoをプログラミングしていない場合や、PicoでMicroPythonを使ったことがない場合は、Raspberry PiによるMicroPythonの入門ガイドを参照してください。 https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Windowsをお使いの方は、Raspberry Pi PicoとMicroPython on Windowsについてのブログ記事をご覧ください。 https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Pico に MicroPython ファームウェアをフラッシュした後に Thonny を終了し、rshell をインストールします。rshellはコマンドラインからファイルシステムにアクセスするために使います。

sudo pip3 install rshell
rshell --version

これにより、すべてが正しく設定されていれば、rhsellバージョンが表示されます。次に、picoのプラグを抜いて、(BOOTSELボタンを押さずに)再度プラグインして、何もファイルシステムにアクセスしようとしていないことを確認します。ここで、次のことを実行する必要があります。

rshell -p /dev/ttyACM0 --buffer-size 512

cp factfib.mpy /pyboard/factfib.mpy

インストールをテストするには、rshellまたはThonny IDEを使って .py ファイルを使っていますが、今回はminicom上でMicroPythonインタープリタを使う方法を紹介します。

そこで、まず最初に Ctrl+c をクリックして、rshellを終了し、minicomをインストールしてください。

sudo apt install minicom

これで、Picos REPL(Read-eval-print loop)にアクセスできるようになりました。

minicom -o -D /dev/ttyACM0

3つの閉じ角括弧 >> は、MicroPython インタプリタが実行されていることを示します。これで、拡張機能をインポートして、いつものように作業できるようになりました。

>>> import factfib as ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

おめでとうございます!あなたは Pico 用の最初の MicroPython C 拡張モジュールを作成しました!次のステップは、より複雑なモジュールを書いてコンパイルする方法を学ぶことです。リストとディクスのマーシャリングがどのように機能するかをテストすることから始めるのがよい方法です(上記のマーシャリングのウェブページを参照してください)。

この記事について質問があれば、遠慮なくコメントを書いてほしい。

8コメント

  1. PeterB on 11月 26, 2021 at 8:29 am となります。

    Cプログラムのエラーを除けば、問題なく動作しました。ありがとうございました。

    STATIC mp_obj_t factorial(mp_obj_t x_obj) {.
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_int_t rslt = factorial_helper(x);
    mp_obj_new_int(rslt) を返します。
    }

    • raspi berry on 11月 27, 2021 at 5:56 pm となります。

      フィードバックをありがとうございました。

  2. XMC.pl on 6月 1, 2022 at 3:31 am となります。

    どのようにmysqlからデータを取得することができますjoomlaを設定するには?

  3. Lynggaard on 1月 8, 2023 at 8:09 pm となります。

    上記のようにやってみたのですが、いろいろと説明通りにいかないのです。

    - 上記の手順に従い、micropythonを入手し、makefileを記述通りに修正しました。
    - makeはしています(ただし、factfib.mpyではなく、factfib.native.mpyのファイルを取得します)
    - factfib.native.mpyをpicoにコピーしてfactfib.mpyとしています。
    (rshellを試しましたが、「timed out or error in transfer to remote: b"」と出てしまいましたが、Thonnyを使ってコピーすることが出来ました)
    - 私はエラーなしで(thonnyまたはrshell - 同じ)モジュールをインポートすることができます。
    - 試しに「ff.fibonacci(5)」を実行してみましたが、その後、「?

    "トレースバック(最も最近のコールラスト)。
    ファイル "", 行 1, in
    AttributeError: 'module' オブジェクトには 'fibonacci' という属性がありません。"

    どこが悪いんだろう?

    • paopao69 on 3月 22, 2023 at 5:59 pm となります。

      最終的にはうまくいったのでしょうか?

  4. Paulo on 2月 9, 2024 at 1:44 am となります。

    これでarmv6にコンパイルできるようになったので、Makefileの以下の行を変更するだけで、micropythonのコードを変更する必要はない。
    ARCH = armv6m

    factfib.cのコンパイルでいくつかエラーがありました:

    // 最後に "がない。
    #include "py/dynruntime.h"

    // 返り値を mp_obj_t に変換する。
    STATIC mp_obj_t factorial(mp_obj_t x_obj) {.
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_int_t rslt = factorial_helper(x);
    mp_obj_new_int(rslt) を返します。
    }

    • Adam on 2月 9, 2024 at 9:22 am となります。

      パウロ、情報をありがとう!

  5. Dr_Phil on 5月 24, 2024 at 7:36 am となります。

    すべての指示に従い、facfib.mpyファイルをビルドしました。使用したのは
    ARCH = armv6m
    Picoにロードすると、こんなエラーが出る:

    ValueError: 互換性のない .mpy ファイル

    私のピコは以下のmpy値を要求する:
    mpy バージョン: 6
    mpy サブバージョン: 2
    mpy のフラグ:-march=armv6m

    ファイルの最初の2バイトをチェックすると、バージョン6とサブバージョン6がわかる。
    これを修正する方法はありますか?

コメントを残す