0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RaspberryPi PicoのためのMicroPython自作モジュールの作り方

0
Last updated at Posted at 2026-05-04

はじめに

MicroPython 用の自作 C モジュールを作成するため、公式ドキュメントの手順に従ってビルドを試してみた。

目次

MicroPythonのBuild手順

WindowsのUbunt(WSL)上でBuildする手順をまとめる。詳細は下記参照。

1.MicroPythonのコードを取得する

# 任意のフォルダ内にClone
$ git clone --recursive https://github.com/micropython/micropython.git
# 必要な依存パッケージ取得
$ sudo apt update
$ sudo apt install build-essential git python3 pkg-config libffi-dev

2.MicroPythonのクロスコンパイラmpy-crossのビルド

$ cd mpy-cross
$ make

3.Linux用のMicroPythonビルド

Linux上で動作するMicroPythonビルド。

$ cd ports/unix
$ make submodules
$ make

結果を動作確認する。replできればOK。「Ctrl+D」で抜ける。

$ cd build-standard 
$ ./micropython
$ MicroPython v1.29.0-preview.115.g9f396bba8d on 2026-05-04; linux [GCC 13.3.0] version
$ Type "help()" for more information.
>>> print("hello")
hello
>>>

4.Pico用のMicroPythonビルド

Pico用のビルドをしてuF2ファイルを生成する。

# 必要な依存パッケージ取得
$ sudo apt install cmake
$ sudo apt install gcc-arm-none-eabi build-essential
# Buildする
$ cd ports/rp2
$ make
# uf2ファイル置き場
$ cd build-RPI_PICO 
$ ls
$ CMakeCache.txt  cmake_install.cmake  firmware.elf.map  frozen_mpy  pico_flash_region.ld  pioasm-install
$ CMakeFiles      firmware.bin         firmware.hex      generated   picotool
$ Makefile        firmware.dis         firmware.uf2      genhdr      pins_RPI_PICO.c
$ _deps           firmware.elf         frozen_content.c  pico-sdk    pioasm
# firmware.uf2 が生成結果

Picoの種類によってmakeのコマンドが異なる。

種類 make
pico make BOARD=PICO
pico w make BOARD=PICO_W
pico2 make BOARD=PICO2
pico2 w make BOARD=PICO2_W

戻る

自作のCモジュールを追加してBuildする

/examples/usercmodule/cexampleのサンプルコードを一部変更して試してみる。user_sample(a,b)という関数名で引数a,bの掛け算をreturnする。

examplemodule.c
// sample add
static mp_obj_t user_sample(mp_obj_t a_obj, mp_obj_t b_obj) {
    // Extract the ints from the micropython input objects.
    int a = mp_obj_get_int(a_obj);
    int b = mp_obj_get_int(b_obj);

    return mp_obj_new_int(a * b);
}
static MP_DEFINE_CONST_FUN_OBJ_2(user_sample_obj, user_sample);
// sample add
//・・・

static const mp_rom_map_elem_t example_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
    { MP_ROM_QSTR(MP_QSTR_user_sample), MP_ROM_PTR(&user_sample_obj) }, // sample add
    { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
    { MP_ROM_QSTR(MP_QSTR_Timer),    MP_ROM_PTR(&example_type_Timer) },
    { MP_ROM_QSTR(MP_QSTR_AdvancedTimer),    MP_ROM_PTR(&example_type_AdvancedTimer) },
};

makeする

$ cd ports/rp2/
# 追加モジュールをオプションにつける
$ make USER_C_MODULES=../../examples/usercmodule/micropython.cmake
# uf2ファイル置き場
$ cd build-RPI_PICO 
$ ls
$ CMakeCache.txt  cmake_install.cmake  firmware.elf.map  frozen_mpy  pico_flash_region.ld  pioasm-install
$ CMakeFiles      firmware.bin         firmware.hex      generated   picotool
$ Makefile        firmware.dis         firmware.uf2      genhdr      pins_RPI_PICO.c
$ _deps           firmware.elf         frozen_content.c  pico-sdk    pioasm
# firmware.uf2 が生成結果

Pico の BOOTSEL ボタンを押しながら PC と USB 接続して、UF2ファイルをドラックアンドドロップしてreplを起動。自作モジュール をコールするとuser_sample(5*10)=50で返答される。成功!!

MicroPython v1.29.0-preview.115.g9f396bba8d.dirty on 2026-05-04; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> import cexample
>>> print(cexample.user_sample(5,10))
50
>>>

戻る

自作のCモジュールを.mpy化

自作のCモジュールを追加してBuildするでは、自作の C モジュールを MicroPythonのファームウェアごとビルドする必要がある。しかし、自作 C モジュールだけを個別にビルドし、独立した .mpy ファイル としてライブラリ化する方法もある。公式サイトに記載されている例を試してみる。

factorial.cに自作のコードを書く場合は、ファイル配置を下記のようなフォルダ構成にする。

├── /micropython
│    ├── ports/
│    ├── py/
│    │     └── dynruntime.mk   ← ビルドに必須
│    ├── mpy-cross/
│    ├── tools/
│    └── ...(その他 MicroPython のソース)
└── /factorial
     ├── Makefile
     └── factorial.c

Cとmakefileは下記の通り。階乗を計算する例。

factorial.c
// MicroPython API にアクセスするためのヘッダファイルをインクルード
#include "py/dynruntime.h"

// 階乗を計算するヘルパー関数
static mp_int_t factorial_helper(mp_int_t x) {
    if (x == 0) {
        return 1;
    }
    return x * factorial_helper(x - 1);
}

// Python から factorial(x) として呼び出される関数
static mp_obj_t factorial(mp_obj_t x_obj) {
    // MicroPython 入力オブジェクトから整数を抽出
    mp_int_t x = mp_obj_get_int(x_obj);
    // 階乗を計算
    mp_int_t result = factorial_helper(x);
    // 計算結果を MicroPython 整数オブジェクトに変換して戻す
    return mp_obj_new_int(result);
}
// 上の関数の Python 参照を定義
static MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

// これはエントリポイントであり、モジュールをインポートしたときに呼び出される
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_DYNRUNTIME_INIT_EXIT
}

Makefile
# 最上位の MicroPython ディレクトリの場所
MPY_DIR = ../micropython

# モジュールの名前
MOD = factorial

# ソースファイル(.c や .py)
SRC = factorial.c

# ビルド対象のアーキテクチャ(x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH = armv6m

# このインクルードにより、モジュールをコンパイル・リンクするルールを取得
include $(MPY_DIR)/py/dynruntime.mk

make時は対象のARCHを指定必要。Picoの場合は、armv6mを指定。

$  make ARCH=armv6m
# 結果
$ GEN build/factorial.config.h
$ CC factorial.c
$ LINK build/factorial.o
$ arch:         EM_ARM
$ text size:    128
$ bss size:     0
$ GOT entries:  2
$ GEN factorial.mpy

生成される facorial.mpyをThonny等でPicoに書き込む。replを起動。自作モジュール をコールするとfactorial.factorial(10)=3628800で返答される。成功!!
10!=1×2×3×4x5x6x7x8x9x10 = 3628800

MicroPython v1.29.0-preview.115.g9f396bba8d.dirty on 2026-05-04; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> import factorial
>>> print(factorial.factorial(10))
3628800
>>> 

戻る

LEDをOnOffする自作のCモジュールを.mpy化

Picoのレジスタを直接触って動作する例としてLEDをOnOffするモジュールを作成する。フォルダ構成は下記の通り。

├── /micropython
│    ├── ports/
│    ├── py/
│    │     └── dynruntime.mk   ← ビルドに必須
│    ├── mpy-cross/
│    ├── tools/
│    └── ...(その他 MicroPython のソース)
└── /myled
     ├── Makefile
     └── myled.c

Cとmakefileは下記の通り。

myled.c
#include "py/dynruntime.h"

// RP2040 レジスタベース
#define SIO_BASE        0xD0000000
#define IO_BANK0_BASE   0x40014000
#define PADS_BANK0_BASE 0x4001C000

// SIO レジスタ
#define GPIO_OUT_SET    (SIO_BASE + 0x14)
#define GPIO_OUT_CLR    (SIO_BASE + 0x18)
#define GPIO_OE_SET     (SIO_BASE + 0x24)

// IO_BANK0 / PADS_BANK0
#define IO_BANK0_GPIO_CTRL(n) (IO_BANK0_BASE + 0x04 + (n) * 8)
#define PADS_BANK0_GPIO(n)    (PADS_BANK0_BASE + 0x04 + (n) * 4)

// FUNCSEL GPIOは5
#define FUNCSEL_GPIO 5

// -------------------------
// LED(GPIO25) 初期化
// -------------------------
static void init_led_gpio(void) {
    uint32_t pin = 25;

    // IO_BANK0: GPIO 機能に設定
    *(volatile uint32_t *)IO_BANK0_GPIO_CTRL(pin) = FUNCSEL_GPIO;

    // PADS_BANK0: IE=1, OD=0, PU=0, PD=0
    *(volatile uint32_t *)PADS_BANK0_GPIO(pin) = (1 << 6);

    // SIO: 出力許可
    *(volatile uint32_t *)GPIO_OE_SET = (1u << pin);
}

// -------------------------
// led(val) : 1=ON, 0=OFF
// -------------------------
static mp_obj_t led(mp_obj_t val_obj) {
    uint32_t val = mp_obj_get_int(val_obj);
    uint32_t mask = 1u << 25;

    init_led_gpio();

    if (val) {
        *(volatile uint32_t *)GPIO_OUT_SET = mask;
    } else {
        *(volatile uint32_t *)GPIO_OUT_CLR = mask;
    }

    return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(led_obj, led);

// -------------------------
// dynruntime 初期化
// -------------------------
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_led, MP_OBJ_FROM_PTR(&led_obj));

    MP_DYNRUNTIME_INIT_EXIT
}

Makefile
# 最上位の MicroPython ディレクトリの場所
MPY_DIR = ../micropython

# モジュールの名前
MOD = myled

# ソースファイル(.c や .py)
SRC = myled.c

# ビルド対象のアーキテクチャ(x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH = armv6m

# このインクルードにより、モジュールをコンパイル・リンクするルールを取得
include $(MPY_DIR)/py/dynruntime.mk

makeをするとmyled.mpyが生成されるので、Picoに書き込む。replを起動。自作モジュール をコールするとPicoのledがON/OFFする成功!!

MicroPython v1.29.0-preview.115.g9f396bba8d.dirty on 2026-05-04; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> import myled
>>> myled.led(1)
>>> myled.led(0)
>>>

戻る

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?