~新しいBSP(ボードサポートパッケージ)を使いこなす〜
豊山 祐一
トロンフォーラム T3 WGメンバー
INIAD(東洋大学 情報連携学部)
TRONプログラミングコンテストがいよいよ始まった。同時にコンテストで使用するリアルタイムOS「µT-Kernel 3.0」のBSP(ボードサポートパッケージ)の新バージョンBSP2(β版)も公開された。
https://github.com/tron-forum/mtk3_bsp2/tree/develop
コンテストで使用されるマイコンボード、そしてµT-Kernel 3.0 BSP2(β版)について紹介する。
コンテストの対象マイコンボード
本コンテストで使用するマイコンボードは、協力するマイコンメーカー4社のボードと、それに加えて教育分野で広く使用されているmicro:bitの計5種類である(写真1)。
写真1 各マイコンボードの外観
micro:bitについては、パーソナルメディア株式会社の製品である「IoTエッジノード実践キット/micro:bit」を使用する。micro:bitのキットはパーソナルメディアのウェブページ注1)を参考にされたい。
マイコンメーカー4社のマイコンボードの概要を表1に示す。
表1 各マイコンボードの概要
KIT_XMC72_EVK | Nucleo-H723ZG | FRDM-MCXN947 | EK-RA8M1 | |
製造メーカー | インフィニオン テクノロジーズ | STマイクロエレクトロニクス | NXP Semiconductors | ルネサス エレクトロニクス |
搭載マイコン | XMC7200 | STM32H723 | MCX N947 | RA8M1 |
CPUコア※ (最大動作周波数) | Arm Cortex-M7デュアル※ | Arm Cortex-M7 (550MHz) | Arm Cortex-M33デュアル※ (150MHz) | Arm Cortex-M85 (480MHz) |
メモリ | FLASH 8MB+256KB WF RAM 1MB | FLASH 1MB RAM 546KB | FLASH 2MB RAM 512KB | FLASH 2MB RAM 1MB |
外部インタフェース | Arduino互換コネクタ、 Pmodコネクタ×2、 Ethernet、 USB、他 | Arduino互換コネクタ、 Ethernet、 USB、他 | Arduino互換コネクタ、 mikroBUSコネクタ、 Pmodコネクタ、 Ethernet、 USB、他 | Arduino互換コネクタ、 mikroBUSコネクタ、 Pmodコネクタ×2、 Groveコネクタ×2、 Ethernet、 USB、他 |
※µT-Kernel 3.0はデュアルコアには対応していません。シングルコアで動作します。
Arduino互換コネクタなどの拡張性
各マイコンボードは、搭載しているマイコンの各信号の入出力を備えており、センサーやアクチュエータなどの外部ペリフェラルを接続することも可能である。
また、どのマイコンボードもArduino互換コネクタを搭載している。Arduinoは電子工作などの分野で普及しているハードウェアであり、Arduino互換コネクタに対応したさまざまな外部ペリフェラルが販売されている。コンテストにこれらを使用することも容易である。
さらにマイコンボードによっては、Arduino互換コネクタ以外にも、GroveコネクタやmikroBUSコネクタなども搭載されている。
デバッガ機能をマイコンボードに搭載
一般的にはマイコンボードを用いた開発では、デバッガプローブやJTG ICEなどの専用の装置を用いてパソコンとマイコンボードの接続を行う。しかし、今回対象のマイコンボードはデバッガ機能をボードに搭載しているので、これらの装置は不要である。USBケーブルでマイコンボードとパソコンを接続するだけで開発が可能だ。
IDE注2)が無償提供
マイコンメーカー各社からは、IDEが無償提供され、これを使用してプログラムの開発やデバッグを行うことができる。また、これらのIDEはコンフィギュレータの機能も持ち、マイコンのCPUや内蔵ペリフェラルの設定を行い、起動処理やHAL注3)のソースコードを含むプロジェクトの自動生成が可能である。
なお、メーカー提供のIDEの使用はコンテストの必須事項ではないので、使い慣れている開発環境やツールがあれば、それを使用することも可能だ。
注1) IoTエッジノード実践キット/micro:bit http://www.t-engine4u.com/products/ioten_prackit.html
注2) IDE:Integrated Development Environment(統合開発環境)の略称。
注3) HAL:Hardware Abstraction Layerの略称。ハードウェアを抽象化して制御するソフトウェア。
µT-Kernel 3.0 BSP2について
µT-Kernel 3.0 BSPとは
トロンフォーラムでは以前から市販のマイコンボードで簡単にµT-Kernel 3.0を使用することが可能なµT-Kernel 3.0 BSPをGitHubより公開してきた。昨年12月にはBSPの新バージョンであるµT-Kernel 3.0 BSP2が公開された。
BSP2の大きな特徴は、マイコンメーカーが提供するIDEやHALなどのソフトウェアとの親和性が強化されたことである。
これまでのBSPは、特定の開発環境やファームウェアに依存せずにスタンドアローンで動作するように作られていた。しかし、マイコンの機能が大幅に増えてきたことにより、メーカー提供のIDEやHALなどのさまざまな開発ツールを活用し、開発効率を向上させることを要望する声が多くなってきた。このような背景をふまえて、BSP2はマイコンメーカー提供のIDEのプロジェクトに簡単に組み込むことができ、コンフィギュレータが自動生成したソースコードとも共存し、HALなどの活用ができるようになっている。
なお、どのような開発形態をとるかは製品の特長やメーカーの方針によりさまざまであり、従来のBSPも引き続き提供は続けていく予定である。BSPとBSP2のどちらを使うかは用途に応じて選択していただきたい。OS自体は同じµT-Kernel 3.0であり、その機能に変わりはない。
IDEによる一般的な開発の流れ
マイコンメーカーが提供するIDEやコンフィギュレータ、HALなどを使用した開発について概要を説明しよう。
詳細な手順や機能などは各社各様であるが、基本的な流れは共通である。今回のマイコンボードに提供される各社のIDEは、Eclipse Embedded CDTというオープンソースのIDEがベースであり、共通の操作も多い。
開発するマイコンのプログラムは、プロジェクトとよばれる単位で管理される。個々のプロジェクトには、開発するプログラムのソースコードや開発環境の各種設定、その他関連するデータがまとめられている。
IDEによるプログラムの開発はまずプロジェクトの作成から始まる。プロジェクト作成のイメージが湧きやすいように、基本的な手順を各社のIDEの画面とともに説明しよう。
① ハードウェアの選択
プロジェクトの新規作成時には、まず使用するマイコンやデバッガなどのハードウェアの選択を行う。
メーカー純正のマイコンボードであれば、そのボードを選択するだけで、各種の基本設定が終わることもある。
図1に示したのは、NXPのMCUXpresso IDEのマイコンボードの選択画面である。
図1 IDEのマイコンボード選択画面(MCUXpresso IDE)
② マイコンの端子設定
最近のマイコンには多くのペリフェラルが内蔵されている。このため、マイコンの端子一つに対して、複数の機能が割り当てられており、マイコンの初期化時にそれぞれの端子がどの機能を使用するか設定を行わなければならない。
IDEのコンフィギュレータはGUIベースで各端子の機能設定を行い、それに基づいて端子を初期化するプログラムを自動生成することができる。
図2に示したのは、ルネサス エレクトロニクスのe2studioのマイコン端子の設定画面である。
図2 IDEのマイコン端子の設定画面(e2studio)
③ クロックの設定
マイコン内蔵のペリフェラルが増えたことにより、マイコンの内部クロックの設定も複雑になっている。クロックのソースを選択し、そこからCPUや各ペリフェラルに提供する各種のクロックを生成していかなければならない。目的の周波数のクロックを生成する設定は組み合わせが多く、設定を誤ればCPUやペリフェラルが正常に動作しなくなる。
IDEのコンフィギュレータはGUIベースでクロックの設定を行い、その設定に基づくクロック初期化のプログラムを自動生成することができる。また、メーカー純正のマイコンボードを使用している場合は、最初から標準的な設定をとることも可能だ。
図3に示したのは、STマイクロエレクトロニクスのSTM32Cube IDEのクロック設定の画面である。
図3 IDEのクロック設定画面(STM32Cube IDE)
④ HALの設定
マイコン内蔵のペリフェラルは高機能化に伴い、その設定や制御も複雑化している。HALはペリフェラルのレジスタを直接制御するのではなく、機能的に抽象化された制御関数を提供するソフトウェアである。メーカーによって呼び名はさまざまであるが基本的な目的は同じである。
HALもIDEのコンフィギュレータにより、プロジェクトへのソースコードの追加や各種設定を行うことができる。
µT-Kernel 3.0 BSP2から、HALなどを用いたペリフェラルの制御方法については、後ほど説明する。
µT-Kernel 3.0 BSP2のプロジェクトへの組込み
IDEのコンフィギュレータを使用して作成したプロジェクトへのµT-Kernel 3.0 BSP2の組込みは簡単な手順で行うことができる。また、コンテストで使用する各マイコンボードについては、組込み済みの基本的なプロジェクトが提供される。
以下にµT-Kernel 3.0 BSP2のプロジェクトへの組込みの手順を示そう。
① ソースコードの追加
プロジェクトのディレクトリに、µT-Kernel 3.0 BSP2のソースコードのディレクトリを追加する。これは単純なディレクトリのコピーでよい。IDEではディレクトリのドラッグ&ドロップで行うことができる。
② 対象マイコンボードの指定
µT-Kernel 3.0 BSP2は一つのソースコードから各マイコンボードに対応した実行プログラムがビルドできるようになっている。これには、対象とするマイコンボードを指定するC言語プリプロセッサのマクロ名を定義すればよい。表2に各マイコンボードのマクロ名を示す。
マクロ名の定義はIDEから行うことができる。
表2 マイコンボードを指定するマクロ名
マイコンボード | マクロ名 |
KIT_XMC72_EVK | _MODUS_EVK_XMC7200_ |
Nucleo-H723ZG | _STM32CUBE_NUCLEO_H723_ |
FRDM-MCXN947 | _NXPMCUX_FRDM_MCXN947_ |
EK-RA8M1 | _RAFSP_EK_RA8M1_ |
③ インクルードパスの設定
µT-Kernel 3.0 BSP2をビルドするために必要な四つのインクルードパスの設定を行う。一つはµT-Kernel 3.0 BSP2のソースコードのディレクトリのパスである。残りの三つは、µT-Kernel 3.0をビルドする際に使用するパスである。
インクルードパスの設定はIDEから行うことができる(図4)。
図4 IDEでインクルードパスの設定
④ µT-Kernel 3.0の呼び出し
プロジェクト上のアプリケーションプログラムからµT-Kernel 3.0の実行関数knl_start_mtkernel()を呼び出すことにより、µT-Kernel 3.0を起動することができる。以降はµT-Kernel 3.0の上でアプリケーションプログラムが実行されていく。
µT-Kernel 3.0 BSP2のシステム構成
マイコンメーカーのプロジェクトに組み込まれたµT-Kernel 3.0 BSP2のシステム構成を図5に示す。
最下層にIDEで自動生成された初期化処理のプログラムやHALがある以外は、一般的なµT-Kernel 3.0のシステム構成と同じである。最上位で動作するアプリケーションプログラムから見れば、ハードウェアの相違はOSによって抽象化され隠ぺいされる。固有のハードウェア機能に依存しない限りは、マイコンボードが異なっても同一のアプリケーションプログラムが実行可能となる。これはOSを使用するメリットの一つである。
図5 µT-Kernel 3.0 BSP2のシステム構成
ペリフェラルの操作方法
µT-Kernel 3.0は標準の機能としてデバイス管理機能を備えており、各種のペリフェラルを抽象化したデバイスとして、共通のデバイス操作APIで操作することができる。このためには対象のペリフェラルについて、専用のデバイスドライバを開発する。本稿では他と区別するために、このµT-Kernel 3.0標準のデバイスドライバを「µT-Kernelデバイスドライバ」とよぶこととしよう。
µT-Kernel 3.0 BSP2では具体的に以下の三つの方法でペリフェラルの操作が可能だ。それぞれ長所短所があるので、用途、目的などに応じて選択してほしい。
① µT-Kernelデバイスドライバを使用する
µT-Kernel 3.0従来の方法であり、それぞれのペリフェラルに対してµT-Kernelデバイスドライバを作成し、それを使用してペリフェラルの操作を行う。すでに対象のペリフェラルのµT-Kernelデバイスドライバが開発済みであれば、そのまま使用することができる。
メリットは、専用に開発するので機能や動作を自由に決められることがある。デメリットととしては、マイコンメーカーが提供するHALを使用せず一から開発を行うので、開発工数が大きくなることが考えられる。
② HALを直接使用する
マイコンメーカーが提供するHALをµT-Kernel 3.0のアプリケーションプログラムから直接使用することは可能である。
メリットは、まず開発工数がかからないことがあげられる。さらに、HALは一般的に対象のペリフェラルの持つ機能を網羅しているので、機能面での不足もない。
デメリットとしては、HALはマイコンメーカーごと、さらに対象とするペリフェラルごとに仕様が定められているので、プログラムのハードウェア依存性が高くなることがあげられる。
また、HALはリアルタイムOSのマルチタスクでの使用を必ずしも考慮していないので、使用上は以下の点をアプリケーションプログラムが考慮しなくてはならない。
- 複数のタスクから同一のペリフェラルを同時に操作しようとするとコンフリクトが発生し正常な動作ができなくなる。基本的には一つのペリフェラルは固有のタスクからHALを用いて操作することが望ましいが、複数のタスクで同時に使用する場合は、µT-Kernel 3.0のセマフォなどの機能を使用し、排他的にHALを使用するようにする。
- HALの制御の中には、イベントの取得にポーリングを使うことを前提としたものがある。ポーリングはマルチタスクの環境で使用すると、リアルタイム性能の低下をもたらすので、イベントの取得は割込みを使用するようにしなければならない。通常、HALの機能もポーリングと割込みを選択できるようになっていることが多いので、後者を使用するようにプログラミングを行う。
- HALの割込み制御において、割込みハンドラから通常のプログラムへのイベントの通知には、µT-Kernel 3.0のイベントフラグなどの機能を使用する。HALのサンプルプログラムの多くはグローバル変数を使用したポーリング方式のものが多いが、この方式はリアルタイム性能の低下をもたらすので避けなければならない。また、HALの割込みハンドラからµT-Kernel 3.0のAPIを使用するには、µT-Kernel 3.0の実装上定められた手順をとらなくてはならない。通常はAPIを使用する区間を決められたマクロで明示する必要がある。
③ HALを利用したµT-Kernelデバイスドライバを使用する
µT-Kernelデバイスドライバの内部で直接ペリフェラルを制御するのではなく、HALを使用して制御を行うようにする。つまりµT-KernelデバイスドライバをHALのラッパープログラムとして作成する。
メリットは、HALを直接使用する場合と比べて、HALの持つハードウェア依存性をデバイスドライバが隠ぺいすることにより、マイコンやペリフェラルが異なっても、アプリケーションプログラムからは同じデバイスドライバとして使用することが可能となることが、まずあげられる。
さらに、前項で述べたHALをアプリケーションプログラムから直接制御するために必要な事項はデバイスドライバが行うので、アプリケーションプログラムは意識する必要がなくなる。
デメリットとしては、HALを直接使用するよりは、開発工数が必要となることがあげられる。ただし、HALを使用せずにデバイスドライバを開発するよりは大幅な工数の低減が期待できる。
どの方法を使用するかは、開発するアプリケーションプログラムの特徴や方針に依存するが、総合的には③がお勧めと考える。信頼性や検証の問題で他社製のHALを使用できない場合でも、まずプロトタイピングとして利用し、最終的に①のHALを含まないデバイスドライバに置き換えることもできる。
µT-Kernel 3.0 BSPのサンプル・デバイスドライバ
µT-Kernel 3.0 BSPには、サンプルプログラムとして、A/DコンバータやI2C通信用のµT-Kernelデバイスドライバが付属している。
このデバイスドライバは、先に説明した方式のうち、HALを利用したµT-Kernelデバイスドライバである。デバイスドライバ内の処理でHALを呼び出してペリフェラルの制御を行っている。そのまま使用しても良いし、HALを利用したµT-Kernelデバイスドライバを作成するために参考として利用してほしい。
各デバイスドライバの使い方の例を簡単に説明しよう。
例1 A/Dコンバータによるセンサーの制御
アナログ信号を出力するセンサーには、音センサー、温度センサー、光センサー、圧力センサーなどさまざまな種類がある。どのセンサーも基本的には測定した値に応じて出力するアナログ信号の電圧を変化させる。
センサーからのアナログ信号の電圧を、マイコン内蔵のA/Dコンバータによってデジタル値に変換することにより、プログラムからセンサー値を利用することが可能となる。
リスト1に示すのは、A/Dコンバータのデバイスドライバを使用し、センサーの値を読み取って、シリアル出力に送信するタスクのプログラムである。このタスクのプログラムは、コンテストで使用するマイコンメーカー4社のマイコンボードで実行が可能である。
プログラムの順序に従って説明しよう。
① デバイスのオープン
デバイスのオープンAPI tk_opn_devにより、A/Dコンバータのデバイスドライバを使用可能とする。APIの第一引数がオープンするデバイスドライバの名称であり、これはデバイスドライバを登録する際に決められている。リストでは「hadca」という名称であるが、実際に使用するマイコンボードやそのアナログ信号によって指定するデバイス名は決められる。
APIが成功すると戻り値としてデバイスドライバのディスクリプタが返ってくる。以降はこのディスクリプタを使用してデバイスドライバを制御する。
② デバイスからのデータのリード
デバイスからのリードAPI tk_srea_devにより、デバイスドライバからデータを取得する。
第1引数に対象とするデバイスのディスクリプタを指定する。ここでは①でオープンしたA/Dコンバータのデバイス・ディスクリプタを指定している。
第2引数はリードするデータ位置の指定である。これはデバイスドライバの種類によって具体的な意味が異なるがA/Dコンバータのデバイスドライバの場合は、アナログ信号のチャンネル番号である。一般的なA/Dコンバータは複数のアナログ信号の入力チャンネルを持つので、センサーが接続されているチャンネルの番号をここで指定する。リストではチャンネル0が指定されている。
第3引数は取得したデータを格納する変数へのポインタである。第4引数には読み取るデータのサイズを指定する。BSP2に付属するA/Dコンバータのデバイスドライバは1回のAPIで1データしか読み取れないので、ここは常に1を指定する。
そして最後の引数には実際に取得したデータのサイズを格納する変数へのポインタを設定する。なお、A/Dコンバータのデバイスドライバの場合は、実際に取得したデータサイズは、APIが成功していれば1である。
③ データのシリアル出力
デバッグ用のシリアル出力API tm_printfにより、取得したセンサーのデータを出力する。tm_printfはC言語の標準関数printfによく似た関数だが、printfがコンピュータの画面に文字を表示するのに対し、tm_printfはUARTなどのシリアル通信に文字データを出力する。このシリアル出力をUSB変換してパソコンに接続すれば、パソコンのターミナルソフトでデータを確認することができる。
④ タスクの時間待ち
タスク実行遅延API tk_dly_tskにより指定した時間、タスクを待ち状態とする。指定する時間の単位はミリ秒である。リストの例では500ミリ秒を指定している。
⑤ プログラムの繰り返し
②から④の処理をwhileループで繰り返す。よって、0.5秒ごとにアナログ入力からセンサーの値がリードされ、シリアル通信に出力される。
リスト1 A/Dコンバータによるセンサーの制御タスク
LOCAL void task_1(INT stacd, void *exinf)
{
UW adc_val;
ID dd;
SZ asz;
ER err;
dd = tk_opn_dev((UB*)"hadca", TD_UPDATE); // ① デバイスのオープン
while(1) {
err = tk_srea_dev(dd, 0, &adc_val, 1, &asz); // ② デバイスからデータのリード
tm_printf((UB*)"A/DC A0 =%06d ", adc_val); // ③ デバッグ出力
tk_dly_tsk(500); // ④ タスクの時間待ち
}
}
例2 I2C通信の制御
I2C通信はシリアル通信の一種であり、2本の信号線で複数のペリフェラルに接続することができることから、マイコンで外部ペリフェラルの接続によく使用される。I2Cを使ったペリフェラルは、各種センサーやメモリ、LCDなどのディスプレイなどさまざまなものが存在する。
I2C通信による実際のデータの送受信の内容は、対象とするペリフェラルによって異なる。リスト2には、温度湿度センサーSHT32をI2C通信で制御するタスクのプログラムを示す。
デバイスのオープンなど基本的な動作は前述のA/Dコンバータと同様であるので、ここでは相違点となるI2C通信の送受信について説明しよう。
① データの送信
デバイスへのライトAPI tk_swri_devによりセンサーにコマンドを送信している。
第1引数は対象とするデバイスのディスクリプタである。第2引数はライトするデータ位置の指定であるが、I2C通信デバイスドライバの場合はここにターゲットアドレスを指定する。先に述べたようにI2C通信では複数のペリフェラルが接続できるので、それぞれのペリフェラルに固有のターゲットアドレスが与えられている。
第3引数は送信するデータのサイズ、第4引数は送信するデータを格納した変数へのポインタ、第5引数は実際に送信したデータのサイズである。I2C通信のデバイスドライバの場合は、実際に送信したデータサイズは、第3引数で指定した値と同一である。
② データの受信
デバイスへのリードAPI tk_swri_devによりセンサーからデータを受信している。
第1引数は対象とするデバイスのディスクリプタである。第2引数のリードするデータ位置の指定は、送信と同様にI2C通信デバイスドライバの場合はここにターゲットアドレスを指定する。
第3引数は受信するデータのサイズ、第4引数は受信したデータを格納する変数へのポインタ、第5引数は実際に受信したデータのサイズである。I2C通信のデバイスドライバの場合は、実際に受信したデータサイズも、第3引数で指定した値と同一である。
リスト2 I2C通信の制御タスク
LOCAL void task_1(INT stacd, void *exinf)
{
UW tmp0, hum0;
UB cmd[] = {0x2C, 0x06}; UB rcv[6];
ID dd;
SZ asz;
ER err;
dd = tk_opn_dev((UB*)"hiica", TD_UPDATE); // デバイスのオープン
while(1) {
err = tk_swri_dev(dd, 0x45, cmd, 2, &asz); // ① データの送信
tk_dly_tsk(1); // 時間を空ける
err = tk_srea_dev(dd, 0x45, rcv, 6, &asz); // ② データのリード
/* センサーの値から温度、湿度を計算 */
tmp0 = rcv[0]<<8 | rcv[1];
hum0 = rcv[3]<<8 | rcv[4];
tmp0 = (tmp0*175)/65535 - 45;
hum0 = (hum0*100)/65535;
tm_printf((UB*)"tmp = %d hum = %d\n\n", tmp0, hum0); // デバッグ出力
tk_dly_tsk(1000); // タスクの時間待ち
}
}
コンテストに応募しよう
µT-Kernel 3.0 BSP2を活用すれば、市販のマイコンボードとメーカーが無償で提供するIDE、さらに標準で用意されたA/DコンバータやI2C通信のデバイスドライバを用いて、これまでにも増して簡単にアプリケーションプログラムを作成することができる。特にµT-Kernelの使用経験がない方も、この機会に挑戦していただきたい。
そして、完成したプログラムをTRONプログラミングコンテストにぜひ応募してみてほしい。