BeagleBone BlackのAngstrom Linuxに入ってるNode.jsについて
ちょっとだけ調べてみました。
Nodeのバージョン
root@beaglebone:~# node -v v0.8.22
Node Package Managerも入っているようです
root@beaglebone:~# npm Usage: npm <command> where <command> is one of: add-user, adduser, apihelp, author, bin, bugs, c, cache, completion, config, ddp, dedupe, deprecate, docs, edit, explore, faq, find, find-dupes, get, help, help-search, home, i, info, init, install, isntall, issues, la, link, list, ll, ln, login, ls, outdated, owner, pack, prefix, prune, publish, r, rb, rebuild, remove, restart, rm, root, run-script, s, se, search, set, show, shrinkwrap, star, stars, start, stop, submodule, tag, test, tst, un, uninstall, unlink, unpublish, unstar, up, update, version, view, whoami npm <cmd> -h quick help on <cmd> npm -l display full usage info npm faq commonly asked questions npm help <term> search for help on <term> npm help npm involved overview Specify configs in the ini-formatted file: /home/root/.npmrc or on the command line via: npm <command> --key value Config info can be viewed via: npm help config npm@1.2.14 /usr/lib/node_modules/npm
Nodeのパッケージを調べてみる
root@beaglebone:~# npm list -g /usr/lib ├─┬ bonescript@0.2.2 │ ├─┬ express@3.1.0 │ │ ├── buffer-crc32@0.1.1 │ │ ├── commander@0.6.1 │ │ ├─┬ connect@2.7.2 │ │ │ ├── bytes@0.1.0 │ │ │ ├── formidable@1.0.11 │ │ │ ├── pause@0.0.1 │ │ │ └── qs@0.5.1 │ │ ├── cookie@0.0.5 │ │ ├── cookie-signature@0.0.1 │ │ ├── debug@0.7.2 │ │ ├── fresh@0.1.0 │ │ ├── methods@0.0.1 │ │ ├── mkdirp@0.3.3 │ │ ├── range-parser@0.0.4 │ │ └─┬ send@0.1.0 │ │ └── mime@1.2.6 │ ├── UNMET DEPENDENCY serialport 0.7.5 │ ├─┬ socket.io@0.8.7 │ │ ├── policyfile@0.0.4 │ │ ├── redis@0.6.7 │ │ └─┬ socket.io-client@0.8.7 │ │ ├── uglify-js@1.0.6 │ │ ├── websocket-client@1.0.0 │ │ └── xmlhttprequest@1.2.2 │ ├── systemd@0.2.0 │ └─┬ winston@0.6.2 │ ├── async@0.1.22 │ ├── colors@0.6.0-1 │ ├── cycle@1.0.2 │ ├── eyes@0.1.8 │ ├── pkginfo@0.2.3 │ ├── request@2.9.203 │ └── stack-trace@0.0.6 └─┬ npm@1.2.14 ├── abbrev@1.0.4 ├── ansi@0.1.2 ├── archy@0.0.2 ├── block-stream@0.0.6 ├── chmodr@0.1.0 ├── chownr@0.0.1 ├── fstream@0.1.22 ├─┬ fstream-npm@0.1.3 │ └── fstream-ignore@0.0.6 ├── glob@3.1.21 ├── graceful-fs@1.2.0 ├── inherits@1.0.0 ├── ini@1.1.0 ├─┬ init-package-json@0.0.6 │ └── promzard@0.2.0 ├── lockfile@0.3.0 ├── lru-cache@2.2.2 ├─┬ minimatch@0.2.11 │ └── sigmund@1.0.0 ├── mkdirp@0.3.5 ├── node-gyp@0.8.5 ├── nopt@2.1.1 ├─┬ npm-registry-client@0.2.18 │ └── couch-login@0.1.15 ├─┬ npmconf@0.0.23 │ └─┬ config-chain@1.1.5 │ └── proto-list@1.2.2 ├── npmlog@0.0.2 ├── once@1.1.1 ├── opener@1.3.0 ├── osenv@0.0.3 ├─┬ read@1.0.4 │ └── mute-stream@0.0.3 ├── read-installed@0.1.1 ├── read-package-json@0.2.2 ├── request@2.9.203 ├── retry@0.6.0 ├── rimraf@2.1.4 ├── semver@1.1.4 ├── slide@1.1.3 ├── tar@0.1.16 ├── uid-number@0.0.3 └── which@1.0.5 npm ERR! missing: serialport@0.7.5, required by bonescript@0.2.2 npm ERR! not ok code 0
ふむふむ、bonescriptはもちろん、express, socket.io, serialportなどがグローバルインストールされていました。ということは、AngstromのままでもNode.jsでプログラム書いて動かして遊ぶのもいいですね
BeagleBone BlackにNode.jsをインストールする2(セルフビルド)
見事にビルドに失敗・・・ググってみたら、傘のお肉はどこにあるの?知り合いの@iwata_nのブログに引っ掛かったw
つまりは
./configure --without-snapshot
が必要ということなので、nodebrewのソースを修正して対応します。
nodebrew本体のコード(~./nodebrew/nodebrew)の「sub _cmd_install」にあるConfigureに--without-snapshotを追加します
system qq[ cd "$src_dir/$target_name" && ./configure --without-snapshot --prefix="$self->{node_dir}/$version" && make && make install ];
これでもう一度インストールしてみます。一旦さっきのバージョンをuninstallしておいてから再度インストール。
ubuntu@ubuntu-armhf:~$ nodebrew uninstall v0.10.21 v0.10.21 uninstalled ubuntu@ubuntu-armhf:~$ nodebrew ls not installed current: none ubuntu@ubuntu-armhf:~$ nodebrew install v0.10.21 fetch: http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz ######################################################################## 100.0% { 'target_defaults': { 'cflags': [], 'default_configuration': 'Release', 'defines': [], 'include_dirs': [], 'libraries': []}, 'variables': { 'arm_fpu': 'vfpv3', 'arm_neon': 0, 'armv7': 1, 'clang': 0, 'gcc_version': 46, 'host_arch': 'arm', 'node_install_npm': 'true', 'node_prefix': '/home/ubuntu/.nodebrew/node/v0.10.21', 'node_shared_cares': 'false', 'node_shared_http_parser': 'false', 'node_shared_libuv': 'false', 'node_shared_openssl': 'false', 'node_shared_v8': 'false', 'node_shared_zlib': 'false', 'node_tag': '', 'node_unsafe_optimizations': 0, 'node_use_dtrace': 'false', 'node_use_etw': 'false', 'node_use_openssl': 'true', 'node_use_perfctr': 'false', 'node_use_systemtap': 'false', 'python': '/usr/bin/python', 'target_arch': 'arm', 'v8_enable_gdbjit': 0, 'v8_no_strict_aliasing': 1, 'v8_use_arm_eabi_hardfloat': 'true', 'v8_use_snapshot': 'false'}}
「'v8_use_snapshot': 'false'」になっています。失敗した時のログを見てみると
fetch: http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz ######################################################################## 100.0% { 'target_defaults': { 'cflags': [], 'default_configuration': 'Release', 'defines': [], 'include_dirs': [], 'libraries': []}, 'variables': { 'arm_fpu': 'vfpv3', 'arm_neon': 0, 'armv7': 1, 'clang': 0, 'gcc_version': 46, 'host_arch': 'arm', 'node_install_npm': 'true', 'node_prefix': '/home/ubuntu/.nodebrew/node/v0.10.21', 'node_shared_cares': 'false', 'node_shared_http_parser': 'false', 'node_shared_libuv': 'false', 'node_shared_openssl': 'false', 'node_shared_v8': 'false', 'node_shared_zlib': 'false', 'node_tag': '', 'node_unsafe_optimizations': 0, 'node_use_dtrace': 'false', 'node_use_etw': 'false', 'node_use_openssl': 'true', 'node_use_perfctr': 'false', 'node_use_systemtap': 'false', 'python': '/usr/bin/python', 'target_arch': 'arm', 'v8_enable_gdbjit': 0, 'v8_no_strict_aliasing': 1, 'v8_use_arm_eabi_hardfloat': 'true', 'v8_use_snapshot': 'true'}}
こちらはtrueになっていました。
さてまたしても1時間経過・・・ビルド完了
symlinking ../lib/node_modules/npm/bin/npm-cli.js -> /home/ubuntu/.nodebrew/node/v0.10.21/bin/npm updating shebang of /home/ubuntu/.nodebrew/node/v0.10.21/bin/npm to /home/ubuntu/.nodebrew/node/v0.10.21/bin/node ubuntu@ubuntu-armhf:~$ nodebrew ls v0.10.21 current: none ubuntu@ubuntu-armhf:~$ nodebrew use v0.10.21 use v0.10.21 ubuntu@ubuntu-armhf:~$ node >
というわけで、無事Node.jsが起動できるようになりました。
BeagleBone BlackにNode.jsをインストールする(セルフビルド)
いつものようにNode.jsをインストールします。今回はnvmではなくnodebrewを使い、セルフビルドにてインストールします。
BeagleBone Black用のNode.js
ビルドするのが面倒な方はこちらにインストールバイナリがありますので、こちらを使ったほうが楽チンです。その場合はnodebrewは必要ありません。このリンク先のNode.jsのバージョンはv0.10.21なので、同じバージョンをnodebrewでセルフビルドでインストールします
ビルド環境のインストール
ubuntu@ubuntu-armhf:~$ sudo apt-get install curl build-essential libssl-dev
nodebrewのインストール
nodebrewに関してはBlock Rockin’ Codesに記事があるのでご参考に。nodebrewのサイトはこちらです。サイトにあるように下記コマンドでインストールできます。なおnodebrewをインストールするとnpm(Node Package Manager)も同時にインストールされます。
ubuntu@ubuntu-armhf:~$ curl -L git.io/nodebrew | perl - setup % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 18651 100 18651 0 0 18947 0 --:--:-- --:--:-- --:--:-- 18947 fetching nodebrew... install nodebrew in $HOME/.nodebrew ======================================== Add path: export PATH=$HOME/.nodebrew/current/bin:$PATH ========================================
インストールしたら、上記パスをvimなどで.bashrcに追加して、sourceコマンドで読み込みなおしておきます
ubuntu@ubuntu-armhf:~$ vim .bashrc ubuntu@ubuntu-armhf:~$ source .bashrc
nodebrew ls-remoteで使えるNode.jsのバージョンが取得できます
ubuntu@ubuntu-armhf:~$ nodebrew ls-remote -- 省略-- v0.9.0 v0.9.1 v0.9.2 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9 v0.9.10 v0.9.11 v0.9.12 v0.10.0 v0.10.1 v0.10.2 v0.10.3 v0.10.4 v0.10.5 v0.10.6 v0.10.7 v0.10.8 v0.10.9 v0.10.10 v0.10.11 v0.10.12 v0.10.13 v0.10.14 v0.10.15 v0.10.16 v0.10.17 v0.10.18 v0.10.19 v0.10.20 v0.10.21 v0.10.22 v0.10.23 v0.11.0 v0.11.1 v0.11.2 v0.11.3 v0.11.4 v0.11.5 v0.11.6 v0.11.7 v0.11.8 v0.11.9
nodebrewにはバイナリのインストール機能がありますので、試しにv0.10.21をインストールしようとすると、サポートしてないよ!ってエラーが出てしまいます。
ubuntu@ubuntu-armhf:~$ nodebrew install-binary v0.10.21 Error: Linux armv7l is not supported. at /home/ubuntu/.nodebrew/current/bin/nodebrew line 585.
Node.jsのセルフビルドでのインストール
というわけで、セルフビルドでインストールします (ちなみに以下、失敗します...ちゃんと動くようにビルドするにはコチラへ)
ubuntu@ubuntu-armhf:~$ nodebrew install v0.10.21
セルフビルドは約1時間・・・(class2のSDカードだったのでclass10だともっと速いと思われ)
installing /home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/npm/lib/utils/completion/installed-shallow.js installing /home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/npm/lib/utils/completion/file-completion.js symlinking ../lib/node_modules/npm/bin/npm-cli.js -> /home/ubuntu/.nodebrew/node/v0.10.21/bin/npm updating shebang of /home/ubuntu/.nodebrew/node/v0.10.21/bin/npm to /home/ubuntu/.nodebrew/node/v0.10.21/bin/node
ちゃんとインストールされたか確認
ubuntu@ubuntu-armhf:~$ nodebrew ls v0.10.21 current: none
v0.10.21を使用するように指定
ubuntu@ubuntu-armhf:~$ nodebrew use v0.10.21 use v0.10.21 ubuntu@ubuntu-armhf:~$
さて、ではnodeを起動してみます
ubuntu@ubuntu-armhf:~$ node Segmentation fault _人人人人人人人人人人人_ > Segmentation fault <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
...orz
BeagleBone BlackにUbuntu12.04をインストールする
作業の備忘録として記録しています。Raspberry Piを触っていれば、ほぼ同じような手順ですが・・・ (本当はIntel Galileoで遊ぶつもりが発売が年明けに延びたので、こっちをやっつけることに...)
追記 この方法では、SDカードからのブート時に「ボタン」を押す必要がありますが、きんねこさんが押さなくても起動するように、解決してくれました。 armhf.comで配布しているUbuntuイメージはボタン押さないと起動できない件 解決方法は最後に追記しました
BeagleBone Blackの購入
たまたま寄った秋月電子に最新版のRev A6が売ってたので購入¥4,980
UbuntuをSDカードに書き込む
ホストマシンはMacintoshです。まずはBeagleBone Black用のUbuntuイメージをダウンロードします。今回はLTS版のPrecidse 12.04を使います
ダウンロードしたら解凍します。
$ xz -d ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img.xz
解凍して出来たイメージをSDカードに書き込みます。使用するmicroSDは2GB以上のclass10が良いでしょう。ddコマンドで書きこめばいいのですが、Raspberry Piで使用した「RPi-sd card builder」などを使うと楽になります。
Ubuntuから起動
LANケーブルを接続しておき、SDカードを本体に差し込み起動しますが、そのままでは起動しないので、Bootボタンを押しながら電源を入れます。LEDが点滅し始めたら離しても大丈夫のようです(離すまでの時間が曖昧・・・)無事起動していればsshでログインできるはずです。
$ ssh ubuntu@192.168.0.6 <— BeagleBone Blackのアドレス ubuntu@192.168.0.6's password: Welcome to Ubuntu 12.04.3 LTS (GNU/Linux 3.8.13-bone30 armv7l) * Documentation: https://help.ubuntu.com/ The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. ubuntu@ubuntu-armhf:~$
パーティションの拡張
今回は4GBのSDカードを使ったのですが、そのままではブートイメージのサイズ上2GBしか使用できないので、パーティションの拡張を行います。電子工作マスターへの歩みを参考にfdiskで拡張します
ubuntu@ubuntu-armhf:~$ df -h Filesystem Size Used Avail Use% Mounted on rootfs 1.8G 244M 1.5G 15% / /dev/root 1.8G 244M 1.5G 15% / devtmpfs 248M 4.0K 248M 1% /dev none 50M 224K 50M 1% /run none 5.0M 0 5.0M 0% /run/lock none 248M 0 248M 0% /run/shm /dev/mmcblk0p1 1004K 480K 524K 48% /boot/uboot
今はまだサイズが1.8GBになってますので、fdiskで拡張します
ubuntu@ubuntu-armhf:~$ sudo fdisk /dev/mmcblk0 ommand (m for help): p Disk /dev/mmcblk0: 4023 MB, 4023386112 bytes 4 heads, 16 sectors/track, 122784 cylinders, total 7858176 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x80008000 Device Boot Start End Blocks Id System /dev/mmcblk0p1 * 2048 4095 1024 1 FAT12 /dev/mmcblk0p2 4096 3751935 1873920 83 Linux Command (m for help): d Partition number (1-4): 2 Command (m for help): p Disk /dev/mmcblk0: 4023 MB, 4023386112 bytes 4 heads, 16 sectors/track, 122784 cylinders, total 7858176 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x80008000 Device Boot Start End Blocks Id System /dev/mmcblk0p1 * 2048 4095 1024 1 FAT12 Command (m for help): n Partition type: p primary (1 primary, 0 extended, 3 free) e extended Select (default p): p Partition number (1-4, default 2): Using default value 2 First sector (4096-7858175, default 4096): Using default value 4096 Last sector, +sectors or +size{K,M,G} (4096-7858175, default 7858175): Using default value 7858175 Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 16: Device or resource busy. The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) Syncing disks.
ここまで来たら、先のBootボタンを押しながらリブートします
ubuntu@ubuntu-armhf:~$ sudo reboot
起動したら再びsshで接続してログイン後、resizeコマンドを叩きます
ubuntu@ubuntu-armhf:~$ sudo fdisk /dev/mmcblk0 Command (m for help): p Disk /dev/mmcblk0: 4023 MB, 4023386112 bytes 4 heads, 16 sectors/track, 122784 cylinders, total 7858176 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x80008000 Device Boot Start End Blocks Id System /dev/mmcblk0p1 * 2048 4095 1024 1 FAT12 /dev/mmcblk0p2 4096 7858175 3927040 83 Linux Command (m for help): q ubuntu@ubuntu-armhf:~$ sudo resize2fs /dev/mmcblk0p2 resize2fs 1.42 (29-Nov-2011) Filesystem at /dev/mmcblk0p2 is mounted on /; on-line resizing required old_desc_blocks = 1, new_desc_blocks = 1 The filesystem on /dev/mmcblk0p2 is now 981760 blocks long. ubuntu@ubuntu-armhf:~$ df -h Filesystem Size Used Avail Use% Mounted on rootfs 3.7G 246M 3.3G 7% / /dev/root 3.7G 246M 3.3G 7% / devtmpfs 248M 4.0K 248M 1% /dev none 50M 224K 50M 1% /run none 5.0M 0 5.0M 0% /run/lock none 248M 0 248M 0% /run/shm /dev/mmcblk0p1 1004K 480K 524K 48% /boot/uboot ubuntu@ubuntu-armhf:~$
これで領域が3.7GBに拡張されました
ボタンを押さなくてもSDカードブートするように修正
前述のように、きんねこさんがSDカードブートするように解決してくれました。 調査内容はエントリ上部のリンクを参照してください。ここでは修正部分だけ追記します。
nEnv.txtに2行追加します
# cd /boot/uboot # vim nEnv.txt mmcpart=2 bootfile=zImage <---- 追加 optargs=fixrtc uenvcmd=i2c mw 0x24 1 0x3e; kd=0; if test $mmcdev -eq 1; then mmc dev 0; if mmc rescan; then kd=1; fi; mmc dev 1; fi; setenv mmcroot /dev/mmcblk${kd}p${mmcpart} ro loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdtaddr} ${bootdir}/dtbs/${fdtfile} loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${bootdir}/${bootfile} mmcboot=echo Booting from mmc ...; run mmcargs; bootz ${kloadaddr} - ${fdtaddr} <---- 追加
これで保存して、一度シャットダウンして再度電源を入れればSDから自動起動するようになります\(^o^)/
HTML5 Conference 2013でLTしてきました
きっかけ
第0回HTML5エンタメ部の開催に参加した際に、白石さん@Shumpeiに、こんなネタありますが、と話しをしたら「LTに応募してみてください」ということだったので、軽い気持ちで応募したらなぜか当選/(^o^)\してしまった。ため(どうしてこうなった)、Web開発者とデザイナーのためのイベントと銘打った「HTML5 Conference 2013」という完全アウェイの中、5分間のLTをしてきました。
反応
司会のあんどうさん@technohippy曰く「僕には全然わかりませんでした」と言わしめるほどの撃沈っぷりを発揮し、見事アウェイの洗礼を受けるという...まぁLTなんてのは貰った時間分は宣伝だと思って、スーパージョッキーの「熱湯風呂」みたいなもんだと思ってるので、また次回ガンバローと思うわけですが(^^;
スライドの中に出てくるpush型ナビは時間の関係で動画が見せられませんでしたが、こちらにも置いておきます。(スライド内のリンク先にはWeb記事として記載されています)
車載Raspberry PiでNode.js + Socket.IO「push型カーナビゲ ...
言いたかったこと
さすがに5分でやるのは厳しかったなーと思いつつ補足します。HTML5によってWebと組込みがより近くなるような時代が来ています。ハードウェアというと凄く難しくて、Web開発者からすると手を付けられる領域では無いと思いがちですが、Arduinoなどに代表される最近のマイコンは組込みっぽくなく、C言語の知識さえあればそれほど慣れるのに時間は掛かりません。ましてや今後はJavaScriptで制御できるハードウェアや、Node.js, WebSocketなどがすでに実装されたデバイスが出てくるようです。そうなると、Web開発者でも¥5,000〜¥10,000くらいでオレオレガジェットが作れます。特に、今後出てくるのはネットワーク接続が前提のものが多く、クラウドなどのサーバと組み合わせて、面白いことがどんどんできるようになるんじゃないかと思います。来年は何か作りたいなぁ
とりあえず、個人的にはマスになりそうな技術の中の、ニッチな部分を探してなんかやる。くらいのことしかできない、端っこエンジニアなので、しばらくこのスタンスは変わらないかも
さいごに
セッションはWebプロトコルやネットワーク技術を聞いていましたが、現在の所属先がISPなので、ネットワークインフラ技術などは勉強になりました。また、インフラ側からするとHTML5に移行することにより弊害がすでに予想されており「今までのようにインフラとアプリが別々に考えるのではなく、もっとお互いの領域を理解しながらHTML5をどのように活かしていくか考えなければならない」という投げかけは根本的なところを突いていたように思います。
資料等纏められていました。
HTML5 Conferenceスタッフのみなさん、お疲れ様でした\(^o^)/
HTML5 Conference 2013 講演資料まとめ #html5j - Time to live forever http://t.co/wyp7DgUPsU
— 星影 (@unsoluble_sugar) 2013, 12月 1
LPCXpressoとLPC800-MAXでマイコンを学ぶ(その9:I2Cでスイッチコントロール(GPIO))
おそらく今回でLPCXpressoは最後になりますが、I2Cを使ってみます。LPC812は少ピンなのでGPIOが少ないのですが、Arduinoと同じようにGPIOやADCを載せるために、I2Cバスにデバイスを接続して拡張しています。
I2Cのサンプルプログラムを動かす
まずはサンプルプログラムを動かしてみます。サンプルは例のごとく、import project(s)からNXP_LPC8xx_SampleCodeBundle.zipを選択して「I2C」をインポートします。メインはi2ctest.cです。しかしこのサンプルコードは、このLPC800-MAXでは動かないのでLPC800-MAXのGPIO制御用のI2Cのコードを作成しました。
このコードをi2ctest.cを削除して使用します。このコードを動かすと、SW2のスイッチを押すと赤色のLEDが光るようになっています。 LEDを光らせているのは、最初の方にやったGPIO制御ですが、SW2のスイッチ制御にI2Cを使用しています。
LPC800-MAXのI2C
I2Cデバイス
LPC800-MAXでは2つのデバイスがI2Cバスに接続されています
- PCA9672PW : GPIOエキスパンダ
- PCF8591T : ADC / DAC
今回はこのうちのGPIOエキスパンダを使用しています。PCA9672PWの資料はこちらにあります。
I2Cアドレス
GPIOエキスパンダのI2Cアドレスを調べてみます。回路図に書いてあります。
I2C Addrs = 0b01000(A1)(A0); Default Addrs = 0b0100011
ということなので、0x23になります。I2Cバスは7bitアドレスを採用していて、下位1bitでRead/Write制御するようになっています。そのためこの場合は左へ1bitシフトし、b01000110/Write, b01000111/Readとなり、それぞれ0x46/Write, 0x47/Readとなります。GPIOへのアクセスは8bitでRead/Writeする形になります(AND書込みなので、どこかのポートだけ制御したい場合は、読み込んでからORして書込む必要あり)
また回路図を見るとP0-P7がGPIOになっており、P7がSW2に接続されていることがわかります。IOEXPAN4, IOEXPAN5はArduinoのDigitalピンとして出ています。
なお、基板上では「XP_4」「XP_5」となっていますが、シルクが間違っていますので注意して下さい。
サンプルプログラムの動作
サンプルのプログラムではI2Cの初期化を行い、GPIOエキスパンダのIOEXPANを操作します。動作確認はテスタなどで当たってもらえばわかります。その後、P7のスイッチを監視するようにしていて、スイッチが押されるとLEDを点灯する。というプログラムです。
I2Cのピンアサインの設定
コードの最初のところでI2Cへのピンアサインを行っています。この辺は以前にも出てきたピンマルチの設定です。
- SDA : PIO0_10
- SLA : PIO0_11
/* * Initialize I2C pin connect */ /*connect the I2C SCL and SDA sigals to port pins(P0.10-P0.11)*/ regVal = LPC_SWM->PINASSIGN7 & ~(0xFFUL<<24); LPC_SWM->PINASSIGN7 = regVal | (10 << 24); /* P0.10 is I2C SDA, ASSIGN0(31:24) */ regVal = LPC_SWM->PINASSIGN8 & ~(0xFF<<0); LPC_SWM->PINASSIGN8 = regVal | (11 << 0); /* P0.11 is I2C SCL. ASSIGN0(7:0) */ regVal = LPC_IOCON->PIO0_10 & ~(0x3<<8); LPC_IOCON->PIO0_10 = regVal | (0x2<<8); /* Enable Fast Mode Plus */ regVal = LPC_IOCON->PIO0_11 & ~(0x3<<8); LPC_IOCON->PIO0_11 = regVal | (0x2<<8); /* Enable Fast Mode Plus */ /* Enable I2C clock */ LPC_SYSCON->SYSAHBCLKCTRL |= (1<<5); /* Toggle peripheral reset control to I2C, a "1" bring it out of reset. */ LPC_SYSCON->PRESETCTRL &= ~(0x1<<6); LPC_SYSCON->PRESETCTRL |= (0x1<<6);
後半の部分はI2Cブロックへのクロックの供給とリスタートです。
I2Cの初期化
/* For master mode plus, if desired I2C clock is 1MHz (SCL high time + SCL low time). If CCLK is 36MHz, MasterSclLow and MasterSclHigh are 0s, SCL high time = (ClkDiv+1) * (MstSclHigh + 2 ) SCL low time = (ClkDiv+1) * (MstSclLow + 2 ) Pre-divider should be 36000000/(1000000*4)-1 = 9-1 = 8. If fast mode, e.g. communicating with a temp sensor, Max I2C clock is set to 400KHz. Pre-divider should be 36000000/(400000*4)-1 = 22.5-1 = 22. If standard mode, e.g. communicating with a temp sensor, Max I2C clock is set to 100KHz. Pre-divider should be 36000000/(100000*4)-1 = 90-1 = 89. */ I2C_MstInit(LPC_I2C, I2C_FMODE_PRE_DIV, CFG_MSTENA, 0x00);
今回はLPC812はI2Cマスターとして動作するので、その初期化を行います。I2Cバスプロトコルには3種類あります。今回アサインされているPIO0_10, PIO0_11は全てのモードをサポートしています。この設定ではFast-modeでの動作設定を行っています。またマスターモードをイネーブルにセットしています。
- Standard-mode :
- Fast-mode :
- Fast-mode Plus :
その後にI2Cがアイドルかどうかチェックしている箇所があったり、バッファを用意しています。
GPIOの初期化(LEDの初期化)
最初の頃にやったGPIOの設定です。ここでは赤色LEDを使うために初期化しています。
/* GPIO初期化 */ GPIOInit(); GPIOSetDir( 0, 7, 1 ); // RED GPIOSetBitValue( 0, 7, 1 ); // RED OFF
GPIOエキスパンダの操作
GPIOエキスパンダに一度0を書き込んでから、B0を書き込んで確認しています。0x46/Write, 0x47/Readです。
/* Clear GPIO = 0 / GPIO = 0xB0 */ uint8_t data; I2CMasterTXBuffer[0] = 0x00; I2C_MstSend( LPC_I2C, 0x46, (uint8_t *)I2CMasterTXBuffer, 1 ); I2C_MstReceive( LPC_I2C, 0x47, &data, 1 ); printf("GPIO: %x\n", data); I2CMasterTXBuffer[0] = 0xB0; I2C_MstSend( LPC_I2C, 0x46, (uint8_t *)I2CMasterTXBuffer, 1 ); I2C_MstReceive( LPC_I2C, 0x47, &data, 1 ); printf("GPIO: %x\n", data);
0xB0を書き込んでいる理由は、b10110000で、P7 = HIGH, P5 = HIGH, P4 = HIGHに設定するためです。これでArduino端子のDigital 5, 6がHIGHになります。 またP7をHIGHにすることで、SW2の押下でP7がGND(=0)になるのを検知できるようになります。
スイッチの取得
永久ループ内でレジスタを読みだしています。0x80と比較して、つまりb1000000と比較して1(=HIGH)なら、押されていないのでLEDを消灯、0(=GND,LOW)ならスイッチが押されているのでLEDを点灯するようにしています。
while (1) { I2C_MstReceive( LPC_I2C, 0x47, &data, 1 ); if ( data &= 0x80 ) { GPIOSetBitValue( 0, 7, 1 ); // RED OFF } else { GPIOSetBitValue( 0, 7, 0 ); // RED ON } }
まとめ
とりあえずLPC800-MAXを使ったLPCXpressoでの組み込みマイコンはこれくらいになります。Arduinoでもマイコンでもだいたい
- GPIO
- UART
- I2C
がだいたいできれば、あとはなんとかなるんじゃないかと思います。LPC812単体の価格ですが@200以下で買えます。ArduinoはUnoで@3000くらいしますので、一桁価格が違うことになります。もちろん、LPC812単体ではダメで、周辺回路やデバッグ回路を作成することになりますので、LPC812の場合は100台以上の量産向けという選択になります。
こんな感じになるでしょうか。ある程度の量産を視野にいれる場合、このようなマイコンへの習熟やコスト感が後々重要になってきます。
# 僕自身は回路屋さんじゃないので実際の量産基板設計とかはできないのですが、回路図を読むことはできるので、ソフトウェア開発を行うためのハードの要件を回路屋さんと詰めることができます。ユーザーズマニュアルを読めることと、回路図を読めることで、ソフトウェア開発者としての幅が広がります。まぁ需要があるかどうかは置いておきますが(^_^;)
LPCXpressoとLPC800-MAXでマイコンを学ぶ(その8:UARTでPCと接続)
今回もサンプルを使ってUARTの動作を確認していきます。
UARTのサンプルプログラムを動かす
まずはサンプルプログラムを動かしてみます。サンプルは例のごとく、import project(s)からNXP_LPC8xx_SampleCodeBundle.zipを選択して「UART」をインポートします。メインはuarttest.cです。このサンプルプログラムはUARTでPCのターミナルソフトなどと接続して、PCのからの入力をループバックでエコーを返すプログラムです。それにはPCとLPC800-MAXを接続する必要があるので接続図を示します。
LPC800-MAXの0pinをシリアルアダプタのTX, 1pinをRX, GNDを接続します。注意としてはLPC800-MAXは3.3v駆動なので、USBシリアルアダプタを使う場合、3.3v対応のものを使うことです。PCのターミナルソフトではボーレートを9600に設定しておきます。あとはお決まりの、データビット8,、ストップビット1、 パリティ無し、フローコントール無しです。この状態でdebugビルドで動かしてみます(redlib(semihost)に変更しないとエラーになるので注意)
緑のLEDが点灯します(これはおまけに記述)。一方PCのターミナルには"Hello World!"が表示されます。ターミナルの方に文字を入力するとエコーバックされて文字が表示されます。
UARTの動作を見る
UARTのピンアサインの設定
コードは#ifでいくつかのブロックになっていますが、これはRXとTXのUARTブロックとピンアサインの話なので#if 1のとこだけ見ます。
/* connect the UART0 TXD abd RXD sigals to port pins(P0.4-P0.0)*/ regVal = LPC_SWM->PINASSIGN0 & ~( 0xFF << 0 ); LPC_SWM->PINASSIGN0 = regVal | ( 4 << 0 ); /* P0.4 is UART0 TXD, ASSIGN0(7:0) */ regVal = LPC_SWM->PINASSIGN0 & ~( 0xFF << 8 ); LPC_SWM->PINASSIGN0 = regVal | ( 0 << 8 ); /* P0.0 is UART0 RXD. ASSIGN0(15:8) */ regVal = LPC_SWM->PINASSIGN0 & ~( 0xFF << 16 ); LPC_SWM->PINASSIGN0 = regVal | ( 12 << 16 ); /* P0.12 is UART0 RTS, ASSIGN0(23:16) */ regVal = LPC_SWM->PINASSIGN0 & ~( 0xFFUL << 24 ); LPC_SWM->PINASSIGN0 = regVal | ( 13 << 24 ); /* P0.13 is UART0 CTS. ASSIGN0(31:24) */
この部分はUARTのRX, TX, RTS, CTSのピンアサインを行っています。
LPC800-MAXの回路図で見ると、TX, RXはそれぞれDigitalピンとしての1pin, 0pinに割りあたっています。ちょうどこのピン配置はArduinoと同じ配置にしてあります(当たり前だけど)
ここではPIOにUARTの端子を割り付けるという、いわゆるピンマルチの設定を行っています。LPC800シリーズでは機能の割にピン数が少ないため、デフォルト状態ではすべてGPIOに設定されていますが、これを内部のピンマルチ機能を使って、使いたい機能ブロックのピンをGPIOに割りつけるようになっています。通常ピンマルチは制約が多いのですが、LPC800シリーズではかなり自由に割り付けられるようになっていて、Switch Matrix機能と呼ばれています。詳しいことはLPC800シリーズ - 少ピンパッケージ、スイッチ・マトリックス内蔵 Cortex-M0+に書いてあります。設定を見てみます。ユーザーズマニュアルp122-p124にSwitch Matrixのレジスタ設定があります
Pin assigne register 0を見ると、該当するビット範囲(ワード設定)にPIOの番号を書き込むことでアサインされるようです。TXDをPIO0_4にアサインするには4を[7:0]で書き込みます。その他のピンアサインも同様に行っています。
UART通信の初期化
初期化でUARTのピンアサインを行ったので、UARTの初期化を行います。
UARTInit(LPC_USART0, 9600);
UARTInit関数です。UARTのコードもARMが提供しているところなので詳細は省きます。まぁ普通に使う分にはそのままでいいんじゃないかと。(厳密にはボーレートの生成クロックの選択など、シビアな設定がありますが)lpc8xx_uart.cで提供されている関数で、ボーレートと使うUARTのチャンネルを設定します。USART(非同期および同期が使える)はLPC812では2チャンネル、もしくは3チャンネル用意されています(パッケージで違う)あれれ?フローコントロールとか、パリティの設定が無いなーと思ったら・・・
(lpc8xx_uart.c) void UARTInit(LPC_USART_TypeDef *UARTx, uint32_t baudrate) { uint32_t UARTSysClk; UARTTxEmpty = 1; UARTClock_Init( UARTx ); UARTSysClk = SystemCoreClock/LPC_SYSCON->UARTCLKDIV; UARTx->CFG = DATA_LENG_8|PARITY_NONE|STOP_BIT_1; /* 8 bits, no Parity, 1 Stop bit */ // UARTx->CFG = DATA_LENG_7|PARITY_NONE|STOP_BIT_1; /* 7 bits, no Parity, 1 Stop bit */ // UARTx->CFG = DATA_LENG_8|PARITY_NONE|STOP_BIT_2; /* 8 bits, no Parity, 2 Stop bit */ // UARTx->CFG = DATA_LENG_8|PARITY_EVEN|STOP_BIT_1; /* 8 bits, even Parity, 1 Stop bit */ // UARTx->CFG = DATA_LENG_8|PARITY_ODD|STOP_BIT_1; /* 8 bits, odd Parity, 1 Stop bit */
コメントアウトされてる...orz UARTも詳細を自分で設定する場合は、このドライバ書き直す必要がありますね...(;´Д`)
受信・送信処理
実際の受信・送信処理は下記の部分です。UARTSend関数で"Hello World!"をUARTで送信して、永久ループで受信待ちになっています。送信はUARTのチャンネルと、送信データ、サイズです。
UARTSend(LPC_USART0, (uint8_t *)"Hello World!\r\n", 14); for ( i = 0; i < 0x10000; i++ ); while ( 1 ) { if ( UARTRxCount && !RxErrorCount ) { LPC_USART0->INTENCLR = RXRDY; /* Disable RXRDY */ UARTSend( LPC_USART0, (uint8_t *)UARTRxBuffer, UARTRxCount ); UARTRxCount = 0; LPC_USART0->INTENSET = RXRDY; /* Re-enable RXRDY */ } } }
受信ですが、これも実装が微妙な気がしますが(゜.゜)・・・UARTRxCountは受信データ数なので、受信データがあって、かつエラービットが立ってない場合処理を行います。
- 受信割り込みクリア
- 受信バッファの内容を、そのまま送信
- 受信データサイズクリア
- 受信割り込み有効
という流れになっています。これで、受信した(PCからの入力)データがエコーバックされる動作となっています。しかし、この実装はドライバで使う変数をここで処理するのはあまり良くないですね...(;´Д`) なんかサンプルコードがこんなのばっかなんだけどいいのかな。
おまけ。なぜLEDが点灯するのか?
さて、UARTの動作は理解できたかと思います。ひとつあれ?っと思う部分があったので補足します。LPC800-MAXでこのサンプルプログラムを走らせると、LEDが緑に点灯するんですね。GPIOの設定した覚えないのに...というわけで、そこを調べてみます。実はBlinkyの時からあった、この最初のデバッグに使うよ。という部分が答えでした。
/* Config CLKOUT, mostly used for debugging. */ regVal = LPC_SWM->PINASSIGN8; regVal &= ~( 0xFF << 16 ); regVal |= ( 17 << 16 ); LPC_SWM->PINASSIGN8 = regVal; /* P0.17 is CLKOUT, ASSIGN(23:16). */ CLKOUT_Setup( CLKOUTCLK_SRC_MAIN_CLK );
何をやってるのか調べてみると、CLCKOUTを特定のピンに外部出力していました。このプログラムの場合、PIO0_17にCLCKOUT、おそらく12MHzを出力しています。LPCXpressoとLPC800-MAXでマイコンを学ぶ(その3:LEDの動作(GPIO)を調べる)でやりましたが、LPC800-MAXのボードはPIO0_17は緑のLEDに接続していました。ここにCLCKOUTが出力されたことでPWMとして機能するため、緑色に点灯するというわけです。具体的にやっていることは
- Switch MatrixのレジスタでCLCKOUTピンをPIO0_17に設定
- CLCKOUTをメインクロックの12MHzに設定
CLKOUTは右真ん中あたりにあります。CLKOUT_Setup関数では、CLKOUTのソースクロックを設定します。関数内ではソースクロックの選択と、CLKOUTのためにCLKOUTDIVで分周しています。ただし、ちょっと不思議なのはCLKOUTDIVは初期設定が0なのでDisableのはずなのにLEDが点灯しているんですよね。はて
その後にCLKOUTDIV = 1を書き込むことで、12MHzが出力されるということのはずなのですが、オシロスコープがあればこの辺確かめられるはずだけど持ってない...orz