2018年01月07日

Raspberry Pi版MicroPythonのベンチマークテスト

昨日行った、Raspberry Piベアメタル版MicroPythonでのLチカですが、手動でオン・オフができるだけで、「点滅」はできていませんでした。
点滅を行うには、一定時間停止するdelay機能が必要ですが、MicroPythonではutimeモジュールにdelay_ms()があります。
ESP32やSTM32用の実装を参考に、このモジュールをRaspberry Pi用に移植しました

ESP32やSTM32用のモジュールとの差分は、ほぼ現在時刻を取得する部分のみですが、これは以前のC言語版ベアメタルLチカで使ったシステムタイマの機能をそのまま使います。
ただ、Raspberry Piにはバッテリバックアップ付きの時計機能が無いので、電源ONのたびに2000年1月1日0時0分0秒になってしまいます。

とはいえ、delayは実現できましたので、以下のコードでいわゆる「Lチカ」が行えました。



これで経過時間を計測できるようなりましたので、次に以下で紹介されているベンチマークテストを動かしてみました。

Benchmark comparison of MicroPython boards - MicroPython Forum

モジュール名がtimeになっているところはutimeに適宜変更します。
ベンチマークの内容は、
(1)文字列や配列の演算:値が大きいほど高速
(2)一定時間に「1増やす」を行った回数:値が大きいほど高速
(3)内容はよく分かりませんが、ある浮動小数点演算の所要時間:値が小さいほど高速
となっています。

結果ですが、以下のようになりました。
(1)Pystone
Pystone(1.2) time for 500 passes = 818 ms
This machine benchmarks at 611 pystones/second

(2)performanceTest
>>> performanceTest()
Count: 612921

(3)hsquare.py
Doing 50000 calculations...
calculations done after 11717 ms.
Mean time for each inverse h square calculation = 234.3400001525878 us
Sum of inverse h square = 38023.2257843017578
Mean of inverse h square = 0.7604645729065


上記のスレッドにある他のMCUと比較してみましょう。
PyBoard1.1は168MHzのCortex-M4F、Teensy3.6は180MHzのCortex-M4です。

(1)Pystone
* Pyboard v1.1 with MicroPython v1.8.6 : 1,754;
* ESP8266 with MicroPython v1.8.6-7 : 223 (80 MHz) / 415 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 2212;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 611.

(2)performanceTest
* Pyboard v1.1 with MicroPython v1.8.6 : 2,783,122;
* ESP8266 with MicroPython v1.8.6-7 : 171,145 (80 MHz) / 341,224 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 3,451,931;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 612,921.

(3)hsquare.py
* Pyboard v1.1 with MicroPython v1.8.6 : 83;
* ESP8266 with MicroPython v1.8.6-7 : 460 (80 MHz) / 239 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 73;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 234.34.

Raspberry Pi Zero Wのクロックは1GHzのはずなのですが、全然速くないですね。
どこかにボトルネックがあるのかもしれません。
ラベル:MicroPython
posted by boochow at 18:38| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月06日

Raspberry Pi Zero + ベアメタルMicroPythonでのLチカ

REPLが何とか動作するようになった、Raspberry Pi用のベアメタル版MicroPythonですが、次は「Lチカ」をやってみました。

C言語でのLチカは以前行いましたが、これをREPLからできるようにします。
理想的には、machineモジュールを実装してPinオブジェクトを実装して、PinオブジェクトでGPIOを制御する…となりますが、最初から全部作るのはなかなか荷が重いので、いろいろ調べた結果、STM32の「stm」モジュール相当を実装してみることにしました。

stmモジュールはSTM32用のMicroPythonでメモリへの直接アクセスの手段を提供します。
以下に解説がありますが、要するに
stm.mem32[address]
という形式でaddressへのアクセスができます。
mem32でなくmem16やmem8を使うと、16ビットや8ビット単位でのアクセスが可能です。
値を代入すれば、addressへ書き込むこともできます。

Module: stm

これを使えば、GPIOレジスタへの読み書きができるので、GPIOへの入出力ができます。

というわけで、stm32用のmodstm.cをほぼそのまま使用してrpi mcuというモジュールを追加してみました。(追記:rpiはボードの名称を表していますが、今回のモジュールはボードではなくCPUに依存するので名称を変更しました)
モジュールのコードはこちらです。

MicroPythonにモジュールを追加するお作法については、以下のページが詳しいです。

Adding a Module − MicroPython Development Documentation 1.0 documentation

Book/text.md at master ・ PyConPL/Book

概ね、
・新しいモジュールのためのCソースファイルを作り、Makefileに追加する
・Cソースの中で、mp_obj_module_t型の定数を宣言する
・その定数をmpconfigport.hの中でextern宣言して参照できるようにする
・mpconfigport.hの中でMICROPY_PORT_BUILTIN_MODULESへ、
{ MP_ROM_QSTR(MP_QSTR_モジュール名), MP_ROM_PTR(&上記の定数) }
を追加する
という感じです。

mp_obj_module_t型は、モジュールで使用する関数や定数の名称を保持するmp_obj_dict_t型のメンバ変数を持っており、関数等はこれを介して呼び出されます。

このモジュールを使って、Raspberry Pi Zero Wのボード上のLEDをオン・オフしてみます。
以前の記事に書いたとおり、オンボードのLEDはGPIO47に接続されています。

GPIO47を出力モードにするには

・GPFSEL4のbit 21を1に

これを点灯させるには、GPIO47にLを出力するので

・GPCLR1のbit15を1に

消灯するにはGPIO47にHを出力するので

・GPSET1のbit15を1に

設定します。
MicroPythonのコードで書くと、それぞれ以下のようになります。



レジスタの名前は定義していませんので、アドレスをベタ書きしています。

以下の記事によると、Raspberry Pi 1/Zero/Zero Wでは0x20200000から始まっていたレジスタが、Raspberry Pi 2では0x3F200000からに変わっているそうなので、やはりアドレスではなくレジスタの名前が使えるようにするのが良さそうです。

Step01 – Bare Metal Programming in C Pt1 – Valvers

モジュールでの定数値の定義の仕方がまだよく分かっていないので、次回に持ち越しにしておきます。
(1/6追記)
GPIO関係のレジスタのアドレスを定数として追加しました。
mcu.mem32[mcu.レジスタ名]でレジスタへアクセスできます。
rpi-mp-gpio.png
ラベル:MicroPython
posted by boochow at 02:16| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月05日

Raspberry PiベアメタルをQEMUでデバッグするメモ

Raspberry Piベアメタルプログラミングは、microSDをいちいち抜き差ししないといけないのが面倒です。
SDカードを使わない方法としては、ネットワークブートやUSB接続でホストをマスストレージに見せかけるなどの方法もあるようですが、GPIOなどを操作しない場合にはエミュレータが有効です。

今回Raspberry PiのベアメタルにMicroPythonのREPLを追加するにあたって、Linux上でQEMUを使ってみました。

ARMのバイナリを動作させられるQEMUは、Ubuntuのパッケージで用意されていますのでインストールは簡単です。
Raspberry Piのバイナリを動かす場合は、
qemu-system-arm \
-kernel firmware.elf \
-cpu arm1176 \
-M versatilepb \
-m 256 \
-no-reboot \
-nographic \
-monitor null \
-serial stdio \
-redir tcp:10022::22

というようにすれば動作します。これはMakefileの中にもrunというターゲットで入れてあります。

ただ、QEMUを使う場合にはMini-UARTはうまく動作させるのは難しいようです。
ですので、QEMUの場合はMiniでないほうのUARTを使う必要があります。
今のところ、uart-qemu.cに通常のUARTとMini-UARTの両方を入れて、
#if 1 // 0ならMini-UART
通常のUARTのコード
#else
Mini-UARTのコード
#endif
というやり方で選択できるようにしてあります。

QEMU上で動作しているARM用バイナリは、クロス開発環境用のGDBでデバッグすることができます。

まず、QEMU上でのバイナリは"-s -S"オプションをつけて起動します。
$ qemu-system-arm -kernel build/firmware.elf -cpu arm1176 -M versatilepb -m 256 -no-reboot -nographic -monitor null -serial stdio -s -S


次に、同じマシンの別のターミナルからGDBを起動します。
そして、targetコマンドで「remote localhost:1234」を指定します。
$ arm-none-eabi-gdb -q build/firmware.elf
Reading symbols from build/firmware.elf...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00008000 in start ()
(gdb)


あとは普通にGDBのコマンドが使えます。
よく使うのは

・l 現在位置のソースを表示
・n 次の行(関数の中には入らない)
・s ステップ(関数の中に入る)
・c continue
・b file:num fileのnum行をブレークポイントに
・b function functionの先頭をブレークポイントに
・p/x var 変数varを16進数表示(&varや*varという表現も可能)
・awatch var 変数varが読み書きされたらブレーク

あたりです。

以下に今回参考にしたサイトを挙げておきます。

piでベアメタルプログラミング - bobuhiro11's diary
RaspberryPi/kernel/src-qemu at master ・ richcole/RaspberryPi
QEMU ARM で遊ぼう
gdb の使い方・デバッグ方法まとめ
posted by boochow at 01:45| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月04日

ベアメタルRaspberry Pi版MicroPythonにREPLを追加してみました

rpi-mp-repl.png

先日書いた、ベアメタルRaspberry Piで動作するMicroPythonですが、このままだと対話的に使用することができないので、REPLを使えるように改造してみました。
改造にあたっては、以前紹介したunicorn用MicroPythonを参考にしました。
コードは以下で公開しています。

boochow/micropython-raspberrypi

ちょっと試してみたい方向けにバイナリを以下に置いておきます。
Raspberry Pi ZeroとZero Wで動作を確認しています。CPUが異なるのでPi2やPi3では動作しないと思います。

firmware.img

あとconfig.txtに以下のように書いて
kernel=firmware.img
上記のfirmware.imgと、bootcode.binとstart.elfと一緒にmicroSDカードのルートフォルダに入れれば動作します。
bootcode.binとstart.elfはこちらからダウンロードできます。

画面表示もUSB入力もサポートしていませんので、PCとUARTで接続する(GPIO 8番ピンと10番ピンを、それぞれUSB-UARTアダプタのRXとTXに、GPIO 6番ピンをGNDに接続する)必要があります。
電源ONから2〜3秒程度で立ち上がるはずです。

まだモジュールも追加していませんし、算術演算も整数だけという状態なので、REPLを動かす以外ほとんど何もできません。
あとは暇をみつけて機能追加していこうかと思います。
ラベル:MicroPython
posted by boochow at 19:02| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2017年12月28日

ベアメタルRaspberry Pi用MicroPythonが公開

以前、下記の記事で紹介したStefan NaumannさんのベアメタルRPi向けMicroPythonが公開されました。

Raspberry PiベアメタルでMicroPythonの調査: 楽しくやろう。

プルリクエストがこちらに出ています。
サポートされているハードウェアはRaspberry Pi Zeroのみで、おそらく初代Raspberry Piでも動作するだろうとのことです。RPi Zero Wは試してみましたが動作しませんでした動作しました。

Bare-Metal Raspberry Pi port by naums ・ Pull Request #3522 ・ micropython/micropython

マージされるまでは、下記にリポジトリの形でも公開されているそうです。

naums/micropython: MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems

学生さんのプロジェクト?であるらしく、期末レポートがこちらで公開されています。

Term Paper: Porting Micropython to bare-metal Raspberry Pi – Stefan Naumann

とりあえずビルドして、先日購入したRaspberry Pi Zeroで動かしてみました。
REPLが実装されておらず、mainの中で渡された文字列を実行して終わりなので、現時点ではIchigo Jamのように単体でプログラミングすることはできません。
ハードウェアはUARTとGPIOがサポートされており、Lチカはできるようです。

rpi-zero-serial.jpg


ちなみにRaspberry Pi Zeroにはまだピンヘッダを付けていなかったので、スルホール用テストワイヤを使いました。
バネが弱いので、沢山接続するにはあまり向かないと思いますが、このようにちょっとUARTを接続するだけなら割と便利です。
ラベル:MicroPython
posted by boochow at 01:41| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする
人気記事