2013年5月12日日曜日

RaspberryPiのGPIOでLEDを点灯

RaspberryPiのGPIOを扱う練習で、LEDの点灯をしてみます。

1. LEDの接続


GPIOの出力を確認するためのLEDを接続します。SoCのGPIOに直接接続されるので、電流制限抵抗を付けるのを忘れないでください。ローコストのボードとは言え、あっさり壊してしまってはもったいないですからね。だいたい数百オームでOKだと思いますが、気になる場合は使用するLEDのVFを調べて、GPIOのソース電流に収まるよう抵抗値を決める必要があります。今回は根拠ナシですがとりあえず470Ωを選びました。


抵抗を接続する足はLEDのアノード側、カソード側どちらでもOKですが、足の長さがわからなくなるので、LEDの極性を忘れないように気をつけます。(なお画像のようにハンダ付けしなくても、ブレッドボードを使ってもOKです。)


LEDをRaspberryPiに接続します。基板上のGPIOコネクタのうち、GPIOとGNDが隣り合っている13ピン、14ピンを使います。LEDのアノード側を基板内側の13ピン(GPIO) 、カソード側を基板外側の14ピン(GND)に接続します。


私の使用しているRaspberryPiはRev.2.0なので、13ピンはSoCのGPIO27に接続されています。回路図はこちらのWikiにリンクがあります。

2. コマンドで点灯してみる


DebianのRaspberryPi向け改変版のRaspbianでは、ファイル入出力を通してRaspberryPiのGPIOをコントロールすることができます。Raspbianを使うには、ここからRaspbianのイメージをダウンロードし、Win32 Disk ImagerなどでSDカードに焼いてから、RaspberryPiのカードスロットに挿して起動します。

起動したら、まずログイン。HDMIで画面表示してUSBキーボードを使ってもいいですし、LAN接続してSSHを使ってもいいです。 ユーザー名はpi、パスワードはraspberryになっています。

ログインしたら、下記のようにコマンドします。
まずsuでスーパーユーザーに変更。続いて、/sys/class/gpio/ディレクトリの下のexportファイルにピン番号を指定すると、対応するgpioのディレクトリが作成されます。directionファイルで入出力方向を指定した後、valueファイルへの入力でGPIOの出力をON/OFFすることができます。


このように、ファイル入出力で操作できることで、 コマンドだけでなく、およそファイル入出力の機能を持った言語であれば、CでもPythonでも、同様の操作を行うことができます。
次に、C++によるGPIO操作のプログラムを試してみます。

3. プログラムによる点滅


まずはソースファイルを作成しエディタでソースコードを入力。
ARM用のクロスコンパイラでビルドします。ツールチェインのインストールはこちらの記事の「2. ARMコンパイラのインストール」をご参照ください。コンパイルできたら、バイナリをRaspberryPiにロードします。RaspberryPiをホストマシンと同じLANに接続しておけばSSHが利用できるので、SCPでコピーします。
ロードされたバイナリをRaspberryPiで実行します。まずは実行可能なようにパーミッションを変更。続いてスーパーユーザーでバイナリを実行します。
LEDが点滅を始めます。


参考情報
Creating a "Blinking LED" project for Raspberry PI

2013年5月5日日曜日

APC Paper Alternative

This article describes how to make a APC Paper mimic paper-made case for APC 8750 Neo-ITX sized ARM board.

紙製ケースに入った本のようなルックスのクールなミニPC、APC Paperの発売を待っていたのに、"Pre-Order in March"が"Coming soon..."になり、待てども暦はもう皐月、、、そんなあなたへ!

APC 8750を入れる紙箱を作って、気分だけでもPaperを味わっちゃいましょう。

紙箱のレシピは、バチカさんのこちらの記事を参考にさせていただきました。

材料
 ・ ボール紙(2mm厚) 画材店等で売ってます
 ・ 包装紙(外装、内箱、裏表紙用に何種類か)
 ・ 貼り付けボス 4pcs
 ・ ねじ(M3) 4本

道具
 ・ シャーペン
 ・ スティックのり(包装紙を貼る用。ペーパーセメントを使うと紙にシワがよらないのでなお良し)
 ・ ボンド(厚紙貼り合わせ用)

まずは内箱を作ります。
下の写真にある5枚に切った厚紙が内箱の材料です。真ん中の大きいのが底板、上下左右にある4枚が側面に当たる部分です。寸法はそれぞれ
 ・ 底面(1枚) 204x145mm
 ・ 長い側面(2枚) 204x59mm
 ・ 短い側面(2枚) 141x59mm
になっています。


切り出したら、長い側面のうち1枚にI/Oパネル用の穴を開けます。


後で登場しますが、貼り付けボスの高さだけ基板底面が上がります。また、基板を箱の中心に置く場合、パネルの位置は中心にはならないので注意が必要です。なおパネルの寸法はこちら(PDF)で確認できます。


位置を決めたら切り開きます。


実際にパネルをはめてサイズを確認しましょう。小さすぎる場合は調整して、ぴったりはまるようにします。


続いて側面と底面の厚紙を張り合わせます。底面の上に側面の厚紙を載せるようにして、ボンドで張り合わせていきます。


こんな感じになります。短い側面の両端が長い側面にはさまれるように組みます。


次にスティックのりまたはペーパーセメントで包装紙を貼り付けていきます。内箱の高さ+10mmくらいの幅に切って、側面の周囲を巻きつけるように貼っていきます。上下5mmくらいずつ紙が余るので、内側に折り込むように貼り付けます。


I/Oパネル用の窓に穴を開けます。ここも包装紙を周囲5mm程度を折り込めるように残した上で、真ん中を切り落とします。残った部分を、厚紙側に空けた窓の角まで切り込みを入れた上で、折り込んで貼り付けます。


内箱への基板の組付けには、下図のような貼り付けボスを使います。今回使ったのはタカチ電機工業のT-600というもの。M3のねじで基板を固定します。


はじめに基板側に貼り付けボスを固定してから、はくり紙をはがして位置決めすると楽です。


I/Oパネルにあわせて基板の位置決めをしたら、貼り付けボスをしっかり押し付けて固定します。これで内箱はとりあえず完成。


最後にふたになる外側のパーツを組み立てていきます。
まずは厚紙の切り出し。
 ・ 表紙(2枚) 210x148mm
 ・ 背表紙(1枚) 210x61mm
ちなみにこのサイズはA5書籍に合わせているので、APC 8750基板を入れると少し余裕ができます。


外装用の包装紙を貼り付けていきます。前後の表紙と背表紙の厚紙3枚を4mm程度の間隔をあけて並べ、その上下左右に25mm程度の余白を空けたくらいの大きさに包装紙を切ります。包装紙と厚紙をスティックのりまたはペーパーセメントで貼り付け。四隅は厚紙の角から3mm程度空けて斜めに切り落とします。


余白を内側に折り込んで貼り付けます。


内側に別の紙を貼って厚紙部分を隠します。内箱が載るところは省略で。


最後に、内箱と表紙をボンドで張り合わせます。きちんとふたが閉まるように気をつけてください。表紙の折り目の部分で定規などで内紙を押さえながら折り込むと、きれいに折り目が付きます。


完成図。ちょっとした雑貨入れのようなおとなしいルックスで、800MHzのARMコアを潜ませたにくい1台のできあがり。





ちなみにAPC 8750よりもAPC Rockを使った方が、コネクタが低い分、薄くできると思います。

和風版も作成。こちらは文庫本サイズです。


Arduinoが2台収納できます、殿。



APC Forumに投稿されている諸先輩方の作品も秀逸です。併せてご覧ください。
 ・ "The netbook case" by Icesnake
 ・ "My 0$ APC case" by Maxwell

2013年2月25日月曜日

ARM QEMUでU-Bootを動かす

ブートローダの一種であるDas U-Bootは組み込みLinuxのブートにも良く使われていて、BeagleboardをいじっていたときにはAndroidを起動するときにカーネルパラメータを渡すのによくいじっていました。今回はそのU-BoolをQEMUで動かす練習。

まずはU-BootのFTPサーバからダウンロード。続いて解凍してコンフィギュレーションしてビルドする定番の流れです。
本稿執筆時点ではu-boot-2013.01.tar.bz2までリリースされていたんですが、u-boot-2010.12.tar.bz2以降では、ビルドが失敗したり、実行がうまくいかなかったりしたので、やや古いですが上記を選んでいます。コンフィギュレーションターゲットの対応とか、ツールチェインとの相性とかが原因かと思いますが、詳しくは調べてません。


さて、できあがったバイナリを確認。
u-bootがコンパイルされたバイナリで、さらにobjdumpでセクションギャップに0xFFをフィルした上でRAWバイナリにしたのがu-boot.binでしょうか。0xFFフィルは、一つのフェイルセーフですかね。NOPとかの有効な命令だと危なそうですし。0xFFフィルは、実際のFlashメモリ内の各ビットの初期値が1であるため、無用な書き込みを減らして効率化と書き込み回数の温存を図るための「おまじない」らしいです(参考)。コメント欄でのご指摘ありがとうございました。
早速QEMUで実行してみます。
で、U-Bootのコマンド待ちになるわけですね。
printenvで環境変数一覧を表示できます。bootargsはカーネルパラメータですね。コマンド一覧はhelpで表示可能です。

で、このU-Bootのバイナリに、前回作ったinitのバイナリをマージします。そのために、リンカスクリプトを少し細工してビルドし直しておきます。
先頭アドレスの位置が0x10000から0x100000になっています。
これをmkimageコマンドを使ってU-Bootがロード可能なフォーマットに変換します。
で、先ほど作ったU-BootのRAWバイナリと一つのイメージの中にまとめます。

このイメージをQEMUで実行するわけですが、その前にマージしたinitのイメージのブートアドレスを調べておきます。
まず、statでu-boot.binのサイズを調べます。それに65536を足して16進形式で出力しています。これは、QEMUが-kernelパラメータで指定されたイメージを65536、すなわち0x10000だけオフセットした場所に配置するからです。catコマンドでtest.uimgをu-boot.binの直後に配置したので、その先頭は0x10000にu-boot.binのサイズを足したアドレスになるということです。
ではイメージを起動してみます。
起動前に調べた0x253DCの位置にあるはずのinitのイメージを確認してみます。
よさげです。ではブート。
起動しましたー!

参考情報

Using QEMU for Embedded Systems Development, Part 3 - LINUX For You
U-boot for ARM on QEMU - Balau

2013年2月24日日曜日

ARM QEMUでベアメタルコードを動かす

これまで、ARM用QEMUでHello World!したりlinuxカーネルを動かしたりするのをやってみました。そのとき使ったのがqemu-armというツール。Hello World!の話でQEMUをインストールするときに
./configure --target-list=arm-softmmu,arm-linux-user
という風にコンフィギュレーションしたわけですが、arm-linux-userを含めることでビルドされるのが、qemu-armで、ユーザモードのプログラムを動かすツールです。一方のarm-softmmu、これがシステムモードのプログラムを動かすためのツールをビルドするらしいです。そのツールがqemu-system-armです。ユーザモードのプログラムでは、mainのようなエントリポイントからプログラムが始まるわけですが、システムモードではリセットベクタからプログラムの実行がスタートします。この前はlinuxカーネルを動かすのに使いましたが、今回はリセットベクタからスタートする小さなコードを書いてみます。

Hello World!を動かしたときにはarm-none-linux-gnueabi-というツールを使いましたが、今回はベアメタル用のプログラムをコンパイルするため、くarm-none-eabi-を使います。まずはそのインストール。
次にQEMUのCPU種を調べます。ソースのアーカイブを展開したディレクトリの下のhwに移動して、エミュレーションターゲットとして用いるVersatilePBのCPUを特定してみます。
cpu_model = "arm926"だそうです、ARM9っすね。

続いて、ツールチェインの対応を確認。
(`・ω・´) おk。

んで、とりあえずHello World!を出力してみようと思いますが、システムモードで動かすので、printfのようなライブラリ関数を使わずにUARTに直接キャラクタを叩き込むなんてこともできます。

UARTのアドレスは
となっているので、とりあえず0x101f1000に送り込んでみます。

まずはCソースinit.cの作成。
UARTのアドレスにvolatileを指定することで、コンパイラによる最適化を防ぎます。普通、コンパイラは冗長なアクセスは省略するのですが、volatile指定されたアドレスにはそれが適用されません。UARTの場合、キャラクタ数だけ書き込みを行う必要がありますが、普通のメモリアクセスを仮定して最適化するとすれば、最後の一回の書き込み以外は、結局上書きされてしまうものなので、コンパイラは不要なものと判断します。組み込みの世界では、こういうことを気にしなければならないことがしばしばありますね。

で、ユーザプログラムなら何も考えずにmain()を実装すれば自動的にそれをエントリポイントとして実行してくれるわけですが、 リセットベクタから始まるプログラムの場合、最初にどの関数に飛ぶかを指定しなければなりません。より正確に言えば、所望の関数へジャンプするコードを書く必要があるということです。それが、次のアセンブラコード、startup.sです。
私は昔、MIPSのアセンブラを触ったことがあるのですが、MIPSにはJALという命令があって、シンボルへのジャンプに使ったのを思い出しました。Jump And Linkという意味で、現在の実行箇所をリターン先としてスタックに積んだ上で、指定のシンボル(関数)へジャンプするというものです。上記のARMアセンブラコードのBLはおそらくそれに相当するものだと思います。Bというのは分岐の意味のBranchでしょうか。その前のLDRが、sp_topというシンボルで指定するスタックポインタをSPレジスタにロード、後のBはその場でループといったところでしょう。

最後に、これらをまとめるリンカスクリプト、
ENTRY(_Start)でリセットベクタのエントリポイントを指定。startup.sの_Startシンボルを指定しています。0x10000から初めて、.test、.data、.bssセクションを置いて、0x500だけ離して、スタックポインタを指定しています。この0x500は、下に伸びるスタックポインタのためのマージンといえますね。今回は関数を一つジャンプするだけなので、大きなスタックは必要ありません。さて、ビルドします。普段はMakefileで自動化されてて見えませんが、一つ一つコマンドで、コンパイル、リンク、バイナリの変換を行っていきます。
ELFフォーマットで作られた実行バイナリを、ベアメタルで実行できるようにRAWバイナリに変換しています。
では実行。


参考情報

Using QEMU for Embedded Systems Development, Part 2 - LINUX For You
Hello world for bare metal ARM using QEMU - Balau

2013年2月18日月曜日

ARM QEMUでlinuxカーネルを起動

QEMUでARMの話の続き。

linuxを動かしてみたいと思います。


1. linuxカーネルのビルド

kernel.orgからダウンロードしてビルドします。3.xもありますが、今回は2.6を選んでみました。
ここでコンフィギュレーションは次のようにしておきます。 
で、ビルド。
ビルドできたらイメージを確かめてみます。

2. とりあえずQEMUに放り込んでみる

ここでQEMUのビルドのとき、--target-listオプションにarm-softmmuを仕込んでおいた効果が出ます。linuxカーネルを動かすときはqemu-system-armコマンドを使います。
私はx11vncを使っているので、-vnc :0オプションでvncに出力して見ています。linuxデスクトップで試している場合はナシでOKです。それから先にvncのセッションが存在している場合も良くない場合があるので、止めておきます。x11vncなら下記です。

実行してみると、kernel panicで落ちています。
ということで、rootを指定しろ、と言われます。

3. ダミーファイルシステムの作成

ルートファイルシステムに指定するためのダミーを作成します。適当なディレクトリで、下記のようにエディタでcコードを書いてください。

続いてコンパイル。
ここで-staticにしておくのがミソのようです。
cpioコマンドでルートファイルシステムに変換します。

で、これをルートに指定して実行します。-kernelオプションの引数は正しいカーネルの位置を指定してください。

すると、cコードに書いたとおり、Hello World!を出力する様子が確認できると思います。





トラブルシューティング。



◆実行時

oss: Could not initialize DAC
oss: Failed to open `/dev/dsp'
oss: Reason: No such file or directory
oss: Could not initialize DAC
oss: Failed to open `/dev/dsp'
oss: Reason: No such file or directory
audio: Failed to create voice `lm4549.out'

下記を入れてから実行します。

----
Unimplemented flash cmd sequence

これは、 grepしてみるとkernelではなくQEMUのhw/pflash_cfi01.cが出していることがわかります。この辺で調べてみたところ、どうやらQEMUのバージョンが古いのがダメらしい。このブログの前回のQEMUでARMの記事で、当初1.3.1を入れたとか書いてたりしてたんですが、1.4以降を入れる必要があったようです。ここで最新のReleaseをDLしましょう。


参考情報

Using QEMU for Embedded Systems Development, Part 1
Compiling Linux kernel for QEMU ARM emulator 
Architectures/ARM/HowToQemu

2013年2月15日金曜日

APCのuzImageって何だ?

先日、APC8750のイメージを焼く話を書いたんですが、そのときAPCのサイトから落としてきて解凍したzipアーカイブのファームウェアの中に、uzImageっていうファイルがあったんですね。linuxイメージって言ったら、vmlinux、vmlinuz、zImage、uImageとかじゃないですか。大雑把に言うと、実行形式のvmlinuxをzip圧縮してzImageができ、それをU-bootでブートできるように手を加えたのがuImageだと。ググってみると、ざっとそんなことがわかったりしますが。

だから、、uzImageは?なんとなく「zip圧縮されたU-boot用のカーネルイメージ」っていう気がしますが、そもそもuImageも中身のカーネルはzip圧縮されてるし・・・っていう。ね。

なので、ちょっとだけ調べてみます。

ふむ。fileコマンドさんがおっしゃるには、U-boot用のイメージのようですが(信頼できるかわかりませんが)。

別の用途のために数日前にソースビルドしたarm用のlinuxカーネルがあるので、 こちらも同様に見てみると、、

似ている。

とりあえずAPCのuzImageはuImageなんだと思います。

2013年2月13日水曜日

ARM QEMUでHello World!


1. QEMUのインストール


パッケージでもOKですが、ためしにソースビルドしてみます。

2. ARMコンパイラのインストール


Sourcery CodeBenchのARMコンパイラをインストールします。

一応、インストール確認として、

3. ソース作成、コンパイル、実行


テキストエディタでソースコードを作成します。
内容は、
続いてコンパイル。
出力されたバイナリを確認。
test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped

実行。
"Hello World!"が出力されればOKです。



さて、ここからはトラブルシューティング編。上記インストール手順の実施中に直面したエラーたちと、その対策です。

1. configure時


Error: zlib check failed
Make sure to have the zlib libs and headers installed.


→ zlibをインストール

Error: pkg-config binary 'pkg-config' not found

→ pkg-configをインストール

glib-2.12 required to compile QEMU

→ glibのインストール

    さらにglibのconfigure中、、

    configure: error: Package requirements (libffi >= 3.0.0) were not met:

    No package 'libffi' found
   
    Consider adjusting the PKG_CONFIG_PATH environment variable if you
    installed software in a non-standard prefix.
   
    Alternatively, you may set the environment variables LIBFFI_CFLAGS
    and LIBFFI_LIBS to avoid the need to call pkg-config.
    See the pkg-config man page for more details.


    → libffiのインストール

    configure: error:
    *** You must have either have gettext support in your C library, or use the
    *** GNU gettext library. (http://www.gnu.org/software/gettext/gettext.html


    → gettextのインストール

    configure: error: Package requirements (libpcre >= 8.13) were not met:

    No package 'libpcre' found
   
    Consider adjusting the PKG_CONFIG_PATH environment variable if you
    installed software in a non-standard prefix.
   
    Alternatively, you may set the environment variables PCRE_CFLAGS
    and PCRE_LIBS to avoid the need to call pkg-config.
    See the pkg-config man page for more details.

    → libpcreのインストール
        libpcreのconfigure中、、

        ** Cannot --enable-pcregrep-libbz2 because bzlib.h was not found
        → libbz2のインストール

2. make時


(cd /home/hoge/foo/bar/qemu-1.3.1/pixman; autoreconf -v --install)
/bin/sh: 1: autoreconf: not found
make: *** [/home/kim/work/qemu/qemu-1.3.1/pixman/configure] エラー 127

→ autoconfのインストール

configure.ac:75: error: possibly undefined macro: AC_PROG_LIBTOOL
  If this token and others are legitimate, please use m4_pattern_allow.
  See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1
make: *** [/home/hoge/foo/bar/qemu-1.3.1/pixman/configure] エラー 1
make: *** ファイル `/home/hoge/foo/bar/qemu-1.3.1/pixman/configure' を削除します

→ libtoolのインストール



参考情報

Using QEMU for Embedded Systems Development, Part 1
Compiling Linux kernel for QEMU ARM emulator 



追記

2013年2月18日 インストールするQEMUのバージョンを1.3.1から1.4.0に修正。