{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# mbedオフライン開発環境の構築\n", "岡野さんのページを参考にmbedのオフライン開発環境を構築しました。\n", "- https://developer.mbed.org/users/okano/notebook/setup-mbed-cli-on-mac-os-x-JP/\n", "\n", "## 準備\n", "パッケージ管理ソフトHomebrewとXcodeをインストールします。\n", "\n", "App Storeを使ってXcodeをインストールした後、最新に更新してください。\n", "mbed cliではXcode Command line Toolsも必要になりますが、mbed cliがインストールを促してくれます。\n", "\n", "### Homebrewのインストール\n", "以下のコマンドでHomebewがインストールされます。\n", "\n", "```bash\n", "$ ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"\n", "```\n", "\n", "brewコマンドでpythonとnpmをインストールします。\n", "\n", "```bash\n", "$ brew install npm\n", "$ brew install python \n", "```\n", "pythonのインストールで警告がでるので、以下のコマンドを実行します。\n", "```bash\n", "$ brew link --overwrite python\n", "```\n", "\n", "次にgit、Mercurial(hg)とGCCをインストールします。\n", "```bash\n", "$ brew tap PX4/homebrew-px4\n", "$ brew update\n", "$ brew install git hg gcc-arm-none-eabi\n", "```\n", "\n", "## mbedオフライン開発環境mbed cliのインストール\n", "mbed cliはpipコマンドを使ってインストールします。これでmbedオフライン開発環境が整いました。\n", "```bash\n", "$ pip install mbed-cli\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 動作確認\n", "動作確認のために、Lチカのサンプル(blink)を作成します。\n", "\n", "```bash\n", "$ mbed new blink --mbedlib\n", "[mbed] Creating new program \"blink\" (git)\n", "[mbed] Adding library \"mbed\" from \"https://mbed.org/users/mbed_official/code/mbed/builds\" at latest revision in the current branch\n", "[mbed] Updating reference \"mbed\" -> \"https://mbed.org/users/mbed_official/code/mbed/builds/tip\"\n", "[mbed] Couldn't find build tools in your program. Downloading the mbed 2.0 SDK tools...\n", "[mbed] Auto-installing missing Python modules...\n", "```\n", "\n", "main.cppは、以下の様にしました。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing blink/main.cpp\n" ] } ], "source": [ "%%writefile blink/main.cpp\n", "#include \"mbed.h\"\n", " \n", "DigitalOut led1(LED1);\n", " \n", "int main()\n", "{\n", " while (1) {\n", " led1 = !led1;\n", " wait_ms(500);\n", " }\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "blinkには、以下のディレクトリとファイルができています。\n", "mbedディレクトリには、必要なライブラリやインクルードファイルがダウンロードされるので、Githubには含めていません。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "main.cpp mbed\tmbed.bld mbed_settings.py mbed_settings.pyc\r\n" ] } ], "source": [ "!ls blink" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### mbed LPC1768で動かす\n", "手元の初期のmbed LPC1768をMacに接続してみます。\n", "\n", "mbed cliが正しくmbed LPC1768を認識するかdetectコマンドで確認します。\n", "\n", "以下の様に入力すると、LPC1768として認識されていることが分かります。\n", "```bash\n", "$ mbed detect\n", "\n", "[mbed] Detected LPC1768, port /dev/tty.usbmodem1412, mounted /Volumes/MBED\n", "[mbed] Supported toolchains for LPC1768\n", "+---------+-----------+-----------+-----------+-----------+-----------+\n", "| Target | mbed OS 2 | mbed OS 5 | ARM | GCC_ARM | IAR |\n", "+---------+-----------+-----------+-----------+-----------+-----------+\n", "| LPC1768 | Supported | Supported | Supported | Supported | Supported |\n", "+---------+-----------+-----------+-----------+-----------+-----------+\n", "Supported targets: 1\n", "Supported toolchains: 3\n", "```\n", "\n", "それでは、toolchainをGCC_ARM、ターゲットをLPC1768にセットします。\n", "```bash\n", "$ mbed toolchain GCC_ARM\n", "[mbed] GCC_ARM now set as default toolchain in program \"blink\"\n", "$ mbed target LPC1768\n", "[mbed] LPC1768 now set as default target in program \"blink\"\n", "```\n", "\n", "mbed OS5では不要ですが、mbed OS2ではライブラリのアップデート(新規の場合ダウンロード)が必要です。\n", "\n", "mbed 2.0 9bcdf88f62b0のバグでLPC1768のdefault targetが見つかりません。その場合には、以下のコメントに従ってください。\n", "- https://github.com/ARMmbed/mbed-cli/issues/391\n", "\n", "```bash\n", "$ mbed update\n", "```\n", "\n", "準備が整ったのでコンパイルを実行します。\n", "\n", "```bash\n", "$ mbed compile\n", "Building project blink (LPC1768, GCC_ARM)\n", "Scan: .\n", "Scan: mbed\n", "Scan: env\n", "Compile: main.cpp\n", "Link: blink\n", "Elf2Bin: blink\n", "+-----------+-------+-------+------+\n", "| Module | .text | .data | .bss |\n", "+-----------+-------+-------+------+\n", "| Subtotals | 27529 | 2496 | 632 |\n", "+-----------+-------+-------+------+\n", "Allocated Heap: 2048 bytes\n", "Allocated Stack: 3072 bytes\n", "Total Static RAM memory (data + bss): 3128 bytes\n", "Total RAM memory (data + bss + heap + stack): 8248 bytes\n", "Total Flash memory (text + data + misc): 30025 bytes\n", "Image: ./BUILD/LPC1768/GCC_ARM/blink.bin\n", "```\n", "\n", "正常にビルドが完了したので、Imageファイル(blink.bin)をmbedに書き込みmbedのリセットボタンを押します。LEDが1秒間隔で点滅したら成功です。\n", "\n", "```bash\n", "$ cp ./BUILD/LPC1768/GCC_ARM/blink.bin /Volumes/MBED/\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## mbedのデバッグ\n", "オフラインの特徴であるデバッグ機能について、順を追って説明します。\n", "\n", "### mbedのファームウェアの更新\n", "私の使っていた初期のものでpyocdを使うには、ファームウェアの更新が必要でした。\n", "\n", "更新が必要かどうかは、PCにmbedを差してマウントされたディスクにあるMBED.HTMをテキストエディタで開いて確認します。\n", " \n", " ```\n", "\n", "\n", "\n", "\n", "mbed Website Shortcut\n", "\n", "\n", "\n", "```\n", "\n", " firmware=xxxxxの番号が1421212よりも小さい場合には、mbedのファームウェアの更新が必要です。\n", "\n", "以下のサイトから最新ファームウェア(mbedmicrocontroller_21164.if)をダウンロードし、mbedに書き込んでmbedの電源を入れ直してください。\n", "\n", "- https://developer.mbed.org/handbook/Firmware-LPC1768-LPC11U24\n", "\n", "\n", "正常に更新されたら、MBED.HTMのfirmware=141212になっています。\n", "\n", "### デバッグオプションを付けてコンパイル\n", "mbedのデバッグには、compile時にデバッグオプションを付けます。\n", "\n", "mbed OS2の場合には、-o debug-infoを付けます。既にBUILDがある場合には、削除してからmbed compileを実行してください。\n", "```bash\n", "$ mbed compile -o debug-info\n", "```\n", "mbed 5.2以降の場合には、add --profile=debugを付けます\n", "\n", "### pyocdの起動\n", "mbedのデバッグは、pyocdというPythonベースのOn-Chip Debuggerを使って行います。\n", "\n", "ターミナルを開いて、以下のコマンドを入力してください。\n", "pyocd-gdbserverが起動し、デバッグの準備をします。\n", "\n", "```bash\n", "$ pyocd-gdbserver\n", "INFO:root:DAP SWD MODE initialised\n", "INFO:root:ROM table #0 @ 0xe00ff000 cidr=b105100d pidr=0\n", "INFO:root:[0]\n", "WARNING:root:Invalid coresight component, cidr=0x0\n", "INFO:root:[1]\n", "INFO:root:[2]\n", "WARNING:root:Invalid coresight component, cidr=0x0\n", "INFO:root:[3]\n", "WARNING:root:Invalid coresight component, cidr=0x0\n", "INFO:root:[4]\n", "INFO:root:[5]\n", "INFO:root:CPU core is Cortex-M3\n", "INFO:root:6 hardware breakpoints, 4 literal comparators\n", "INFO:root:4 hardware watchpoints\n", "INFO:root:Telnet: server started on port 4444\n", "INFO:root:GDB server started at port:3333\n", "```\n", "OpenOCDと同様pyocdも以下の2つのポートを開いてデバッグコマンドを処理します。\n", "- pyocdを制御するポート: 4444\n", "- GDBサーバのポート: 3333\n", "\n", "### GDBの起動\n", "次にARM用のDGB(arm-none-eabi-gdb)を起動します。\n", "\n", "別のターミナルを開いて、mbedのプロジェクトのあるディレクトリに移動して、以下のコマンドを入力してください。\n", "\n", "\n", "```bash\n", "$ arm-none-eabi-gdb BUILD/LPC1768/GCC_ARM/blink.elf\n", "GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs\n", "Copyright (C) 2015 Free Software Foundation, Inc.\n", "途中省略\n", "Reading symbols from BUILD/LPC1768/GCC_ARM/blink.elf...(no debugging symbols found)...done.\n", "```\n", "\n", "GDBが起動すると(gdb)のプロンプトが表示されますので、ここで以下のコマンドを入力します。\n", "- target remote :3333 : デバッグターゲットをリモートのgdb-serverとし、localhostの3333ポートに接続\n", "- load : プログラムをmbedに書込みます(loadします)\n", "- break main : main関数にブレークポイントをセット\n", "- c : mbedをDGBの元で実行(continueの略)\n", "\n", "```\n", "(gdb) target remote :3333\n", "Remote debugging using :3333\n", "0x0000082c in mbed_error_printf (format=0x0 )\n", " at ../mbed-os/platform/mbed_board.c:72\n", "72 mbed_error_vfprintf(format, arg);\n", "(gdb) load\n", "Loading section .text, size 0x6c3c lma 0x0\n", "Loading section .ARM.exidx, size 0x8 lma 0x6c3c\n", "Loading section .data, size 0x9c0 lma 0x6c44\n", "Start address 0x4c0, load size 30212\n", "Transfer rate: 8 KB/sec, 1777 bytes/write.\n", "(gdb) br main\n", "Breakpoint 1 at 0x6ca: file ./main.cpp, line 8.\n", "(gdb) c\n", "Continuing.\n", "Note: automatically using hardware breakpoints for read-only addresses.\n", "\n", "Breakpoint 1, main () at ./main.cpp:8\n", "8\t led1 = !led1;\n", "(gdb)\n", "```\n", "\n", "以下のGDBコマンドを使ってblinkをデバッグします。\n", "- n(next): ステップオーバ\n", "- s(step): ステップイン\n", "- p(print): プリント\n", "- q(quit): GDBの終了\n", "\n", "nを入力すると、次の行に進みます。\n", "\n", "```\n", "(gdb) n\n", "9\t wait_ms(500);\n", "```\n", "\n", "もう一度cを入力して、8行目で止め、今度はsを入力してみましょう。\n", "DigitalOUt::operator intのreturn read();で止まりました。\n", "led1で値を参照すると、内部ではled1.read()が呼び出されます。\n", "\n", "```\n", "(gdb) c\n", "Continuing.\n", "\n", "Breakpoint 1, main () at ./main.cpp:8\n", "8\t led1 = !led1;\n", "(gdb) s\n", "mbed::DigitalOut::operator int (this=0x10000bac )\n", " at ./mbed/25aea2a3f4e3/DigitalOut.h:117\n", "117\t return read();\n", "```\n", "\n", "upコマンドでmainの呼び出し元に戻り、プリントコマンドで値を見てみましょう。\n", "```\n", "(gdb) up\n", "#1 0x000006d0 in main () at ./main.cpp:8\n", "8\t led1 = !led1;\n", "(gdb) p led1.read()\n", "$1 = 1\n", "```\n", "\n", "このようにデバッガ(GDB)を使って処理の流れを確認したり、値をみることができます。\n", "\n", "デバッガを終了するには、qを入力してください。\n", "本当に終了するか確認してきますので、yを入力するとGDBが終了し、合わせてpyocd-gdbserverも終了します。\n", "\n", "```\n", "(gdb) q\n", "A debugging session is active.\n", "\n", "\tInferior 1 [Remote target] will be detached.\n", "\n", "Quit anyway? (y or n) y\n", "Detaching from program: /Users/take/proj/jupyter/MySageMath/notebook/letsMbed/blink/BUILD/LPC1768/GCC_ARM/blink.elf, Remote target\n", "Ending remote debugging.\n", "```" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Emacsのgdbモードを使う\n", "コマンドベースのGDBでは、ソースのどの部分を実行しているのかが、いまいち掴みづらいので、Emacsのgdbモードを使ってみましょう。\n", "\n", "通常だとEclipseを使ったデバッグに進むのですが、テキストベースのEmacsの方でも十分デバッグができます。\n", "\n", "先ほどと同様にpyocd-gdbserverを起動した後、\n", "別のターミナルを開いて、mbedのプロジェクトのあるディレクトリに移動して、以下のコマンドを入力してください。\n", "```bash\n", "$ emacs\n", "Welcome to GNU Emacs, a part of the GNU operating system.\n", "Emacsの使い方の説明画面が表示されます。\n", "```\n", "\n", "ここで、ESC xに続いてgdbを入力すると、以下の様に表示されますので、arm-none-eabi-gdb --annotate=1 BUILD/LPC1768/GCC_ARM/blink.elf\n", "と入力してください。\n", "```\n", "Run gdb (like this): gdb --annotate=1 \n", "```\n", "gdbが起動しますので、先ほどと同様に、target remote :3333, load, br main, cを入力すると画面が上下に分割し、上部にgdbのコマンドが表示され、\n", "現在停止している箇所のソースが表示されます。\n", "\n", "![gdbでデバッグを開始した直後の画面](images/M0/start_gdb_mode.png)\n", "\n", "ここで先ほどと同様にnコマンドを入力すると下部の画面の=>がwait_ms(500);に移動します。\n", "\n", "続いて、p leと入力した後にTABを押すと補完され、led1が表示されます。続いて.reの後にTABを押すと.readがでるので、( )を追加して改行するとled1の値を確認することができます。\n", "\n", "n, s, cを入力するとgdb画面でスクロールすので、以下の様に実行するとgdb画面には表示されずにnext, stepを実行できます。\n", "- next: Ctrl-a Ctrl-x Ctrl-n\n", "- step: Ctrl-a Ctrl-x Ctrl-s\n", "\n", "詳しくはGDBモードのCheat Sheetを参照してください。\n", "- [Emacs + GDB チートシート](http://d.hatena.ne.jp/higepon/20090505/p1)\n", "\n", "補完機能の他にCtrl-p, Ctrl-nで前のコマンドや次のコマンドに移動したり、\n", "Ctrl-rで文字列検索で過去のコマンドを検索できるので、キー入力が大幅に省略できます。\n", "\n", "Emacsを終了する前に、GDBにqを入力してデバッグを終了しましょう。\n", "この後、Ctrl-x, Ctrl-cでEmacsを終了します。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" } }, "nbformat": 4, "nbformat_minor": 0 }