サブコアとメインコアをシームレスにデバッグ。高機能IoTアプリケーションを効率的に開発、解析する方法とは


図

前回までの初心者講座を通してマルチコアアーキテクチャの基礎を理解いただけたと思います。今回は、実際の製品開発に欠かすことのできない「マルチコアとサブコアをシームレスに(コアの違いを意識することなく自然に)解析する」方法を紹介いたします。

サンプルアプリケーションとして、メインコアとサブコアを連携させるための同期プリミティブを繋ぎ合わせたシンプルなC/C++ソースコードを準備しました(後述)。

また、実践的なデバッグをすぐに体験いただけるよう、本記事ではASMPアーキテクチャとしてCortex-M4x6コアを搭載しているSPRESENSE™を活用。安価なJTAG-ICEデバッガと、無償の開発環境を利用して、コア間をシームレスにデバッグする様子や方法を動画にて紹介いたします。特別な作業なく簡単に使い始めることができるため、はじめてのマルチコアプログラミングに挑戦される方も、是非お手元でお試しください。

なお、今回紹介するメインコア/サブコアのデバッグにはSPRESENSE SDK v1.5.0(2019/12/20リリース)以降をベースとしたプロジェクトと開発環境が必要となります(理由についてはMakefileの節にて説明いたします)。

図

▼目次

ASMP対応のビルド環境(Makefile)

ASMP上で動作するプログラムのデバッグを始める前に、プログラムがどのようにビルドされているかの手順を解説いたします。ビルド環境を理解することにより、デバッグ対象の実行プログラムがどのように生成され、どういったデバッグ情報を必要としているのかを知ることができます。デバッグに手間取った場合や、他環境で開発した経験をSPRESENSEの開発に活かす際の助けになるでしょう。

SPRESENSE SDKのビルド環境

SPRESENSE SDKでは、プロジェクトに含まれたソースコードから実行ファイルを生成するためのビルド作業に必要な操作を「Makefile」に定義しています。v1.4.0からv1.5.0へのアップデートにより、全Makefile(各アプリケーションそれぞれをビルドするルール)から共通となるステートメントを切り出し。「.vscode」フォルダーに共通部を集約することで、プロジェクト全体のMakefileを簡略化、シンプルなMakefile(ビルドルールの表現)を実現しています。

メインコア向けプログラムをビルドするための共通手順は「.vscode/application.mk」に、サブコア向けプログラムをビルドするための共通手順は「.vscode/worker.mk」に一本化されており、共通処理はアプリケーションごとのMakefileから「inlude」ステートメントにより参照されています(図2-1)。

図
図2-1:SPRESENSE SDKのビルド環境(サブコアデバッグ対応:v1.5.0以降)

参考として、SPRESENSE SDK v1.4.0以前のビルド環境を図2-2に示します。

図
図2-2:SPRESENSE SDKのビルド環境(サブコアデバッグ非対応:v1.4.0以前)

C++(.cxx/.cpp)を使って開発する場合

SPRESENSE SDKのapplication.mk(メインコア用の共通ビルド手順)は、アプリケーションのエントリポイント「プロジェクト名_main」関数がC言語のソースコードファイル(.c)に含まれるものとして設計されています。(application.mk#L68)。

ifeq ($(MAINSRC),)
	MAINSRC = $(APP_FOLDER_NAME)_main.c
endif
ASRCS +=
CSRCS += $(filter-out $(MAINSRC),$(wildcard *.c) $(wildcard */*.c))
CXXSRCS += $(wildcard *.cpp) $(wildcard */*.cpp) $(wildcard *.cxx) $(wildcard */*.cxx)	

そのため、C++言語「.cxx/.cpp」のプログラムを混在させる場合は、エントリポイントのみC言語のソースコードで実装し、そこからC++のエントリポイントを呼び出す構造とすることが良いでしょう。実行時に1回の関数呼び出しコストが発生しますが、Makefileやapplication.mkを変更せずに、C/C++が混在したアプリケーションを開発することができます(図3)。

図
図3:C/C++のアプリケーションが混合したシステムの構築例

デバッグ情報の生成

ASMPのサブコア(CPU#1〜#5まで)をデバッグするためには、サブコア上で動作する実行ファイル(ELF形式)に加えて、同名で拡張子が「*.debug」のデバッグ情報ファイルが必要となります。SPRESENSE SDK v1.5.0はデバッグ時に(JTAG-ICEにより操作の際に)、「*.debug」を参照し、サブコア上で実行中の関数名、コールスタックの内容、スコープ内の変数、それぞれのデータが格納されているメモリアドレスを特定。メインコア/サブコアの違いを感じさせることなく、実行中のC/C++言語をスムーズに追いかけることのできます。(図4)。

SPRESENSE SDK v1.5.0のサブコア用アプリケーション自動生成機能は、Makefileにworker.mkをインクルードするステートメントが含まれており(図4:inclueステートメント)、worker.mkにはデバッグ情報ファイルを生成するためのルール(worker.mk#L15)が定義されています。これにより、ビルドするだけで「デバッグ情報ファイル(*.debug)」を自動的に生成・更新することができます(SPRESENSE SDK v1.4.0以前のMakefileには、.debugをビルドするルールがないためサブコアのデバッグはできません)。

図
図4:SPRESENSE SDK v1.5.0のMakefile

...
BIN = $(OUTDIR)/$(WORKER_NAME)
DBG = $(APPDIR)/$(WORKER_FOLDER_NAME)/$(WORKER_NAME).debug
...

なお、サブコアをデバッグする場合は、メインコアがサブコア上に実行するプログラムを展開した後(図5の②)、デバッグ情報ファイルを適用してください(図5の③:手順ば後述)。

図
図5:実行ファイル・デバッグ情報ファイルを適用するポイント

デバッグの準備

それでは、簡単でシームレスにマルチコアの状態を追いかけることのできる開発環境を構築して、利用してみましょう。

必要な機材

今回のデバッグ作業には、JTAG-ICEデバッガ(実機の内部状態を観測・制御することのできるデバッグ用ハードウェア)が必要となります。プログラムを実行するSPRESENSE Main Boardに加えて、 JTAG-ICEデバッガの接続ポートを備えた「SPRESENSE Extension Board」もしくは「SPRESENSE LTE Board(2019年12月20日発売)」をご用意ください。また、今回はJTAG-ICEデバッガとして「NXP LPC-Link2」を利用しました(詳細は後述の環境構築手順をご参照ください)。

図
図6:SPRESENSE Extension Board(CoreSight10接続端子を搭載)

図
図7:SPRESENSE LTE Board(CoreSight10/20接続端子を搭載)

ソースコードの入手

デバッグ対象となるサンプル・ソースコードは「APS-Academy(Multicore) #9 Sample Code」として公開しております。下記の手順に従ってソースコード一式をPCにダウンロードしてください。本記事ではJTAG-ICEデバッガ「NXP LPC-Link2」の設定方法も紹介しています。

# SPRESENSEのgitのリリースリストが表示されます
$ git tag -l
v1.0.0
v1.0.1
...
v1.5.0.is.1.0
# ソースコードから"1.5.0.is.1.0"という名前のブランチを生成します
$ git checkout -b 1.5.0.is.1.0 refs/tags/v1.5.0.is.1.0
Switched to a new branch '1.5.0.is.1.0'
# このように切り替わっています
$ git branch
* 1.5.0.is.1.0
	master
# 1.5.0.is.1.0の初期状態にリセットします
$ git reset --hard HEAD

ASMPの全コアを同時にデバッグする

今回は、上記の手順により入手できるサンプルアプリケーション「aps_template_asmp(メインコア用プログラム)」と「aps_template_asmp_worker(サブコア用プログラム)」を利用し、デバッグ方法を紹介いたします。

サンプルアプリケーションの動き

サンプルアプリケーションの動作は非常にシンプルです(図8)。本アプリケーションは、メインコア上で起動した後、メインコアがaps_template_asmp ELF実行ファイルを使ってサブコアを起動。メインコアとサブコアを繋ぐメッセージキューにより、メインコアがサブコアへ処理を依頼。サブコアは依頼内容に従って決められた処理を実行し、メインコアに完了通知を発行します。メインコアは、サブコアへ10回処理要求を発行した後、サブコアへ終了要求を発行します。最後に終了要求を受け取ったサブコアが自発的に終了、アプリケーションが停止します。

図
図8:デバッグに利用するサンプルアプリケーション

イベントドリブン/メッセージドリブン設計を実開発へ応用する

今回、デバッグ対象として扱ったプログラムは非常にシンプルですが、このような「イベントドリブン」「メッセージドリブン」型の実装は、世界中ありとあらゆるアプリケーションに採用されています。今回のプログラムに、要求のバリエーションを追加し、メッセージを受け取った際の処理をリッチにすることにより、様々なサービスを実現することができます。

例えば、対話的に操作できるWindowsアプリケーションは「クリックされた」「特定のキーが押された」というイベント(メッセージ)を契機に、適切なリアクションを実行しています。また、WEBサーバーもクライアントからの要求(メッセージ)に応じてコンテンツを生成し返答することにより、レスポンシブルで高機能なサービスを提供しています。

マルチコアをシームレスにデバッグする

すでに様々な組み込み開発を体験されている方にとっては、ASMP上のアーキテクチャをデバッグする手順を難しく感じるかもしれません。しかし、上記の動画を通して要点を抑えることで、SMPアーキテクチャやシングルコアアーキテクチャ(※)よりも簡単にデバッグできることに気付くと思います。是非お手元でお試しください。

※:シングルコアアーキテクチャ上で実行されるアプリケーションは、1個のMCU上で様々なタスクを動的に交換しながら実行するため(コンテキストスイッチが多いため)、デバッグで追いかけている機能と他の機能が混在し、対象の処理を追いかけにくい場合が多くあります。

SPRESENSEのデバッグは、大きく分けて5つの手順により行います。

  • 前準備:ソースコードのビルド、構成ファイルを更新する
  • メインコアとサブコアが最初に連携する箇所にブレークポイントを設定する
  • メインコアのデバッグを開始する
  • サブコアにデバッガをアタッチする
  • メインコアとサブコアを同時にデバッグする

前準備:ソースコードのビルド、構成ファイルを更新する

上記の環境構築手順に従ってGitHubからソースコードを入手ください。ソースコードを入手し、Visual Studio Codeでワークスペースを開いた後、図9に示す①〜⑤の手順でデバッグ・実行の準備が整います。

  1. Visual Studio Codeの画面右に表示されている「デバッグ」アイコンをクリックする
  2. 左上のプルダウンから「Main Core (sandbox00)」を選択する
  3. プルダウン右の歯車マーク(設定ボタン)をクリックし、構成ファイルを開きます
  4. 画面右下の「構成の追加」からSubCore#1に関する設定を追加します
  5. ファイル構造にあわせて、構成にデバッグ対象の情報を追記します

本記事で利用しているデバッグ構成ファイル(launch.json)の内容

図
図9:構成ファイルにサブコア(CPU#1)をデバッグ対象に含める設定を追記

ブレークポイントを設定する

次に、ブレークポイントを設定します。マルチコアとサブコアの双方をデバッグするために「タスク生成処理|ret = pwc->execTask();」の直後にブレークポイントを設定します(図10)。

図
図10:メインコアとサブコアが同期する直前にブレークポイントを設定する

メインコアのデバッグを開始する

続いて、メインコアのデバッグ操作を開始します。デバッグが開始されると、まずRTOS「NuttX」のエントリポイントである「__start」で実行が停止します。再開ボタンを押すことにより、NuttXが開始され、プロンプトであるNuttShellが起動、操作できる状態となります。NuttShellに「aps_template_asmp」と入力しEnterキーを押下するとアプリケーションが開始され、前手順で設定していたサブコア起動直後の位置でプログラムが一時停止します。

図
図11:メインコアのデバッグを開始する

サブコアへデバッガを接続する

メインコアが一時停止している状態で、①画面左上のプルダウンから「Sub Core 1(sandbox001)」を選択、緑色の再生マークをクリックしデバッグを開始します。サブコアのデバッグが開始すると、操作ウィンドウの横に(図12-②)各コアのプルダウンメニューが表示され、各コアを自由に操作できるようになります。

図
図12:操作ウィンドウにメインコア/サブコアの選択肢が表示される

最後に、メインコアとサブコアを画面上の操作ボタンから再開(青色の再生ボタン)し、全コアのデバッグを開始します。これにより、図13の流れでマルチコア/サブコアを意識することなく動作中の命令をデバッグ・解析・検査することができます。

図
図13:設定したブレークポイントがメインコア/サブコア問わず、順に停止する

このように、Visual Studio CodeとSPRESENSE SDKを活用することにより、ASMPやマルチコアといった複雑なシステム開発であったとしても、すべてのプログラムの動作を精密に分析、効率的に不具合箇所の解析や、プログラムのテストを実施可能です。是非ご活用ください。

まとめ

新しいCPUアーキテクチャを次期製品開発に取り入れる場合、開発環境の導入方法や、デバッグ効率の検証は、その後の工数(開発効率)に大きく影響する重要な課題です。SPRESENSE SDK v1.5.0の提供するマルチコアをシームレスにデバッグできるGUIベースのデバッグ環境は、みなさまのマルチコア・プログラミングの開発効率を大きく改善してくれることでしょう。

是非ご活用ください。

SPRESENSE SDK v1.5.0アップデートによる改善点

開発環境がアップデートされたとしても「これまでの開発してきた資産や、追加の評価工数への懸念」などにより、なかなか移行に踏み切れない点もソフトウェア開発の難しさのひとつです。SPRESENSE SDKでは、2019/12/18にv1.5.0が公開され、v1.4.0の提供が終了となりました。今回の記事の補足として、マルチコア・プログラミングを学習している、または実際の開発に採用されているエンジニアの皆様への効果・影響の概略をまとめます。詳細はGitHubのリリースページをご参照ください。

SPRESENSE SDK v1.5.0のリリース情報|GitHub

アプリケーション生成ウィザードの操作性改善

Visual Studio Code上で実行できる「アプリケーションの生成機能」がウィザード形式(対話式)になり、使いやすくなっています。同じメニューから、メインコア専用プログラムの生成、またはメインコアとサブコアを連携させるプログラムの生成が可能となりました。

図
図14:SPRESENSE SDK v1.5.0でのアプリケーション自動生成機能

Makefileの変更

v1.5.0では、ビルドルールの共通処理を.vscodeフォルダにまとめ、アプリケーションごとのMakefileはincludeステートメントのみで完結していることから、簡単にアプリケーションのビルドルールを書き換えられるようになりました。ただし、共通部分を書き換えたい場合、.vscode内のルールを書き換えてしまうと全アプリケーションのビルドに影響が発生するため、v1.4.0のMakefileを参考に対象のアプリケーションに個別で独立したMakefileを準備することをオススメします。アプリケーションの開発効率や、システム全体のメンテナンスのしやすさ、今後のアップデートを見据えた上で、自身で管理しやすいビルド環境を選択してください。

Makefile|v1.4.0からv1.5.0への変更差分