2017年11月23日

シリアルポート接続のJPEGカメラを買ってみた

jpeg-camera.jpg

Aliexpressの11月11日のセールのときに、いくつか買い物をしたのですが、そのうちの一つであるJPEGカメラが届きました。
撮影した画像をシリアルポート経由で取り出せるカメラで、同様の製品はスイッチサイエンスや秋月電子でも販売されています。
今回買ったのは以下の製品で、セールだったので$15.2でした。
発送も比較的迅速で良かったと思います。(同時に4つの店舗で購入しましたが、残り3つの荷物はまだ日本行きの飛行機に乗るか乗らないかといったところです。)

New Color JPEG Color UART TTL Serial Port Digtial Camera Module with OV528 communicaiton protocol-in Surveillance Cameras from Security & Protection on Aliexpress.com | Alibaba Group

上記のページからもリンクされていますが、Windows用のテストプログラムが配布されていますので、とりあえず動かしてみました。
接続する端子はVCC、GND、RX、TXの4本です。
夜間監視用らしく、赤外線LEDも搭載されており、そちらを光らせる場合は別途接続が必要です。

5V動作なので、USBシリアルアダプタのジャンパを5V側に設定して接続しました。
テスト用のアプリケーションは下のように延々とカメラ画像を表示するだけのものです。
ad-7732.png

通信速度は最高で115.2Kbps、解像度は最高640x480ピクセルで、1フレーム送るのに3秒くらいかかっている計算です。QVGAにすれば1秒を切るかもしれません。

NUCLEO-F401REは5Vトレラントなので、そのうち繋いで監視カメラもどき?でも作ってみようかと思います。
posted by boochow at 15:14| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする

STM32のMicroPythonでlwIPを使う

lwip-wiznet5500.png
現在のSTM32用のMicroPythonでは、TCP/IPとして利用できるのはWIZnetやCC3000などのTCP/IPモジュールだけです。
これに対して、以前の記事で、WIZnetのTCP/IPモジュールをイーサネットインタフェースとして使い、TCP/IP実装はlwIPを用いるような実装が進められていることを書きました。(lwIPはオープンソースの軽量なTCP/IP実装です。)
ただし、現時点ではこのコードはESP32/ESP8266のMicroPythonでないと動かないと思います。
urequestsは内部でsocket.readline()を使用していますが、CC3100やWIZnet5Kなど、上記以外のNICではreadline()が実装されていないからです。

そのため、WIZnet5Kに関してはTCP/IP実装はlwIPを使用し、WIZnet5Kは単なるイーサネットインタフェースとして使用するようなMicroPython側のドライバ実装が現在テスト中のようです。

stm32: Incorporate lwip stack and use Wiznet in MACRAW mode by dpgeorge ・ Pull Request #3379 ・ micropython/micropython

ただ、TCP/IPをメインCPUで処理するため、WIZnet5Kのソケット機能を使う場合よりも速度は低下するようです。

上記を書いた後、チューニングが進んでかなり高速化されたようなので、試してみることにしました。
この方式だと、WIZnetを使う場合と比べて、socketの機能がフル実装されますので、上に書いたようにurequestsなどの便利なモジュールが利用できるようになるというメリットがあります。

この実装はDamien George本人が行っていますが、現時点ではマスターブランチへのマージは行われていません。そのため、このブランチをダウンロードしてコンパイルする必要があります。
手順は以下の通りです。

まず、本家ではなくDamien GeorgeのMicroPythonリポジトリをcloneします。
mkdir micropython-lwip
cd micropython-lwip/
git clone https://github.com/dpgeorge/micropython.git


このリポジトリは沢山のブランチがありますので、ブランチの一覧を見ます。
cd micropython/
git branch -r


表示された中から、stm32-lwip-wiznetブランチを選択します。
git checkout -b stm32-lwip-wiznet origin/stm32-lwip-wiznet


ビルドします。
git submodule update --init
make -C mpy-cross
make -C ports/stm32 MICROPY_PY_WIZNET5K=5500 BOARD=NUCLEO_F401RE CROSS_COMPILE=~/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-


追記:以下の事象をリポートしたところ、速攻で修正されたので、現在は以下の修正は必要なくなっています。

すると、以下のようなエラーが出ました。
LINK build-NUCLEO_F401RE/firmware.elf
build-NUCLEO_F401RE/main.o: In function `rand':
main.c:(.text.rand+0x0): undefined reference to `rng_get'
build-NUCLEO_F401RE/lib/lwip/src/core/dhcp.o: In function `dhcp_create_msg':
dhcp.c:(.text.dhcp_create_msg+0x30): undefined reference to `rng_get'
build-NUCLEO_F401RE/lib/lwip/src/core/ipv4/igmp.o: In function `igmp_delaying_member':
igmp.c:(.text.igmp_delaying_member+0x1e): undefined reference to `rng_get'
build-NUCLEO_F401RE/lib/lwip/src/core/ipv4/igmp.o: In function `igmp_joingroup':
igmp.c:(.text.igmp_joingroup+0x72): undefined reference to `rng_get'
Makefile:447: ターゲット 'build-NUCLEO_F401RE/firmware.elf' のレシピで失敗しました

リンクに失敗しているようです。rng_getが見つからないと言われています。

ということでちょっと調べたところ、以下のことが分かりました:

・lwIPは、移植の際に32bitの乱数を得る関数LWIP_RAND()を#defineで与える必要がある。乱数がいいかげんだと脆弱性につながるので、あまり適当な関数を与えないほうが良い。
・今回のMicroPythonの実装では、LWIP_RANDは ports/stm32/lwip-include/lwipopts.h の中で与えており、その定義は以下のようである。
extern uint32_t rng_get(void);
#define LWIP_RAND() rng_get()

・このrng_get()の実体は ports/stm32/rng.c で定義されており、その実装はHAL_RNG_GetRandomNumber()を呼び出すだけである。
・ただし、rng.cの中身全体が #if MICROPY_HW_ENABLE_RNG で囲われているので、rng_get()がリンクエラーになったということはMICROPY_HW_ENABLE_RNGが設定されていない可能性が高い。

ということで、ports/stm32/boardsの各ボードでどのようになっているか調べてみます。
cd ports/stm32/boards/
grep MICROPY_HW_ENABLE_RNG */mpconfigboard.h

結果を見ると、ESPRUINO_PICO、PYBLITEV10、STM32F411DISCで値が0になっているほか、F401REでは値の設定もされていません。
F401REがハードウェア乱数発生器を持っているのであれば1、持っていないのであれば0に設定すべきです。
ハードウェア乱数発生器の有無は、STM32のHALの実装を見ると分かります。
micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src の中にある、stm32f4xx_hal_rng.c を見てみます。
すると
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defi
ned(STM32F417xx) ||\
defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defi
ned(STM32F439xx) ||\
defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) || defi
ned(STM32F469xx) ||\
defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) || defi
ned(STM32F412Rx) ||\
defined(STM32F412Cx) || defined(STM32F413xx) || defined(STM32F423xx)

となっていて、残念ながらF401REは対象外のようです。
STMicroのアプリケーションノート「AN4230」を見ても、やはりF401REにはハードウェア乱数発生器は載っていないように見えます。(このアプリケーションノート自体は、生成された乱数が暗号学的乱数になっているかテストしたレポートです。)

従って、F401REではLWIP_RAND()に用いる乱数発生器をソフトウェアで実装する必要があります。もちろん暗号学的乱数であることが望ましいですが、MicroPythonにそこまで求めるのはどうかという気もします。

そもそも、乱数生成のソフトはMicroPythonにもともと入っている可能性が高いのではないか? と思い、調べてみたところ、以下が見つかりました。

Pseudo-random number generator ・ Issue #965 ・ micropython/micropython

yasmarangという乱数生成の関数が、MicroPythonのurandomモジュールで実装されていますので、これをLWIP_RAND()の実体として使うことにします。
まず、ports/stm32/rng.cの最後のほうにコードを追加して、ハードウェア乱数生成器が無い場合はyasmarang()を使うようにします。

追記:このやり方だとurandomモジュールが生成する乱数列の再現性が失われてしまうため、修正されたコードではrng.cの内部にyasmarangのコードを複製して使っています。

ports/stm32/rng.c:
#if MICROPY_HW_ENABLE_RNG
//途中省略
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);

#else

extern uint32_t yasmarang(void);

uint32_t rng_get(void) {
return yasmarang();
}

#endif // MICROPY_HW_ENABLE_RNG

また、yasmarang()はstatic宣言されていますので、これを外部から呼び出せるようにstaticを外します。

extmod/modurandom.c
//STATIC uint32_t yasmarang(void)
uint32_t yasmarang(void)
{


これでリンクが通るようになりました。
使い方ですが、以前のWIZNET5Kと結線は全く同じですが、ソフトウェアは完全互換ではなく微妙に違います。
サンプルが ports/stm32/wiznet_connect.py に入っているのでその通りやればOKです。
明示的にactiveにしたりdhcpでアドレス設定させたりという処理が必要になるようです。

SPI2を使う結線の場合のサンプルです。
例によってスターウォーズ視聴です。
DHCPのアドレス取得など、WIZnet側に任せる場合と比べて初期化にちょっと時間がかかる印象がありますが、F401REを使う場合は、通信速度自体はむしろこちらのほうが高速です。


ラベル:MicroPython
posted by boochow at 10:04| Comment(0) | stm32 | このブログの読者になる | 更新情報をチェックする

2017年11月19日

Raspberry Pi Zeroにカラーのピンヘッダを装着

rpi-color-gpio.jpg

これまでRaspberry Piを電子工作的には使ってこなかったこともあり、RPi Zero WのGPIOにはピンヘッダをつけていなかったのですが、ベアメタルの実験用にピンヘッダをつけました。

ピンの機能が色分けされた製品があったので、それを使ってみました。
英国で電子工作関連のグッズをいろいろ売っているPimoroniの製品です。

Colour-coded GPIO Header for Pi Zero - Pimoroni

国内では千石電商で買えます。200円でした。

COM1111 Colour-coded GPIO Header for Pi Zero

この色分けの意味ですが、5Vが赤、3.3Vが黄色、GNDが黒です。
rpi-gpio.png


ここまではいいのですが、水色のピンがあって、これは「何も繋ぐな」(Do Not Connect)となっています。
わざわざピンを引き出しておいて、繋ぐなとはどういうことでしょう。
回路図を見ると、この2本のピンの用途が書いてありました。
rpi-gpio-idsc-idsd.png

このピン(ID_SD、ID_SC)は、Raspberry Piに接続するボード(HAT)上のEEPROMを接続するための端子だそうです。
信号的にはI2Cですが、ブート時にここからEEPROMを読み取って、それにあわせたGPIO設定をするためのものなので、それ以外の目的に使ってはいけない、ということです。

この信号の使い方については、Raspberry Piのブログに記載があり、仕様もGitHubで公開されています。

Introducing Raspberry Pi HATs - Raspberry Pi

raspberrypi/hats

posted by boochow at 19:38| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

Raspberry Pi2でベアメタルプログラミング環境を作成

rpi-baremetal1.jpg

先日ちょっと調べたRaspberry Piのベアメタルプログラミングですが、やはり調べたら試してみたくなるもので、Interface誌2017年2月号の記事の通りにやってみました。

ちょっと試すだけならQIピンでの接続でもいいのですが、UARTとJTAGをつなぐとなると結構な本数になりますので、接続用の基板を作成することにしました。
上の写真のように、Raspberry PiのGPIOヘッダと、JTAG用およびUART用のコネクタを接続した基板です。

ターゲットマシンはRaspberry Pi2ですが、将来的にPi Zeroでの利用も考えて、aitendoのPi Zero用のユニバーサル基板を使いました。
rpi-baremetal3.jpg

GPIOをそのまま接続した40pinボックスヘッダ、JTAG用の20pinボックスヘッダ、UART用の6ピンヘッダがついています。
GPIOのピン配列はこちらが詳しいです。

40pinボックスヘッダは、デバッグしながら他のI/Oも使いたい場合のために付けてあり、ここからフラットケーブルでブレッドボードなどに配線する想定です。
JTAGは手持ちの製品がSEGGER J-Link(のコピー品?)なので、ボックスヘッダもこの製品のピン配列に合わせて配線していますが、基本的にどこの製品でも20pinなら同じピン配列だと思います。
UARTは、以前から使っているスイッチサイエンスの製品です。6ピンになっていますが、配線はGNDとRX、TXだけです。
rpi-baremetal2.jpg

参考までに結線も載せておきます。

表面
rpi_jtag_uart_surface.png
裏面
rpi_jtag_uart.png


これをRaspberry Pi2につないで、Interface誌2017年2月号のDVDに入っている開発環境のVMをインストールして、Eclipse + OpenOCDでJTAG経由でのデバッグを試しました。
今回は記事の通りにすれば良かったので、かなり楽にできましたが、設定項目は複雑な上に「RPi2の場合は1回目はOpenOCDがうまく動かないので2回起動する」といった謎のバッドノウハウもあり、この記事なしに最初から自分でやろうとしたらかなり時間がかかったのではないかと思います。

なお、付録のDVDではOpenOCDで使用するJ-Link用の設定ファイルは
 /usr/local/share/openocd/scripts/interface/jlink.cfg

です。
インタフェースのシリアル番号を記入するようになっていますので、
# Example: Select J-Link with serial 123456789
#
jlink serial 000000123456

のように頭の0を省略せずに指定します。
また、openocdの起動は
$ sudo openocd -f /home/user/arm/cfg/jlink.cfg -f /home/user/arm/cfg/raspi2.cfg
のようにスーパーユーザの権限で行う必要がありました。

なお、初代RPiとRPi Zero Wは同じCPUを使っていますので、初代RPi用のベアメタルのオブジェクトならRPi Zeroでも動作するのではないかと思って試してみましたが、うまくいきませんでした。
posted by boochow at 00:27| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2017年11月18日

書籍「Programming with MicroPython」を購入

mp-book.jpg

オライリーから、「Programming with MicroPython」という本が出ましたので読んでいます。
ざっと内容を紹介すると、以下のような感じです。

1章:MicroPythonの歴史。なかなか興味深いです。Damien George(MicroPythonの作者)はPyBoardとESP8266+MicroPythonと、KickStarterを2回成功させているんですね。
他にも、micro:bitにMicroPythonが載ったのは、Damien Georgeの職場の隣の部屋にmicro:bitのボードを設計したARMのエンジニアがいて、頼まれたGeorgeが一週間でMicroPythonを動作するようにした、なんて話が載っています。
また、micro:bitの派生プロジェクトでドイツではCALLIOPEというプロジェクトが動いているそうです。
日本ではスイッチサイエンスさんのグループ会社のスイッチエデュケーションの活躍に期待したいところですね。

2章〜5章:ハードウェアの解説。PyBoard、micro:bit、Adafruit Circuit Playground Express、ESP8266/ESP32が取り上げられています。

6章:組み込みプログラミング概論。

7章〜12章:分野別、MicroPythonプログラミング。内訳はディスプレイ(LCDやNeoPixel等)、入力デバイス(ボタン、タッチセンサ、モーションセンサ、温度センサ等)、インタフェース(SPI、I2C、UART、I/Oピン)、ネットワーク(赤外線通信、micro:bitの無線送受信、WiFi、HTTP、MQTT)、サウンド、モーター制御です。

13章:MicroPythonで省メモリ、高パフォーマンスのプログラムを作成するためのノウハウ。MicroPythonにはconstという、Cでいう#defineみたいなものがあるのですが(この記事で使いました)、これは整数しか使えないしモジュール外からは参照できない、なんていう話も書かれていて参考になります。

14章:より詳しく知りたい人のためのガイド。

ということで、組み込みは初めてという場合にはどの章も参考になると思います。1章と13章はMicroPython特有の話なので、初心者でなくても楽しめると思います。
ラベル:MicroPython
posted by boochow at 13:11| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする
人気記事