/home/tnishinaga/TechMEMO

日々行ったこと、面白かったことを書き留めます。

WindowsでARMCCを用いてmbedライブラリをビルドする

LPC812をmbedライブラリを用いて開発したかったので、mbedライブラリのビルド方法を調べました。

事前準備

  • Python2.xのインストールとパスの設定
  • Keil MDK-ARM v5のインストール

インストール方法

基本は高橋さんの記事のとおりですが、少々変更点があります。

mbedのビルドをOS X上で行う - Qiita

Windows上でARMCCを用いてビルドするに必要なこと

LPC812のビルドはARMCC(Keil MDK-ARMに入ってるコンパイラ)以外ではできません。 よって高橋さんの記事を参考に、以下のビルドコマンドでビルドを行います。

$ python workspace_tools\build.py -m LPC812 -t uARM

しかし、以下のエラーが出てビルドができません。

[WARNING] Using default settings. Define your settings in the file "workspace_tools/private_settings.py" or in "./mbed_settings.py"
Building library CMSIS (LPC812, uARM)
[Error 2] 指定されたファイルが見つかりません。

Completed in: (0.01)s

  Build failures:
  * uARM::LPC812

-vオプションを付けて問題の詳細を確認し、printデバッグで調べたところ、どうやらコンパイラの場所指定がおかしいことがわかりました。 もう少し調べてみると、mbedライブラリではMDK-ARM v4を前提としており、加えてデフォルトではMDK-ARMではなく、スタンドアローンなARMCCを用いるようになっていました。

当該ファイルは workspace_tools\settings.py です。 これをMDK-ARM v5を用いるよう、以下のように書き換えます。

diff --git a/workspace_tools/settings.py b/workspace_tools/settings.py
index 3444f86..23090c1 100644
--- a/workspace_tools/settings.py
+++ b/workspace_tools/settings.py
@@ -30,13 +30,14 @@ ROOT = abspath(join(dirname(__file__), ".."))
 BUILD_DIR = abspath(join(ROOT, "build"))
 
 # ARM
-armcc = "standalone" # "keil", or "standalone", or "ds-5"
+armcc = "keil" # "keil", or "standalone", or "ds-5"
 
 if armcc == "keil":
-    ARM_PATH = "C:/Keil_4_54/ARM"
-    ARM_BIN = join(ARM_PATH, "BIN40")
-    ARM_INC = join(ARM_PATH, "RV31", "INC")
-    ARM_LIB = join(ARM_PATH, "RV31", "LIB")
+    #ARM_PATH = "C:/Keil_4_54/ARM"
+    ARM_PATH = "C:/Keil_v5/ARM"
+    ARM_BIN = join(ARM_PATH, "ARMCC", "bin")
+    ARM_INC = join(ARM_PATH, "ARMCC", "include")
+    ARM_LIB = join(ARM_PATH, "ARMCC", "lib")
 
 elif armcc == "standalone":
     ARM_PATH = "C:/Program Files/ARM/armcc_4.1_791"

あとは再度、以下のコマンドを実行すればビルドが完了します。

$ python workspace_tools\build.py -m LPC812 -t uARM

mbed LPC1768でWatchDogTimerを扱う

mbed LPC1768でWDTを使う方法を調べたので、備忘録として記す。

リファレンス

WDTとは

Watch Dog Timer、直訳で番犬タイマー。 マイコンの暴走や無限ループに陥った際、強制的にリセットをかける機構。

WDTはカウントダウンタイマーである。値がセットされるとカウントダウンを開始し、0になるとマイコンをリセットさせる。 この機能を活かして、マイコンの動作を監視する。

以下、監視の手順を簡単に説明する。 監視対象のプログラムに、一定時間以内にWDTのカウンタを再セット(タップ)する処理を入れる。すると、正常に動作している間はWDTが0になる前にタップが行われるため、WDTによるリセットはかからない。 しかし、マイコンの暴走や無限ループなどの理由によりWDTへのタップが行われなくなった場合、WDTのカウンタが0となり、強制リセットが行われる。

register description

以下、LPC1768のWDTに関するレジスタとその説明を記す。

Name Description
WDMOD WDTのモード設定とステータス確認用レジスタ
WDTC タイムアウト値設定レジスタ
WDFEED 0xAAの後に0x55を書き込むと、WDTCにセットした値がWDTのカウンタにセットされる
WDTV 現在のWDTカウンタ値を確認するレジスタ
WDCLKSEL WDTのクロックソースを選択するレジスタ

WDMOD

Bit Symbol Description
0 WDEN WDTを有効化する。1の場合はWDT実行中。
1 WDRESET WDTによる強制リセットを有効化する。1にすると有効となる
2 WDTOF WDTのタイムアウトフラグ。WDTによるリセットが行われると1になる。自動でクリアされないので、ソフトウェアでクリアする
3 WDINT WDT割り込みフラグ。読み込み専用
31:4 - 予約

WDENとWDRESETは一度設定すると、その後ソフトウェアからは無効化できない。

WDTは独立して動作する。そのため、デバッグ等で動作を止める場合、WDEN,WDRESETがともに1となっているとWDTによるリセットがかかり、デバッグができない。

WDTC

WDTのカウンタ値をセットする。 初期値は0xFFとなっている。

最小値はT_WDCLK * 256 * 4 (T_WDCLK = 1 / WDTクロックソースの周波数 ) 最大値は書かれていないため 0xffffffff と予想する。

WDFEED

ここに0xAA,0x55が書き込まれると、WDTCにセットされた値がカウンタにリロードされる。 つまり、WDTのタップ操作になる。

WDTV

現在のWDTカウンタの値を表示する。 ただしカウンタとの同期に6 WDCLKサイクル、加えて6 PCLKサイクルかかるため、実際のクロックの値に比べてWDTVの値は古くなる。

Name Description
WDCLK WDTのクロックソースから供給されるクロック
PCLK ペリフェラルクロック

WDCLKSEL

Bit Symbol Description
0:1 WDSEL クロックソースを設定する。詳細は後述
30:2 - 予約
31 WDLOCK 1を書き込むとWDTのクロックソースをロックできる。一度ロックされると、リセットがかかるまでクロックソースが変更不可となる。

WDSELは0x00~0x10をセットすることでクロックソースを設定できる。

Value Description
0x00 内蔵RCオシレータ
0x01 ペリフェラルクロック
0x02 RTCオシレーター
0x03 予約

プログラム例

mbed LPC1768でWatchDogTimerの動作を確認するコード

Macでmbedをデバッグする方法についてのまとめ

mbed Advent Calendar 2014の11日目です。

まえおき

mbedとの関わり

f:id:tnishinaga:20141211171140j:plain

現在私はmbedのプログラムを アセンブリ言語でコードをゴリゴリ実装して、バグを作っては治すを繰り返す日々をおくっています。

デバッガは必須

アセンブリ言語はCに比べて低級な言語なので、コーディング中に混乱して、バグを作ることが多いです(主観的発言)。 よくあるバグとしては、メモリ破壊、スタック破壊、リターンアドレスのpop忘れ、etc……。 簡単なデバッグ方法としてはprintfを用いたデバッグがありますが、今回はアセンブリで実装しているため、printfを挟むのは少々コストが大きいです。

そこで活躍するのがデバッガです。 このデバッガがあれば、プログラムを1命令ごと、レジスタの値を監視しながらデバッグすることができます。 これによりprintfでは調査しづらい細かな処理を追うことが可能となり、デバッグの効率を格段に上げることができます。 よって、デバッガは必須なのです。

mbedのデバッグ機構

f:id:tnishinaga:20141211171149j:plain

mbedの一部の製品には、メインのマイコンの他に、mbed interfaceと呼ばれる機能を持ったマイコンがついています。 このmbed interfaceはCMSIS−DAPデバッガとしての機能を持っているため、このmbed interfaceを持った一部の製品は、それ単体でデバッグを行うことができます。

f:id:tnishinaga:20141211172046p:plain

※ CMSIS-DAPの説明は特殊電子回路株式会社さまの「CMSIS-DAPって何?」を参照してください。

Macでmbedデバッグ

前置きが長くなりましたが、本題です。 Macでmbedのデバッグを行いましょう。

プログラムのエクスポート

mbedはプログラムをオンラインでコンパイルするという、画期的なシステムを採用しています。 しかし、このオンラインのシステムはコンパイルは出来ますが、デバッグを行うことができません。 デバッグのためにはオンラインのコードをローカルに保存し、オフラインコンパイル環境を用いる必要があります。 この方法については以下のページを参照し、「Exporting to GCC ARM Embedded」でGCC用のコードをエクスポートしてください。

デバッグ環境の整備

私は普段はMac OS Xを用いています。Windows機も所持していますが、もっぱらゲーム専用機としてしか使っていません。

残念なことに、ARM社謹製の統合開発環境 MDK-ARMは、現状Windows専用ソフトウェアです。 そのためMac環境ではライセンス料が云々の前に、使うこと自体ができません。 それでもなんとかMacで開発を行うため、GNUのフリーな環境を用いて開発環境・デバッグ環境を整えます。 その方法は以前ブログ記事にまとめたので、こちらを参照してください。

Tips: GNU開発環境でのアセンブリ利用時の注意

GNUな開発環境とMDK-ARMでは、アセンブリコードの書き方が異なるため、アセンブリコードの互換性がありません。 そのため、アセンブリで開発する際は、デバッガの使えないオンライン上で完結させるか、WindowsでMDK-ARMを用いて開発を行うか、もしくはオンラインへ戻ることを諦めてGNUな書き方を行うかを判断する必要があります。

私は青mbedのプログラムフラッシュが豊富であり、MDK-ARMを用いずともメモリが足りているので、GNUツールで開発することにしました。 オンラインへの復帰は、開発が完了した後に手動でアセンブリコードを書きなおして行う予定です。

GDBの操作方法(簡易説明)

GDBを用いてデバッグする方法を、簡単に説明します。

GDBサーバーへの接続

(gdb) target remote localhost:3333

プログラムのmake

(gdb) make

プログラムのロード

(gdb) load

なお、以前ロードしたプログラムと新しくロードするプログラムに差異がある場合は、後述のdisplayの設定が削除されます。 breakpointの設定は残ります。

状態の表示

displayコマンドを用いると、レジスタやメモリの値を逐次表示することができます。 自分のおすすめは以下。

(gdb) display/i $pc
(gdb) display/x $r0
(gdb) display/x $r1
(gdb) display/x $r2
(gdb) display/x $r3
(gdb) display/x $r4
(gdb) display/x $r5
(gdb) display/x $r6
(gdb) display/x $r7
(gdb) display/x $r8
(gdb) display/x $r9
(gdb) display/x $r10

これでプログラムカウンタの指すアセンブリコードを表示しつつ、レジスタr0~r10までの値を16進数で確認できます。

再実行

(gdb) continue

プログラムカウンタの指す場所から処理を再開します。 後述のbreakpointに引っかかるまで止まらないので注意してください。 強制的に止めたい場合はCtrl+Cを入力します。

breakpoint

(gdb) breakpoint *0x0000a410

特定のアドレスにbreakpointを仕込んで、その位置で処理を止めることができます。 上記のコマンドでは、プログラムカウンタがメモリアドレス0x0000a410になった時、処理を止めることができます。

なお、本来condition等を用いれば変数の値が変化した際に止める……ということができますが、pyOCDの環境で使ったらpyOCDがハングしました。 再現性の確認等ができていないので、バグ報告は行えていません。

1命令実行

(gdb) stepi
(gdb) nexti

アセンブリでは1命令ごと実行する必要があるため、 C言語のstep命令はstepi、next命令はnextiとなります。

おわりに

以上、Macでmbedをデバッグする方法についての簡易デバッグ説明でした。 デバッグ時にgdbサーバーを建てるため使用したpyOCDをもう少し活用すると、より柔軟なデバッグも可能ですが……今回はここまで。 要望があれば、PyOCDを使ってHard Fault原因を探る方法を、再度advendカレンダーに書こうかとおもいます。

緩募

  • ARMマイコン発売から現在までのシェア情報の書かれた資料
  • mbed発売から現在までのシェア情報の書かれた資料

次の人

次はjksoftさんです。よろしくおねがいします。

MacにPyOCDをインストールする方法について

先日mbed用のコンパイル環境を作る方法を解説した際、PyOCDのインストール方法については省略した。

その理由はPyOCDがLinuxWindowsにしか対応しておらず、Linux上でのインストールは特に問題なく行えたからだ。 しかし調べてみると、最近はPyOCDがMacでも動くようになっていた。

そこで早速Mac環境にインストールを試みたが、本家の説明だけではうまくいかなかったので、正しいインストール手順を備忘録として記す。

pipのインストール

PyOCDはpython2動作するので、python2の環境を揃える必要がある。 この環境を整えるため、まずはpipをインストールする。

$ sudo easy_install-2.7 pip

Cythonのインストール

PyOCDをMacで使用するために必要な cython-hidapi は、Cythonに依存しています。 そのため先にCythonをインストールする必要があります。

$ sudo pip install Cython

cython-hidapiのインストール

残りは一見、PyOCDのREADME通りのようにみえる。 しかしcython-hidapiのインストールスクリプトには setup-mac.py を選択する必要があるという罠がある。

$ brew install hidapi
$ git clone https://github.com/gbishop/cython-hidapi.git
$ cd cython-hidapi
$ sudo python2.7 setup-mac.py install

PyOCDのインストール

やるだけ

$ git clone https://github.com/mbedmicro/pyOCD
$ cd pyOCD/
$ sudo python setup.py install

TODO

公式リポジトリのREADMEにプルリクエストを投げる。

mbedのC++コードからCやアセンブラの関数を呼び出す

GCCを用いてC++のファイルからCやアセンブラで定義した関数が呼び出せない問題に引っかかったので、解決方法を記す。

解決方法

ヘッダなどでの関数定義に、以下のように "C" を入れるだけ。

extern "C" void hoge(void);

これだけでCやアセンブラの関数を呼び出すことができるようになる。

進捗

この問題の解決に3日かかりました。

Mac上にAVRマイコンの開発&書き込み環境を作った

AVRマイコンとはお手軽マイコン開発ツールArduinoに使われているマイコンである。

今回はATMEGA2560を用いる必要があったので、マイコン基板にはArduino MEGA2560を用いた。 書き込み器はAVRISP mk2を購入した。

開発環境の構築

基本的には、橋本商会さんの以下のページを参考に進める。

1つ異なる点として、書き込み用プログラムであるavrdudeのインストールにbrewを用いた。

$ brew install --with-libhid avrdude

AVRISP mk2とArduino MEGA 2560をつなぐ

まずArduino自体に電源を供給するため、ArduinoをUSBケーブルで接続する。

次に写真のように、ArduinoのICSPシルク側にmk2から出ているケーブルの出っ張りを合わせて差し込み、mk2をパソコンに接続すれば完了。

f:id:tnishinaga:20141028222353j:plain

HEXファイルを書き込む

AVRのコードはコンパイルするとHEXファイルができるので、これを書き込めば良い。

書き込みは以下のコマンドで行う。

$ avrdude -c avrispmkII -p atmega2560 -U flash:w:hoge.hex:i

-cは書き込みデバイス名、-pはターゲットマイコンを指定し、hoge.hexの部分を適宜変更すればいいらしい。

私の環境ではこれで書き込みが完了し、動作確認ができた。

進捗

だめです☆

mbedのオフラインコンパイル環境を作った

mbedとは、お手軽マイコン開発ツール群であるArduinoのARM版のようなものである。 オンラインのIDEを用い、mbedライブラリとユーザーの公開しているライブラリを用いてお手軽に開発を行うことができる。

しかし、デバッグはオンラインでは行えない。 デバッグを行いたい場合は、ソースコードのエクスポートを行い、オフライン環境でコンパイルし、オフラインのデバッガツールを用いて行わねばならない。

オフライン環境としては、MDK ARMというARM社謹製の開発ツールを使うのが一番である。 なぜなら、mbedのライブラリなどはすべてMDK ARMでコンパイルされているからだ。

しかしこのツールは1年で50万のライセンス料が必要で、個人は手の届かないシロモノであった。 しかたがないのでフリーなコンパイル環境(GCC)を用意することにした。

フリーな開発環境のインストール

mbedのオフラインコンパイル環境にはnewlib-nanoという標準Cライブラリが必要である。 そのため得意のcrosstool-ngを使った環境構築ができない。

代わりにこれらの問題を解消したツール群が公開されていたので、作者に感謝しつつ使うことにした。

インストール方法は以下のように、ソースをとってきたあと mac_install を実行し、パスを通すだけ。

$ mkdir -p ~/src && cd ~/src
$ git clone https://github.com/adamgreen/gcc4mbed
$ cd gcc4mbed
$ ./mac_install
$ echo 'export PATH=$PATH:~/src/gcc4mbed/gcc-arm-none-eabi/bin'

デバッグ方法(簡易説明)

PyOCDを用いる。インストール方法は省略。

mbedデバイスをつなげて test/gdb_server.py を起動するとgdbサーバーが立ち上がる。

$ python2.7 gdb_server.py

あとはarm-none-eabi-gdbを立ち上げて、リモート接続してデバッグする。

$ arm-none-eabi-gdb hoge.elf
(gdb) target remote localhost:3333

進捗

だめです。