micropython -- MicroPython 内部のアクセスと制御
関数
- micropython.const(expr)
コンパイラが最適化できるように、式が定数であることを宣言するために使います。この関数の使い方は次のとおりです:
from micropython import const CONST_X = const(123) CONST_Y = const(2 * CONST_X + 1)
パーサが
NAME = const(expr)に出会うと、コンパイル時にその式を評価し、NAMEを使っているすべての箇所で結果の値を直接バイトコードに埋め込みます。これにより、毎回グローバル辞書を検索する必要がなくなります。constという名前はパーサが直接認識するので、MicroPython では実際には import は不要です。ただし、constが恒等関数として提供される CPython でもスクリプトが動くように、from micropython import constと書くことが推奨されます。パーサが認識するのは裸の名前constだけである点に注意してください。micropython.const()のようにモジュール名を前に付けたり、別名を使ったりすると、この最適化は働きません。この方法で宣言した定数も、モジュールの辞書にグローバル変数として格納されるので、他のモジュールからアクセスできます(例:
import mymodule; print(mymodule.X))。他のモジュールからこのグローバル変数に再代入しても、定義したモジュール内で埋め込まれた値には影響しません。このグローバルのエントリは、少なくとも2マシンワードの RAM を消費します。モジュール内に閉じた定数: この RAM の消費を避けるには、名前の先頭にアンダースコアを付けます(例:
_X = const(1))。こうすると変数はモジュールの辞書に追加されず、他のモジュールからは見えなくなります。const()に渡す式は、コンパイル時に評価できるものでなければなりません。サポートされる型は次のとおりです:int(算術演算子やビット演算子を使った式を含む)floatstrbytesbool(True、False)、None、...(Ellipsis)定数からなる
tuple
式では、それまでに定義した定数を参照できます。実行時の値や関数呼び出しを使うと
SyntaxError: not a constantが発生します。サンプルコード:
BUFFER_SIZE = const(1024) BUFFER_MASK = const(BUFFER_SIZE - 1) FLAGS = const(0x01 | 0x02) _SCALE = const(0.001) _PREFIX = const("data_") _HEADER = const(b"\x00\xff") _MODES = const(("read", "write"))
コンパイラは真偽値の定数をコンパイル時に評価するので、
const()は条件付きコンパイルに使えます。偽の定数で保護されたコードはバイトコードから完全に取り除かれ、mpy-crossで凍結した場合は到達不能なコードが出力から取り除かれます:FEATURE_X = const(True) if FEATURE_X: def feature_x_handler(): ...
CPython との互換性を保つための典型的な書き方は次のとおりです:
try: from micropython import const except ImportError: const = lambda x: x
メモリ使用量を減らし性能を高めるための定数の実践的な使い方については、 マイクロコントローラ上の MicroPython と MicroPython 性能の最大化 も参照してください。
- micropython.opt_level([level])
level を指定した場合、この関数はスクリプトの後続のコンパイルの最適化レベルを設定して、
Noneを返します。指定しない場合は、現在の最適化レベルを返します。最適化レベルは、次のコンパイル特性を制御します。
アサーション: レベル 0 では、アサーションステートメントが有効になり、バイトコードにコンパイルされます。レベル 1 以上ではアサーションがコンパイルされません。
ビルトイン
__debug__変数: レベル 0 でこの変数がTrueに展開されます。レベル 1 以上ではFalseで展開されます。ソースコード行番号: レベル 0, 1, 2 では、ソースコードの行番号がバイトコードとともに格納され、例外が発生した行番号を例外として報告することができます。レベル 3 以上では行番号が格納されません。
デフォルトの最適化レベルは通常レベル 0 です。
- micropython.alloc_emergency_exception_buf(size)
緊急例外バッファ用に size バイトの RAM を割り当てます(適当なサイズは約 100 バイトです)。このバッファは(たとえば、割り込みハンドラ内などで)通常の RAM の割り当てが失敗した場合に例外を作成するために使用されます。したがって、そのような状況でも有用なトレースバック情報を提供します。
この関数を使う良い方法は、メインスクリプト(たとえば
boot.pyやmain.py)の先頭に置くことです。そのようにしておけば、それに続くすべてのコードに対して緊急例外バッファが有効になります。
- micropython.mem_info([verbose])
現在使っているメモリに関する情報を表示します。 verbose を指定すると冗長モードとなり、詳しい情報を表示します。
表示する情報は実装に依存しますが、現在使っているスタックとヒープのサイズは含みます。冗長モードではヒープ全体の概要を出力し、どのブロックが使用中でどのブロックが空いているかを示します。
冗長モードの正確な出力はポートによって異なりますが、一般的に各文字は16バイトのメモリブロックを表します。出力の各行は 0x400 バイト、つまり 1KiB の RAM を表します。
各文字の意味は次のとおりです:
シンボル
意味
.
空きブロック
h
ヘッドブロック
=
テールブロック
m
マークされたヘッドブロック
T
tuple
L
list
D
dict
F
float
B
バイトコード
M
モジュール
S
文字列またはバイト列
A
bytearray
- micropython.qstr_info([verbose])
現在のところのインターンド文字列(内部に蓄えられている文字列)に関する情報を表示します。 verbose を指定すると冗長モードとなり、詳しい情報を表示します。
表示する情報は実装に依存しますが、現在のインターンド文字列の数とそれが使っている RAM のサイズは含みます。冗長モードでは RAM 上のインターンド文字列すべての名前を表示します。
- micropython.stack_use()
現在使われているスタックのサイズを表す整数を返します。この値そのものは特に有用ではなく、異なる時点でのスタック使用量の違いを計算するために使用されるべきです。
- micropython.heap_lock()
- micropython.heap_unlock()
- micropython.heap_locked()
ヒープをロックまたはロック解除します。ロックされているとメモリ割り当ては発生せず、ヒープを割り当てようとした場合は
MemoryErrorが発生します。heap_locked()は、ヒープが現在ロックされていれば真値を返します。これらの関数はネストすることができます。つまり
heap_lock()は連続して複数回呼び出すことができ、ロックの深さが増します。その後、ヒープを再度使用可能にするためにはheap_unlock()を同じ回数呼び出す必要があります。heap_unlock()とheap_locked()のどちらも現在のロックの深さを返します(heap_unlock() ではロック解除後の値)。返される値は 0 以上の整数値です。0 はヒープがロックされていないことを意味します。ヒープがロックされた状態で REPL が有効になると、強制的にロックが解除されます。
注記:
heap_locked()はほとんどのポートで有効になっていません。有効にするにはビルド時にMICROPY_PY_MICROPYTHON_HEAP_LOCKEDの設定が必要となります。
- micropython.kbd_intr(chr)
KeyboardInterrupt例外を発生させる文字を設定します。デフォルトで、スクリプト実行中は 3 に設定されていて、これは Ctrl-C に該当します。この関数に -1 を渡すとCtrl-C のキャプチャが無効になり、3 を渡すと元に戻ります。この関数は、通常は REPL で使っている文字の入力ストリームを他の目的で使う場合、そのストリームで Ctrl-C がキャプチャーされるのを防ぐために使えます。
- micropython.schedule(func, arg)
関数 func が「早急に」実行されるようにスケジュールします。この関数には、単一の引数として値 arg が渡されます。「早急に」とは、MicroPython ランタイムができるだけ早くに関数を実行すること、効率的にもしようとしていること、および次の条件が満たされるよう最善を尽くすことを意味します。
スケジュールされた関数が他のスケジュールされた機能を横取りすることはありません。
スケジュールされた関数は常に「オペコード間」で実行されます。つまり、すべての基本的な Python 操作(リストへの追加など)はアトミックであることが保証されています。
使用するポートは、その中でスケジュールされた関数が決して実行されないであろう「クリティカル範囲」を定義するかもしれません。関数はクリティカル範囲内でスケジュールされますが、その範囲が終了するまで実行されません。クリティカル範囲の例としては、割り込み割り込みハンドラ(IRQ)があります。
ネイティブコード関数内では、スケジュールされた関数は、ネイティブコードが明示的に呼び出すようにしない限り呼び出されません。
poll.poll,poll.ipoll,time.sleep,time.sleep_msなどの(期間ゼロのスリープを含む)特定の関数は、スケジュールされた関数を呼び出します。
この関数の用途は、プリエントしている IRQ からのコールバックをスケジュールすることです。そのような IRQ は IRQ で実行されるコードに制限を課し(たとえばヒープはロックされるかもしれません)、後で呼び出すために関数をスケジュールすることはそれらの制限を取り除きます。
マルチスレッド対応のポートでは、スケジュールされた関数の動作は、そのポートでのグローバルインタプリタロック(GIL)が有効か無効かによって異なります。
GIL が有効な場合、関数は任意のスレッドをプリエンプトして、そのスレッドのコンテキストで実行できます。
GIL が無効な場合、関数はメインスレッドのみをプリエンプトし、そのコンテキストで実行されます。
注記:
schedule()がプリエントしている IRQ から呼び出された場合、メモリ割り当てが許可されておらず、schedule()に渡されるコールバックがバウンドメソッドであるときに、これを直接渡すことは失敗します。これは、バウンドメソッドへの参照を作成するとメモリが割り当てられるためです。解決策は、クラスコンストラクターでメソッドへの参照を作成し、その参照をschedule()に渡すことです。これについては 「Pythonオブジェクトの作成」の 参考資料 を参照してください 。スケジュールされた関数を保持するための有限のキューがあり、キューがいっぱいになると
schedule()はRuntimeErrorを起こします。特殊なケースとして、この関数に最初の引数として
micropython.kbd_intrを渡すと(2番目の引数はNone)、メインスレッドで「まもなく」KeyboardInterruptが発生するようにスケジュールされます。
クラス
- class micropython.RingIO(size)
- class micropython.RingIO(buffer)
ストリームインターフェースを備えた、バイトの固定サイズリングバッファを提供します。これは
io.BytesIOの FIFO キューのバリアントと考えることができます。整数サイズを指定して作成すると、適切なバッファが割り当てられます。
bytearrayや類似のバッファプロトコルオブジェクトをコンストラクタに渡して、その場で利用することもできます。クラシックなリングバッファのアルゴリズムが使用されており、任意のサイズのバッファを使用できますが、1バイトは追跡のために消費されます。整数サイズで初期化された場合、このことは考慮されます。たとえば、RingIO(16) は内部で17バイトのバッファを割り当て、16バイトのデータを保持できるようにします。ただし、事前に割り当てられたバッファを渡した場合、元の長さより1バイト少なくなり、
RingIO(bytearray(16))では15バイトのデータしか保持できません。RingIO インスタンスは、データを単方向に渡す場合、IRQ/スレッドセーフとして使えます。たとえば、IRQ 中で書き出し、非IRQ関数で読み込めます(その逆も可能です)。しかし、IRQと非IRQの両方から同じインスタンスに書き出そうとすると、データの破損が発生することがよくあります。
- any()
読み込める文字数を整数で返します。
- read([nbytes])
利用可能な文字を読み込みます。これはブロッキングしない関数です。
nbytesが指定されている場合は、最大でそのバイト数までを読み込み、指定されていない場合は可能な限り多くのデータを読み込みます。戻り値: 読み込んだバイトを含むバイト列オブジェクト。データが利用できない場合は、長さがゼロのバイト列オブジェクトが返されます。
- readline([nbytes])
改行文字で終わる行を読み込みます。改行がバッファ内に存在する場合は、そこまでの行を返し、それ以外の場合はバッファ内の利用可能なバイトを返します。
nbytesが指定されている場合は、最大でそのバイト数までを読み込みます。戻り値: 読み込んだ行を含む bytes オブジェクト。
- readinto(buf[, nbytes])
指定された
bufに利用可能なバイトを読み込みます。nbytesが指定されている場合は、最大でそのバイト数までを読み込み、それ以外の場合はlen(buf)バイトまでを読み込みます。戻り値:
bufに読み込んだバイト数を表す整数。
- write(buf)
bufからリングバッファにバイト列を書き出し(非ブロッキング)。リングバッファの空き容量に制限されます。戻り値: 書き出したバイト数を示す整数。