2017年10月28日

fritzingのW5500 Ethernet Module用データを作ってみた

w5500module-fritzing.png

ブレッドボードでのパーツ接続図を描くツールにFritzingを使っていますが、このツールは新しいパーツを自分で追加することができます。
先日使ったW5500イーサネットモジュールのパーツデータを作ってみました。

作成方法の解説は、下記のページが分かりやすかったのでお勧めです。

Fritzing カスタムパーツの作り方 – jumbleat

Make Your Own Fritzing Parts - learn.sparkfun.com

基本的には、(1)ブレッドボード用の図(2)回路図(3)プリント基板用パターン の3つの図をSVG形式で作成し、かつ配線のポイントとなるピンやランドなどのオブジェクトの名前を決まったルールで付与します。
そして、これらのファイルをFritzingのパーツエディタに読み込み、各図のオブジェクトを相互に関連付けるXMLファイルを生成します。
ゼロからやると面倒そうですが、上記の解説はIC用の既存データを修正して作成する方法が紹介されており、その方法ならそれほど面倒ではありません。

これを使って先日の記事の接続図を作り直したものがこちらです。

Before:
stm32-w5500.png

After:
stm32-w5500-2.png


NUCLEOボードのグラフィックスの凝り様に比べると、非常にショボいグラフィックですが、データは一応以下に置いてあります。

boochow/W5500_fritzing_data
posted by boochow at 11:56| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2017年10月27日

Amazon Web Servicesを(今更)試してみた

aws-ec2.png

AWS IoTなるものに興味を持ったので、AWSのアカウントを取ってみました。
AWS IoTの前にまずはIaaSであるEC2のお勉強です。
教科書は、こちらを使いました。執筆陣には先頃KDDIに買収されたソラコムの玉川さんも入っています。

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版|日経BPブックナビ【公式サイト】
awsbook.jpg


この本はEC2のインスタンス2つ(WebサーバとDBサーバ)を立て、WordPressのサイトを作るチュートリアルになっています。
Webサーバはインターネットに公開し、DBサーバはプライベートネットワークにおきます。
ただしDBサーバはソフトウェア更新等のため、NATゲートウェイを介してインターネットへ接続できるようにします。
aws-book2.jpg

この本のおかげで細かいことに躓くことなく、使い方を学ぶことができました。
デフォルトのユーザが「ec2-user」であることとか、ssh接続のためのキーペアをつくるところとか、本書のようなガイドがあればどうということは無いですが、アカウントを作っていきなり試行錯誤していたら余計な時間がかかっていたかもしれません。

また、HTTPプロトコルをtelnetで目視したり、WireSharkでパケットを観測したりというトピックも扱っており、AWSに限らずネットワーク技術の入門書としても、とても良いと思いました。

WordPressはこんな感じで無事立てることができましたが、実際に使うかというと、個人では料金面が課題になりそうです。
aws-wordpress.png

12ヶ月間は無料利用枠が利用できますが、内容はEC2が750h/月なので24時間×31日分で、本書のようにインスタンスを2つ使ったら超過するのではないかと思います。
また、本書で使われているNAT Gatewayは時間課金+転送量課金で無料枠はありません(ので、試し終わったら削除しないと課金されます)。
個人でサーバを立てるだけなら定額のVPSサーバを借りるほうが良さそうです。
posted by boochow at 23:48| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2017年10月23日

Nucleo-F401RE + W5500モジュール + MicroPythonでインターネット接続

w5500-nucleo.jpg

先日、Arduino用のイーサネットシールドを無理やりNucleo-F401REボードに接続しましたが、この状態だとやはり危なっかしいので、より小型のモジュールを入手しました。
前回使用したW5100の兄弟チップのW5500を使用したモジュールです。
W5100はSPI以外に8bitバスでも制御可能でしたが、W5500はSPI専用です。
購入したモジュールはフリスクケース程度の大きさでした。
価格はAmazonマーケットプレイスで1000円程度でしたが、Aliexpressからだと$6〜$8くらいで買えるようです。
w5500.jpg


使い方はほぼW5100と同じですが、MicroPythonにはW5500用のドライバを組み込む必要があります。
W5100と違って、W5500はMicroPythonでサポートされていますので、コードを書き換える必要はありません。
現時点のバージョンのMicroPythonでは、makeのオプションで「MICROPY_PY_WIZNET5K=5500」というようにWIZnet5Kのチップ種別を指定できるようになっていますので、gitでcloneするところからmakeのやり方を以下に載せておきます。

git clone https://github.com/micropython/micropython.git
cd micropython/
git submodule update --init
cd ports/unix
make deplibs
make
cd ../stm32/
make BOARD=NUCLEO_F401RE CROSS_COMPILE=~/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi- MICROPY_PY_WIZNET5K=5500
cp build-NUCLEO_F401RE/firmware.hex /mnt/hgfs/share/
#このあとST-Link Utilityでボードに書き込む


接続する端子も、SPIですので基本的には同じです。
購入したモジュールのピン配列(裏面)は下図のようになっていました。

w5500-pins.jpg


ちなみにですが、私の購入したモジュールはピンヘッダが下のように斜めになっていました・・・
実用上は問題ないですが、ちょっと気にはなりますね。

w5500module.jpg


Nucleo-F401REとの接続は以下のようになります(SPI2を使用する場合)。
リセットは自由に決められますが、あとは使用するSPIバスによって自動的に決まってしまいます。

W5500 Nucleo-F401RE
3.3V 3V3
MISO PB14(MISO)
MOSI PB15(MOSI)
SCS PB12(NSS)
SCLK PB13(CLK)
5V -
GND GND
RST PC8
INT -
NC -
表面から見た接続図
stm32-w5500-2.png

(W5500モジュールのfritzingデータはこちら

MicroPythonからの使い方は、W5100のときと全く同じです。
コードは完全に互換性があります。
例によってSTARWARSサイトに接続してみました。
w5500-starwars.png

STM32 + W5500の組み合わせは、Arduino + Ethernetシールドよりもパワフルで、サイズもコンパクトに納まり、有線で使用するにはなかなか良いのではないかと思います。
ラベル:MicroPython
posted by boochow at 23:18| Comment(0) | stm32 | このブログの読者になる | 更新情報をチェックする

2017年10月21日

MicroPythonでurequestsを使う

ESP32版のMicroPythonでは、urequestsモジュールが標準で組み込まれています(現時点では)。
これはWebサーバにリクエストを投げて、応答を得るためのライブラリで、PythonのrequestsモジュールのMicroPython版(機能はだいぶ削られていますが)です。

現時点では、GET、HEAD、PUT、POST、PATCH、DELETEの各HTTPリクエストが実装されています。
PATCHというHTTPメソッドがあるんですね。初めて知りました。
ただ、このモジュールのソースを見るとHTTPバージョン1.0でリクエストを投げるようになっているので、HTTP 1.1のメソッドであるPATCHを要求するとエラーになる可能性もあるように思います。

サーバから返された結果はResponseオブジェクトに格納されます。

このオブジェクトは、

 status_code HTTPステータスコード(正常なら200)
 reason HTTPステータスコードのReason(正常なら'OK')
 encoding 文字コード(ただし現状では'utf-8'固定の実装となっている)
 content 生の応答データ
 text contentをencodingに従ってテキストに変換したもの
 json() contentをjsonとして解釈したもの(ujsonモジュールを使用)
 
を得ることができます。

内部的には、HTTPヘッダを読み終えた時点でソケットオブジェクトがResponseオブジェクトに渡されます。
ソケットオブジェクトはrawプロパティにセットされ、contentが初めて参照されたときにそのソケットからデータを読んでオブジェクト内にキャッシュするようになっています。
ソケットをcloseするには、close()を呼びます。

何度か例題に取り上げた、現在の為替レートを得るWebサービスにアクセスするには、以下のようになります。



WiFiに接続する部分は上記には入っていませんが、それでも短いですね。

ただし、現時点ではこのコードは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のソケット機能を使う場合よりも速度は低下するようです。
ラベル:MicroPython
posted by boochow at 18:28| Comment(0) | ESP8266/ESP32 | このブログの読者になる | 更新情報をチェックする

2017年10月15日

Nucleo-F401RE + Ethernet(W5100) + MicroPythonでインターネット接続

stm32-w5100.jpg


MicroPythonが動くようになったNucleo-F401REですが、ESP32と比べるとネット接続がありません。
しかし、調べてみるとこのボードにArduino用のイーサネットシールドを接続できることが分かりました。

Adding ethernet connectivity to a STM32-Nucleo

実は、私も買ったまま使っていない(このパターン多いです)Arduino用イーサネットシールドを持っており、上記の記事と同じW5100というチップを使用しているものでした。

このチップはWIZnetというメーカーの製品で、単なるEthernetコントローラではなく、TCP/IPが実装されており、単体で通信ができます。
イメージとしてはESP8266のLANバージョンみたいなものでしょうか。
ESP8266よりもかなり以前からあるシリーズで、国内でもスイッチサイエンスさんなどで扱いがあります。

一方、MicroPythonについて調べてみると、このW5000シリーズがドライバとして組み込めることが分かりました。
ただ、現時点ではサポートされているのはW5200とW5500のみでした。

Ethernet Adapter for PyBoard Which? - MicroPython Forum

なおW5500とSTM32の組み合わせはごく最近バグフィックスされたようです。

drivers: WIP getting WizNet5500 working with stm32 port. by dpgeorge ・ Pull Request #3362 ・ micropython/micropython

残念ながらMicroPythonにはW5100のドライバは入っていませんでしたが、W5200やW5500のドライバを調べてみると、WIZnetが開発したドライバを利用していました。
そこで、WIZnetのGitHubをのぞいてみると、W5100のドライバも用意されていました。
また、これらチップの差分を吸収する抽象レイヤも用意されており、MicroPythonでもそれを使用しているようです。

ということで、「WIZnetのW5100用ドライバをMicroPythonへポーティングするのは簡単なのでは?」と思い、やってみることにしました。

利用したWIZnetのドライバは、現時点での最新版と思われるこちらのライブラリです。

Wiznet/ioLibrary_Driver: Create a repository of WIZnet ioLibrary.

ドライバの入っている「Ethernet」フォルダと、DNSなどのプロトコルを実装している「Internet」フォルダがありますが、Ethernetフォルダだけ使用しました。
MicroPythonではInternetフォルダのDNS実装を使っているようでしたので、最初はこちらも最新のものを使おうかと思ったのですが、最新のほうはコンパイルエラーが出る(というかバグが残っている)ので、使うのをやめました。

このEthernetフォルダを、micropython/drivers/wiznet5k/Ethernetに展開します。
そして、以下のように使用するチップの指定を変更します。
../../ioLibrary_Driver/Ethernet/wizchip_conf.h wizchip_conf.h 
64c64
< #define _WIZCHIP_ 5500 // 5100, 5200, 5300, 5500
---
> #define _WIZCHIP_ 5100 // 5100, 5200, 5300, 5500


また、ドライバの抽象レイヤであるwizchip_conf.cは構造体の初期化のところで文法エラーが出るので修正します。
../../ioLibrary_Driver/Ethernet/wizchip_conf.c wizchip_conf.c 
169,172c169,172
< wizchip_cris_enter,
< wizchip_cris_exit,
< wizchip_cs_select,
< wizchip_cs_deselect,
---
> {wizchip_cris_enter,
> wizchip_cris_exit},
> {wizchip_cs_select,
> wizchip_cs_deselect},
176,177c176,177
< wizchip_bus_readdata,
< wizchip_bus_writedata,
---
> {{wizchip_bus_readdata,
> wizchip_bus_writedata}},


WIZnetチップはソケットのインタフェースが実装されています。
関数名はconnect、listenなどよく知られたAPIが使われていますが、もともとMicroPythonに組み込まれていたものに倣って、ソケット関連の関数名を変更するマクロを導入しました。

../../ioLibrary_Driver/Ethernet/socket.h socket.h
87a88,90
> // use this macro for exported names to avoid name clashes
> #define WIZCHIP_EXPORT(name) wizchip_ ## name
>
162c165
< int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);
---
> int8_t WIZCHIP_EXPORT(socket)(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);


以下略しますが、関数名socket, close, listen, connect, disconnect, send, recv, sendto, recvfrom, ctlsocket, setsockopt, getsockoptについて全て上記の変更を行います。
また、socket.cについても同様の変更を行います。
関数の宣言部だけでなく、内部でclose()を呼び出しているところがあるのでそこも変更が必要です。

また、&演算子の使い方でコンパイル時にエラーが出るので、以下を修正しました。
520,521c520,521
< if((taddr == 0) && (getSn_MR(sn)&Sn_MR_MACRAW != Sn_MR_MACRAW)) return SOCKERR_IPINVALID;
< if((port == 0) && (getSn_MR(sn)&Sn_MR_MACRAW != Sn_MR_MACRAW)) return SOCKERR_PORTZERO;
---
> if((taddr == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_IPINVALID;
> if((port == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_PORTZERO;


W5100のドライバは全く変更する必要はありません。ただ、インクルードパスの都合でw5100.hを少しだけ修正します。
../../../../../ioLibrary_Driver/Ethernet/W5100/w5100.h w5100.h
44c44
< #include "wizchip_conf.h"
---
> #include "../wizchip_conf.h"


また、application/dns/フォルダのdns.hも同様に1行だけ修正します。
diff dns.c dns.c~
57c57
< #include "../../Ethernet/socket.h"
---
> #include "../../ethernet/socket.h"


ここでMicroPythonの内部構造を少し書いておきます。
STM32関連の実装は「ports/stm32」に集められています。
networkモジュールはmodnetwork.cで実装されていますが、種類の異なるNICごとの実装は別ファイルになります。
WIZnet5Kシリーズのための実装はmodnwwiznet5k.cにあり、この実装はSTM32のHALライブラリを介してSPIをたたいてWIZnet5Kのデバイスと通信しています。

WIZnet5KドライバのAPIが、もともとMicroPythonに含まれていたものと若干変わっているので、これらのドライバを呼び出すmodnwwiznet5k.c側の修正も必要になりました。
具体的には、SPIのコールバック関数として、1バイトずつの送受信を行うものが新たに必要になりましたので追加しました。
また、W5000シリーズのレジスタの呼び名が若干変更になっています。
diff modnwwiznet5k.c modnwwiznet5k.c.org 
41,42c41,42
< #include "Ethernet/wizchip_conf.h"
< #include "Ethernet/socket.h"
---
> #include "ethernet/wizchip_conf.h"
> #include "ethernet/socket.h"
74,87c74
< STATIC uint8_t wiz_spi_read(void) {
< uint8_t c;
< HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi, &c, 1, 5000);
< (void)status;
< return c;
< }
<
< STATIC void wiz_spi_write(uint8_t c) {
< HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi, &c, 1, 5000);
< (void)status;
< }
<
< //STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) {
< STATIC void wiz_spiburst_read(uint8_t *buf, uint16_t len) {
---
> STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) {
92,93c79
< //STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) {
< STATIC void wiz_spiburst_write(uint8_t *buf, uint16_t len) {
---
> STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) {
381d366
< reg_wizchip_spiburst_cbfunc(wiz_spiburst_read, wiz_spiburst_write);
424c409
< printf(" %02x", WIZCHIP_READ(WIZCHIP_OFFSET_INC(WIZCHIP_SREG_BLOCK(sn), i)));
---
> printf(" %02x", WIZCHIP_READ(WIZCHIP_SREG_ADDR(sn, i)));


最後にMakefileです。
こちらもW5200指定になっていたのでその修正と、インクルードパスの修正をします。
diff Makefile Makefile.org 
295,297c295,297
< Ethernet/W5100/w5100.c \
< Ethernet/wizchip_conf.c \
< Ethernet/socket.c \
---
> ethernet/w5200/w5200.c \
> ethernet/wizchip_conf.c \
> ethernet/socket.c \


以上で移植作業は完了です。
makeします。

cd micropython/ports/stm32/
make BOARD=NUCLEO_F401RE CROSS_COMPILE=~/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi- MICROPY_PY_WIZNET5K=1
cd build-NUCLEO_F401RE/
cp firmware.hex /mnt/hgfs/share/
#このあとST-Link Utilityで書き込み


実際にNucleo-F401REとW5100でインターネットアクセスしてみました。
結線は下図のようになります。
stm32-w5100.png

Adding ethernet connectivity to a STM32-Nucleoにも書かれていますが、このイーサネットシールドはSPIの信号が、Nucleoボードが持っていない6ピンの端子に出ているため、配線に工夫が必要です。
私のボードは6ピン端子の足元の部分に線が露出していたので、ICクリップを使って接続しました。
ethernet-shield-spi.jpg

まずはESP32のときと同様、アスキーアートSTAR WARSに接続してみます。
SPIオブジェクトがmachine.SPIだとクラスが違うというエラーが出てしまい、pyb.SPIを使う必要がありました。
このへんはMicroPythonの問題だと思います。



ちょっとカクカクしますが、一応表示されました。

starwars.png


以下の記事によると、W5kシリーズの通信速度は、最新のW5500でDMAを使用したとき4.4Mbps、使用しないとき1.7Mbpsくらい出るようです。

STM32F401REでSPI DMAを利用してW5500の送受信性能改善 | WIZnet JP Blog

HTTPでの通信も試してみました。
これまたESP32のときと同じネタです。
今回はLCDは使わず、とりあえず通信できるかどうかの確認です。
WIZNET5Kオブジェクトはreadline()が実装されていなかったので、コードは若干変わっています。



REPLの中で呼び出すと結果が表示されます。

>>> main()
2017-10-13
JPY/USD: 112.18
>>>


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