※この記事は、筆者自身のブログに連載していたものを読みやすく1ページにまとめたダイジェスト版です。無断転載などではありませんのでご了承ください。
概要
まだマイコンに低消費電力が今ほどうるさく求められていなかった1990年代初頭(今から30年くらい前!)に、この分野にいち早く目を付けた先進的な製品がTexas Instruments(以下「TI」)のMSP430です。
今では、MSP432というARM(Cortex-M4)コアにMSP430のペリフェラル(周辺機器)をそのまま搭載した後継機種が出ております。
MSP432の方が性能(クロック当たりの演算スコア)が高いのは当然ですが、それほど高い処理能力は必要とせず、コスト重視、且つとにかく低い消費電力が求められるシーンでは、MSP430もまだまだ現役です。
当初はROMやRAMも小さい容量の型番しかありませんでしたが、時代とともに進化し、今では十分にRTOSの搭載も検討できる容量ラインナップも増えてきました。
そこで、このMSP430に「μITRON4.0」準拠のRTOS(リアルタイムOS)であるTOPPERS/ASPを移植してみました。
かなりメジャーなマイコンなので、公式でリリースされていないのは不思議ですけどね。
MSP430は16ビットのマイコンで、独自コアのRISCです。
GCC系のコンパイラが提供されており、TIの開発環境やサンプルプログラムも充実しています。
MSP430最大の売りである低消費電力を保持しつつ、TOPPERS/ASPを実装することが今回のキモになります。
さて、上手く実装できるでしょうか?
必要なもの
TIは、自社のマイコンを搭載した評価ボードのラインナップが豊富です。
今回は、MSP430の「MSP430F5529」を搭載した「MSP-EXP430F5529LP」という評価ボードを使います。
こちらで買うと、2,500円くらいですね。
他の型番への移植も可能ですが、TOPPERS/ASPを搭載して動作させるならROM:128KB/RAM:8KB以上の容量を持つ型番を選びましょう。
また「MSP-EXP430F5529LP」を使用する場合、デバッガーは必要ありません。
この評価ボードには既にデバッガーも実装されています。
「MSP-EXP430F5529LP」を使用しない場合は「MSP-FET」というMSP430に対応したTIのデバッガを使用する必要があります。
こちらで買うと、22,000円くらいですね。
高すぎてやってられません。
ですので、それを搭載している「MSP-EXP430F5529LP」が如何にお買い得かが分かりますね。
このブログでは「MSP-EXP430F5529LP」を使用した場合の例を説明していきたいと思います。
ダウンロード/GitHub
ソースコードの入手は、こちらからどうぞ。
なるべく定期的にメンテナンスするようにしていますので、動きがおかしいな?という場合は最新版に更新をお願いします。
それでもダメな場合はコメントください。
コンパイラのインストール
何はともあれ、まずはMSP430用のコンパイラのインストールを行いましょう。
以下のページでダウンロードします。
以下の場所まで移動しますので、「MSP430-GCC-OPENSOURCE」の方の「ダウンロードオプション」ボタンをクリックしましょう。
もう一方の「MSP432-GCC-OPENSOURCE」の方だと、ARMのコンパイラのダウンロードになっちゃうので注意。
以下の表示が出たら、目的のアーキテクチャ用のコンパイラを選択します。
このブログでは「Mitto Systems GCC Windows installer incl. support files」をダウンロードしたものとして説明します。
ダウンロードが完了すると「msp430-gcc-full-windows-installer-x.x.x.x.exe」というファイルが生成されますので、これをダブルクリック!
程なくして、以下の表示が出ます。
実行できない!?…と焦らずに「詳細情報」というリンクをクリックします。
そうすれば、ちゃんと「実行」ボタンがあらわれますので、これをクリック。
以降、インストーラーが起動し、しばらくは「Next」ボタンを連打です。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F2917131%2F7fa467df-6164-47e9-415b-a6fe68e9b4d3.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=9b85d227187dd6ce0ff6af82de486bc6)
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F2917131%2Fb8696da1-32e7-de04-6976-87b571a9d985.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=9639b0104ae20e9b4901214932af2114)
インストールが完了したら「Finish」ボタンをクリック。
これでコンパイラがインストールされました!
今回使うMSP430用のツールチェーンの環境変数の設定を行います。
ツールチェーンは、先程のインストール作業により既に以下のディレクトリにセットアップされているはずです。
環境変数の設定方法は他のページで調べていただくか、あるいは手前味噌で恐縮ですが、私のブログのページ(TOPPERS/ASPのビルドからデバッグまで~GNUツールチェーンの導入)の「環境変数の設定」の項目を御覧ください。
ただし、パスは…
C:\Program Files (x86)\GNU Tools ARM Embedded\7 2017-q4-major\bin
…となっているところを…
C:\ti\msp430-gcc\bin
また、このページの「パスの確認」の項目で打ち込むコマンドも、以下のように変わります。
続きまして「Cygwin」のインストールを行います。
基本的には「gcc-core」、「make」、「diffutils」、「perl」と「git」の5つのパッケージを含むようなCygwin環境を構築すれば良いです。
もしよろしければ、私のブログのページ(TOPPERS/ASPのビルドからデバッグまで~Cygwinの導入)を参考にしてください。
「Cygwin」がインストールできたら、ここまでの作業が上手くいっているかどうか確認しておきましょう。
次のページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのビルド)を参照してください。
ただし、今回使用するソースコードはこのページの冒頭の「NUCLEO-F401RE STM32 Nucleo-64」開発ボード用のTOPPERS/ASPカーネル簡易パッケージではなく、「MSP430」用のものを使います。
以下のコマンドでソースコードのクローンを行います。
$ git clone https://github.com/RyutaroMorita/asp_msp430_gcc.git
ダウンロードとGithub、いずれの場合も「asp_msp430_gcc」というディレクトリの名前を「asp_1.9.2」などと改名すると、上記のページと同じ状況になります。
また、今回は「OBJ」ディレクトリを作成する必要はありません。
これは既に用意されていますので、そのまま「OBJ」ディレクトリに移動し「make~」コマンドを実行してください。
統合開発環境のインストール
続きまして、MSP430用のIDEのインストールを行います。
IDEは、TI社純正の「Code Composer Studio」というものを使用します。
以下のページでダウンロードします。
以下の場所まで移動しますので、「CCSTUDIO - Code Composer Studio 統合開発環境」の右の「ダウンロードオプション」ボタンをクリックしましょう。
以下の表示が出たら、目的のタイプのコンパイラを選択します。
このブログでは「Windows single file (offline) installer for Code Composer Studio IDE (all features, devices)」をダウンロードしたものとして説明します。
ダウンロードが完了すると「CCS12.x.x.xxxxx_win64.zip」というファイルが生成されますので、これを解凍します。
解凍されて生成された「CCS12.x.x.xxxxx_win64」ディレクトリの中に「ccs_setup_12.x.x.xxxxx.exe」というファイルがあります。
これがインストーラー本体ですので、ダブルクリック!
以下のように、インストーラーが起動しますので「Next」ボタンをクリックです。
以下の表示は、もはや儀式。
「I accept the agreement」を選択して「Next」ボタンをクリックします。
この画面は、特に何もする必要がなく「Next」ボタンをクリック。
ここで以下の警告、「ペンディングされた再起動があるから、続けるならPCを再起動してけろ…」って、よく分からないが…とりあえず「OK」ボタンをクリックしましょう。
自動的に再起動食らうのでは?と思いましたが、そういうこともなく以下の表示が出ます。
続けて良いんだよな?
ならば「Next」ボタンをクリックしましょう。
この画面も、特に何もする必要がなく「Next」ボタンをクリック。
以下の表示は、このIDEで使用するマイコンのアーキテクチャを選択する画面です。
今回は、MSP430で使用しますので「MSP430 ultra-low power MCUs」のみをチェックして「Next」ボタンをクリックしましょう。
その後は、特に何もする必要がないので「Next」ボタンを連打です。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F2917131%2F9ab833c4-277f-3454-9155-66bbfc0955dc.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=38f1fd16fdd700efbbae56d47b92f29e)
ようやくインストールが始まりました。
完了までは、かなりの時間がかかります(序盤は順調にプログレスバーが進むが、終盤にグズグズする)。
インストールが完了すると、再び以下の警告が!
何やら「このインストールを完了するには再起動してけろ…」だって。
よっぽど再起動して欲しいらしい…わかったよ。
とりあえず「OK」ボタンをクリック。
以下の表示が出れば、インストールは完了です。
「Finish」ボタンをクリックしてください。
さて、インストールされた「Code Composer Studio」をすぐにでも起動させてみたいところですが、散々再起動しろ!って言われたので、ここで一旦PCを再起動しましょう。
こういうのは従っておいた方が、後々トラブルに遭う可能性が少なくなるんで。
再起動後は、デスクトップに「Code Composer Studio」ショートカットが出来ているはずなので、それをダブルクリックしてIDEを起動してみましょう。
以下のようなスプラッシュ画面が表示されます。
しばらくすると、以下の表示が。
ここでベテランさんはピンと来ているハズ。
この「Code Composer Studio」って「Eclipse」ベースじゃね!?
…正解!
前回の「Arduino Mega2560版」で使用した「Microchip Studio」は「Visual Studio」がベースでしたが、今回は「Eclipse」ベースなのです。
マイコンベンダー各社は、もはや自前でIDEを作らなくなっちゃったんですかね。
企業の側でもIDEの開発工数を削減できるし、客側もベースとなったIDEを使った経験があればそれを活かせるし、メリットが多いのでしょう。
でもどうせなら、やたらと重い「Visual Studio」や、やや陳腐化している「Eclipse」などより、「Visual Studio Code」をベースにしてくれた方が軽くてナウい気がするんですけどね。
話を戻して…。
この表示で、ワークスペースのディレクトリを選択します。
特に拘りがなければ、そのままで「Launch」ボタンをクリックしてください。
以下の画面が出れば「Code Composer Studio」は正しくインストールできています。
やっぱ「Eclipse」だね~。
プロジェクトの作成
コンパイラのインストールまでの作業で、開発環境をインストールし、MSP430版TOPPERS/ASPのソースコードをダウンロードし、それをコマンドラインでビルドするまでを行いました。
そして、統合開発環境のインストールではTI社のIDEであるCode Composer Studioのインストールを行いました。
そこで、お次はこのIDE上でビルドが行えるようにプロジェクトを作成しましょう。
先程のCode Composer Studioを立ち上げた状態から、画面左上のメニューから「File」→「New」→「Project」の順にクリックしていきましょう。
すると、以下のダイアログが表示されますので、中央のリストから「C/C++」ディレクトリをクリックして、その中の「Makefile Project with Existing Code」を選択し「Next」ボタンをクリックします。
以下のダイアログが表示されたら必要事項を入力します。
ここでは、以下の通り。
Project Name:<任意のプロジェクト名(ここでは「asp_1.9.2」)>
Existing Code Location:C:\cygwin64\home\<ユーザ名>\asp_1.9.2
Toolchain for Indexer Settings:<none>
その後は元の画面に戻ります。
何の変化もないようですが、画面左端の重なったウィンドウマーク(?)を二箇所クリックしてみてください。
以下のように2つのウィンドウが現れ、そのうち「Project Explorer」の方には先程入力したプロジェクト名のディレクトリが表示されているはずです。
次に、画面上部のメニューから「Window」→「Show View」→「Other...」の順にクリックしていきましょう。
すると、以下のようなダイアログが表示されるので、中央のリストから「Make」ディレクトリ直下の「Build Targets」を選択し、「Open」ボタンをクリック!
これにより、画面下部のウィンドウに「Build Targets」タブが追加されたはずです。
配置場所が気持ち悪いので「Build Targets」タブをマウスでドラッグして左に移動させましょうか…。
(個人の好みで結構ですよ。)
以降の作業は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのデバッグ)の「プロジェクトのクリーンとビルド」の項目を参考に続行してください。
(自分のブログへの誘導みたいになっちゃっててすいません…。)
このCode Composer Studioは、Eclipseベースなので、上記のページと同じ方法で作業を続行できます、
但し、文中の「Makeターゲット」タブは、先程表示させた「Build Targets」タブに置き換えてお読みください。
名称は違いますが、これらのタブは同じ働きをするものです。
Code Composer Studioの画面右側に以下のようなアイコンが表示されて、これらをダブルクリックすることによりビルドができるまでを確認してください。
これまでの作業を行っていると「Console」タブが気持ち悪い場所に表示されていますね。
スペースの無駄なので、すぐ上のウィンドウと統合してしまいましょう。
「Console」タブをマウスで上のウィンドウへドラッグ&ドロップしてください。
このように、各タブの表示位置は個人のお好みに応じて変えていってくださいね~。
プログラムの転送とデバッグ
まずは、評価ボード「MSP-EXP430F5529LP」をUSB経由で開発用のパソコンと接続しましょう。
次にパソコン上でデバイスマネージャーを開きます。
ポート(COMとLPT)のサブカテゴリーとして「MSP Application UART1」と「MSP Debug Interface」というポートが追加されているはずです。
(私のパソコンでは、それぞれ「COM13」と「COM12」として認識されていますね。)
今回は、その内で「MSP Application UART1」の方に注目してください。
次に「TeraTerm」をご用意ください。
インストールしていない方は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのデバッグ)の「TeraTermの導入」の項目を参考にしてください。
もちろん、シリアル通信のターミナルであれば、他のものもお使いいただけます。
今回のTOPPERS/ASPのサンプルプログラムは、シリアル通信のメッセージを出力しますので、先程「MSP Application UART1」として認識されたシリアルポート番号でターミナルを立ち上げておきましょう。
設定は、こんな感じです。
ボーレートは「9600」です。
(私のパソコンは、「MSP Application UART1」をCOM13として認識していました。)
さて、Code Composer Studioに戻りましょう。
まだサンプルプログラムをビルドしていない場合は、画面右側の「Build Targets」タブの中、「OBJ」ディレクトリ直下の「all」をダブルクリックして、ビルドを完了させましょう。
次にデバッガの設定を行います。
画面上部にある緑色の「虫マーク」。
その脇に「▼」ボタンがありますので、それをクリック。
そこで現れた「Debug Configurations...」という項目をクリックしましょう。
すると以下のようなダイアログが現れます。
左側のリストから「Code Composer Studio - Device Debugging」という項目をダブルクリックしてください。
まずは上部の「Name:」の部分に、このデバッグ設定の分かりやすい名前を付けてあげましょう。
(例では「OBJ」としています。)
続いて「Use default target configuration」のチェックボックスをクリックしてチェック状態にします。
それと同時に中央のリストボックスに「MSP430」というチェックボックスがチェック状態で表示されることを確認しておいてください。
さて、お次は現在の「Main」タブから「Program」タブへ切り替えます。
クリックです。
まずは、プロジェクトを指定します。
「Project」テキストボックスの右端の「Workspace...」ボタンをクリックします。
以下のようなダイアログが表示されますので、これから実機に転送するプログラムのプロジェクトを選択します。
今回の場合は、この記事の通りに作業いただいた場合は「asp_1.9.2」(もし他の名称でプロジェクトを作成した方は、そのプロジェクト名)一つしか無いはずですので、これをクリックした後「OK」ボタンをクリックします。
次に、実機に転送するプログラムを指定します。
「Program」テキストボックスの右端の「File System...」ボタンをクリックします。
以下のように、ファイル選択ダイアログが開きますので、プログラムが保存されている場所に移動しましょう。
これまで、この記事の通りに作業いただいた場合は以下のパスにあるはず…
C:\cygwin64\home\<ユーザ名>\asp_1.9.2\OBJ
…って、無いじゃん!
そう、ファイル選択ダイアログで上記のパスに移動しても「targetConfigs」ディレクトリ以外は、デフォルトでは何も表示されないのです。
なので、ダイアログ右下の「Program Files」のドロップダウンリストをクリックしてください。
そうすると色々なファイルが表示されるようになります。
この中で「asp.exe」というのが、ビルドして今回実機に転送したいプログラムの実体なのですが、拡張子が「.exe」と特殊なので、デフォルトのフィルタに引っかからなくて表示されなかっただけなんです。
実はこの「asp.exe」、拡張子こそ「.exe」ですが、中身はまんま「.elf」ファイルです。
もし「asp.exe」が見つからない場合は、まだビルドされていない可能性が考えられますので、再度ビルド作業を行なってください。
見つかった場合は「asp.exe」を選択して「開く」ボタンをクリックします。
さて、以上で設定は終わりです。
ダイアログ下部の「Apply」ボタン、「Debug」ボタンの順にクリックするとデバッガが起動します。
以下のような表示が出ることがあります。
気にせずに「Proceed」ボタンをクリックしてください。
毎度出てきて鬱陶しい!と思う方は「Always launch without asking」チェックボックスにチェックを入れちゃってください。
もう二度と聞かれなくなります。
プログラムの転送と書き込みが完了すると、以下のような画面の状態になるはずです。
「View Disassembly...」というボタンをクリックしてみましょう。
左側に「Disassembly」タブが追加され、アセンブラのリストが表示されます。
そして、どうやら004400というアドレスでプログラムが停止しているようですね。
これで良いんです!
004400というのはMSP430マイコンのスタートアップアドレスです。
ターゲットである「MSP-EXP430F5529LP」評価ボードに「asp.exe」というプログラムが転送され、それが書き込まれた後にリセットが発生し、それによって現在004400番地で処理が停まっている様子がコレです。
さて、この状態から実際にプログラムを続行させてみましょう。
画面上部の「▶」ボタンをクリックすると、プログラムが続行されます。
はい、ここで長らく放置していた「TeraTerm」を見てみましょう。
以下のように、サンプルプログラムが動作していることが確認できます。
(…ん?ちょっと出力に違和感あるよ?という方は、後ほどコチラを御覧ください)
プログラムを停止する場合は、画面上部の「■」ボタンをクリックします。
停止させてみましょう。
ブレークポイントを仕掛けましょう。
画面右の「Project Explorer」のソースコードリストの中から「sample1.c」をダブルクリックし、ソースコードを表示します。
このソースコードの丁度中盤くらい、メインタスクの始めに仕掛けましょうか。
ブレークポイントは、ソースコードビューの左端をダブルクリックすると丸が表示され、セットできる…って思うでしょう?
ところが、このCode Composer Studioでは通用しないようです。
ブレークポイントを仕掛けるには、ソースコードビューの左端を右クリックして出てきたメニューの「Brakepoint(Code Composer Studio)」→「Brakepoint」を順にクリックしなければいけません。
すると、以下のように該当のソースコードの左端に丸マークが表示されて、ブレークポイントが設定されたことが分かります。
と同時に「Brakepoint」タブが画面上部に出現し、該当のソースコードがリストアップされます。
めんどくさ…。
因みに、普通にソースコードビューの左端をダブルクリックしてブレークポイントを設定しようとすると、丸マークも正しく表示されて一見問題ないように見えますが…。
実際にデバッグしてみると、見事に空振りするので注意です。
ともあれ、これで本当にブレークポイントがかかるのか、試してみましょう。
画面上部にある緑色の「虫マーク」。
(ほんとコレ、何虫がモデルなんだ?…カメムシ?)
その脇に「▼」ボタンがありますので、それをクリック。
すると今後は、さっき色々と入力した「OBJ」のデバッグ設定が登録されていますので、これをクリックすると、デバッガが起動します。
しばらくして、プログラムの転送と書き込みが完了すると、前と同じように004400番地でプログラムが停止しますので、画面上部の「▶」ボタンをクリックして、プログラムを続行させます。
程なくして、以下のように正しくブレークポイントを仕掛けた位置でプログラムが停止するはずです。
ここからは、「F6」キーでステップオーバー、「F5」キーでステップインなど、おなじみの操作が使用できます。
因みに、ステップオーバーやステップインなどを行っている時に命令が飛んでしまったり前後したりする場合は、最適化のせいです。
デバッグ時は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのデバッグ)の「サンプルプログラムのデバッグ」の項目を参考に最適化を解除しましょう。
サンプルプロジェクトの説明
興味のある方は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトで遊ぼう)を参照してください。
MSP430版カーネルについて
以下、このカーネルにおける備考です。
割り込み優先度の設定不可
このカーネルでは、割り込み優先度の設定はできません。
コンフィグレーションファイルなどにおいて、他のアーキテクチャからの移植性を考慮して、-1(優先度最低)から-6(優先度最高)を設定してもエラーが起きないようになっていますが、実際の動作に反映しません。
これはMSP430に搭載されている割り込みコントローラーがシンプルな設計であり、割り込み優先度を変更する機能が存在しないためです。
MSP430における割り込み優先度は、割り込み番号が大きいほど優先度が高くなるように固定されています。
当然「System Reset」が最優先ですが、マスカブル(マスクできる割り込み)ではアナログ電圧コンパレータの「Comp_B」の割り込み優先度が高いですね。
割り込み番号の定義は「..\arch\msp430x_gcc\include_gcc\msp430f5529.h」にあり、以下の通りです。
上の表と上下逆ですが一致するでしょう?
/************************************************************
* Interrupt Vectors (offset from 0xFF80)
************************************************************/
#define RTC_VECTOR (42) /* 0xFFD2 RTC */
#define PORT2_VECTOR (43) /* 0xFFD4 Port 2 */
#define TIMER2_A1_VECTOR (44) /* 0xFFD6 Timer2_A5 CC1-4, TA */
#define TIMER2_A0_VECTOR (45) /* 0xFFD8 Timer2_A5 CC0 */
#define USCI_B1_VECTOR (46) /* 0xFFDA USCI B1 Receive/Transmit */
#define USCI_A1_VECTOR (47) /* 0xFFDC USCI A1 Receive/Transmit */
#define PORT1_VECTOR (48) /* 0xFFDE Port 1 */
#define TIMER1_A1_VECTOR (49) /* 0xFFE0 Timer1_A3 CC1-2, TA1 */
#define TIMER1_A0_VECTOR (50) /* 0xFFE2 Timer1_A3 CC0 */
#define DMA_VECTOR (51) /* 0xFFE4 DMA */
#define USB_UBM_VECTOR (52) /* 0xFFE6 USB Timer / cable event / USB reset */
#define TIMER0_A1_VECTOR (53) /* 0xFFE8 Timer0_A5 CC1-4, TA */
#define TIMER0_A0_VECTOR (54) /* 0xFFEA Timer0_A5 CC0 */
#define ADC12_VECTOR (55) /* 0xFFEC ADC */
#define USCI_B0_VECTOR (56) /* 0xFFEE USCI B0 Receive/Transmit */
#define USCI_A0_VECTOR (57) /* 0xFFF0 USCI A0 Receive/Transmit */
#define WDT_VECTOR (58) /* 0xFFF2 Watchdog Timer */
#define TIMER0_B1_VECTOR (59) /* 0xFFF4 Timer0_B7 CC1-6, TB */
#define TIMER0_B0_VECTOR (60) /* 0xFFF6 Timer0_B7 CC0 */
#define COMP_B_VECTOR (61) /* 0xFFF8 Comparator B */
#define UNMI_VECTOR (62) /* 0xFFFA User Non-maskable */
#define SYSNMI_VECTOR (63) /* 0xFFFC System Non-maskable */
#define RESET_VECTOR ("reset") /* 0xFFFE Reset [Highest Priority] */
割り込み番号の指定方法
たとえば、「CFG_INT」などで割り込み番号を指定する場合は、上記の割り込み番号の定義から-1した値を入れてください。
例としては、OSタイマーの「..\target\msp_exp430f5529lp_gcc\target_timer.h」が分かり易いでしょうか。
OSタイマーは「TIMER0_A0_VECTOR」を使っているのですが、以下のように-1しています。
ここで定義された「INTNO_TIMER」が「..\target\msp_exp430f5529lp_gcc\target_timer.cfg」によって、コンフィグレーションとして使われているのです。
/*
* タイマ割込みハンドラ登録のための定数
*/
#define INHNO_TIMER (TIMER0_A0_VECTOR - 1) /* 割込みハンドラ番号 */
#define INTNO_TIMER (TIMER0_A0_VECTOR - 1) /* 割込み番号 */
#define INTPRI_TIMER (-6) /* 割込み優先度 */
#define INTATR_TIMER TA_EDGE /* 割込み属性 */
多重割り込みには未対応
デフォルトでは、割り込みハンドラやタスクコンテキスト以外のプログラムのための(非タスクコンテキスト用)スタック領域は、0x200(512バイト)としています。
これは「..\target\msp_exp430f5529lp_gcc\target_config.h」の以下の箇所で「DEFAULT_ISTKSZ」という名前で定義されています。
/*
* デフォルトの非タスクコンテキスト用のスタック領域の定義
*/
#define DEFAULT_ISTKSZ 0x200U
#define DEFAULT_ISTK (void *)(0x00004400U - DEFAULT_ISTKSZ)
このスタックサイズは、今回使った評価ボード「MSP-EXP430F5529LP」に搭載されている「MSP430F5529」チップのRAMのサイズがわずか8KBであることを考えれば、妥当と考えています。
しかし、これにより多重割り込みのサポートを諦めています。
0x200(512バイト)というスタックサイズでは、割り込みをネストするのには十分ではなく、あっという間に暴走してしまう危険性が高くなりますので、そのリスクを避けました。
もっとも、多重割り込みが必要なほどの処理がシビアなアプリケーションには、このターゲットは使われないだろうと判断した結果です。
例外ハンドラは未対応
コンフィグレーションファイルなどにおいて、他のアーキテクチャからの移植性を考慮して、例外ハンドラの作成はできるようになっているものの動作はしません。
理由はMSP430に例外処理が存在しないためです。
一部サービスコールは未対応
割り込みIDを指定して、これを有効/無効化するための「ena_int()」と「dis_int()」サービスコールはサポートしていません。
これはMSP430に搭載されている割り込みコントローラーがシンプルな設計であり、割り込み要因ごとに有効/無効化するためのフラグを設けていないためです。
どうしても一時的に割り込みを有効/無効化したい場合は、各ペリフェラルのレジスタを設定するか、CPU全体の割り込みを一括で設定しても良いのであれば、以下のような処理で代用してください。
/* すべての割込みの禁止 */
Asm("nop");
Asm("dint");
Asm("nop");
/* すべての割込みの許可 */
Asm("nop");
Asm("eint");
Asm("nop");
または、以下のようなマクロが使えますが、その場合はこれを使用するソースに「#include 」を一行加えてあげてください。
_disable_interrupts(); /* すべての割込みの禁止 */
_enable_interrupts(); /* すべての割込みの許可 */
また、性能評価用システム時刻取得のための「get_utm()」サービスコールは未実装です。
内蔵フラッシュROMのメモリマップ
この「MSP430F5529」というモデル、フラッシュメモリのマッピングが変です。
というよりMSP430シリーズの中で内蔵フラッシュが60KB以上の型番は、ちょっと癖があります。
内蔵フラッシュのメモリマップを以下に示します。
内蔵フラッシュ領域の中盤にベクタテーブル(VECTORS)が配置されています。
そして、このベクタテーブルは固定されており自由に移動させることができません。
すなわち、これはベクタテーブルのせいで、読み取り専用データセクション(.rodata)やプログラムコードのためのテキストセクション(.text)に使用するための領域が上下2つに分断されていることを意味します。
で、これら3つの領域の総和である128KBが「MSP430F5529」の内蔵フラッシュの容量ですよ~と言っているわけです。
これは「../target/msp430f5529.ld」のリンカスクリプトでも確認できます。
MEMORY {
SFR : ORIGIN = 0x0000, LENGTH = 0x0010 /* END=0x0010, size 16 */
BSL : ORIGIN = 0x1000, LENGTH = 0x0800
RAM : ORIGIN = 0x2400, LENGTH = 0x2000 /* END=0x43FF, size 8192 */
USBRAM : ORIGIN = 0x1C00, LENGTH = 0x0800
INFOMEM : ORIGIN = 0x1800, LENGTH = 0x0200 /* END=0x19FF, size 512 as 4 128-byte segments */
INFOA : ORIGIN = 0x1980, LENGTH = 0x0080 /* END=0x19FF, size 128 */
INFOB : ORIGIN = 0x1900, LENGTH = 0x0080 /* END=0x197F, size 128 */
INFOC : ORIGIN = 0x1880, LENGTH = 0x0080 /* END=0x18FF, size 128 */
INFOD : ORIGIN = 0x1800, LENGTH = 0x0080 /* END=0x187F, size 128 */
ROM (rx) : ORIGIN = 0x4400, LENGTH = 0xBB80 /* END=0xFF7F, size 48000 */
VECTORS : ORIGIN = 0xFF80, LENGTH = 0x0080
HIROM (rx) : ORIGIN = 0x00010000, LENGTH = 0x00014400
}
今回のMSP430版カーネルは、テキストセクション(.text)をHIROM領域に(一般的に.rodataよりも.textの方が容量が大きくなるため、容量の大きいHIROMを選択)、読み取り専用データセクション(.rodata)をROM領域に配置するように設計しています。
HIROM領域に収まる程度のそれほど大きくないアプリケーションならば問題はありませんが、もし一杯になってしまったら?
当然、読み取り専用データセクション(.rodata)が格納されているROM領域に空きがあれば、その領域を使いたいですよね?
内蔵フラッシュ領域がリニアでない場合、こういう時に面倒くさいことになりますが、以下のようなテクニックでやり過ごしましょう。
仮に以下のような関数をアプリケーションに追加したいとします。
int8_t add(int8_t a, int8_t b)
{
return a + b;
}
でも、HIROM領域が一杯でこの関数が入らないので、これをROM領域に配置したいと考えます。
これはあくまで例ですので小さな関数ですが、もっと大きい関数でもやり方は同じです。
int8_t __attribute__ ((section (".subtext"))) add(int8_t a, int8_t b)
{
return a + b;
}
このように「__attribute__ ((section (".subtext")))」を関数名の前に追記してあげます。
この記述によって、この関数を「.subtext」というセクションに配置してください…ってリンカにお願いをすることになります。
では「.subtext」ってセクションはどっから出てきたのか?
それは「../target/msp430f5529.ld」のリンカスクリプトを参照してください。
SECTIONS
{
.handlers : {} > ROM
.rodata :
{
*(.rodata)
*(.rodata.*)
*(.eh_frame_hdr)
KEEP (*(.eh_frame))
} > ROM
.subtext : {} > ROM /* 「.subtext」はここで定義されています! */
__idata_start = . ;
.data : AT(__idata_start)
{
__data_start = . ;
*(.data)
*(.data*)
__data_end = .;
} > RAM
__idata_end = __idata_start + SIZEOF(.data) ;
.vectors : {} > VECTORS
.text :
{
*(.text)
*(.text.*) /* .text.libgcc */
_etext = . ;
} > HIROM
中盤辺りで「.subtext」セクションの定義を行っています。
これでビルドを行えば「add()」関数は、本来のHIROM領域ではなく、ROM領域に配置されることになります。
関数の呼び出し方は、ROM領域に配置されたからといって特に変わることはなく、通常通りに行えます。
面倒くさくて申し訳ありませんが、こんな感じでどーでっしゃろ?
LPM(ローパワーモード)への対応
さて、MSP430を使用する上で最も重要なのが低消費電力化です。
今回使用した「MSP430F5529」には、以下の通り「Active」、「LPM0」~「LPM4」まで全部で6種類の動作モードがあります。
(「LPM3.5」と「LPM4.5」については今回は割愛します。)
通常…ていうかフルパワーで動作している状態が「Active」であり、「LPMx」はxの数が多いほど低消費電力のローパワーモードとなります。
この表を読んでみると、CPUの中で動いている様々なクロックを「LPMx」の段階に応じて停止させることにより低消費電力化を実現していることが分かります。
今回使用した「MSP430F5529」とは違う型番のデータですが、MSP430の動作モードと消費電力の関係は以下のグラフで表されます。
(多分「MSP430F5529」は全体的にもっと電力を食う…。)
CPUの中で動いているクロックは、ざっくり3つあります。
●MCLK…CPUのコアを動作させるクロック
●SMCLK…周辺機器を動作させるクロック(高速)
●ACLK…周辺機器を動作させるクロック(低速)
さて、OSというものは一定の間隔で割り込みを受け取り、それを基準にディスパッチなどの処理を行っています。
この一定の間隔を生み出すために、CPUに内蔵されているタイマーなどの周辺機器を使用するのが一般的で、このMSP430版カーネルでも同様です。
タイマーの精度はリアルタイムOSそのものの精度に直結するため、それを駆動するソースクロックは、ある程度高速であることが求められます。
したがって、このMSP430版カーネルでは低速のACLKではなく、高速のSMCLKをソースクロックとするタイマーを使用しました。
その結果、MSP430版カーネルでは「LPM1」までしかローパワーモードを下げられないことになってしまいました。
上の動作モードの表をもう一度ご覧ください。
OSが使用するタイマーのソースクロックはSMCLKですから「LPM2」まで下げてしまうとタイマーが停まりカーネルが動かなくなってしまいます。
ならばタイマーのソースクロックをACLKに変更すれば「LPM3」まで下げられるのでは?
…実際やってみましたがACLKの周波数が遅すぎて(32.768kHz)精度に難がある結果となってしまいました。
またSMCLKはデバッグ用のシリアル通信でも使用しているため、これをACLKに置き換えた場合、9600bpsのボーレートでも動作が怪しくなります。
となれば、SMCLKは使わざるを得ず「LPM1」までで妥協するしかないか…。
したがって、このMSP430版カーネルではタスクが一つも動作していないアイドル状態の時には、ぼぼ「LPM1」の状態までに留まります。
(正確にはタイマーの割り込み処理の間だけ定期的に「Active」モードになる。)
しかし、カーネルを停めても良いのであれば手はありまぁす!
ここから更に低消費電力化を図ろうとするならば、アプリケーションに以下のインクルードと、任意の場所にコードを記述してください。
#include <msp430.h>
__bis_SR_register(LPM3_bits + GIE);
これによりCPUは即座に「LPM3」に移行します。
処理はこの行で停止し、当然カーネルも動きを停めます。
これ以降は、ACLKで動作する周辺機器からの割り込みか、そもそもクロックに依存しないGPIOなどからの割り込みが発生するまで「Active」には戻りません。
割り込みが発生して「Active」に戻れば次の行から処理は再開され、カーネルも動作を再開します。
ソースクロックをACLKに指定したRTCなどを動作させて、一定の時間毎に割り込みを発生させて起床するようなアプリケーションでは、このモードが有効です。
更に以下のコードでは「LPM4」に移行します。
#include <msp430.h>
__bis_SR_register(LPM4_bits + GIE);
「LPM4」ではACLKすらも停止しますので、実質的にクロックに依存しないGPIOなどからの割り込みでなければ復帰しません。
GPIOに繋がれたスイッチを押すと起床するようなアプリケーションでは、このモードが有効です。
「LPM1」よりも更に低消費電力化が必要な場合は、カーネルは停まってしまいますが、上記の方法をお試しください。
ライセンスについて
このカーネルは「TOPPERSライセンス」で配布しております。
無償ですが、使用に関しては自己責任です。
このカーネルを商用利用するもの好きな方場合は、このリンク先の条項に従ってください。