※この記事は、筆者自身のブログに連載していたものを読みやすく1ページにまとめたダイジェスト版です。無断転載などではありませんのでご了承ください。
概要
オリジナル「nX-U16/100」コアの16bit RISCマイコンです。
かつてはローム株式会社が開発・販売しており、同じロームグループのラピステクノロジー社に移管されました。
このマイコンの一番の特徴は耐ノイズ性にあり、そのスジでは結構有名です。
次いで、低消費電力。
イメージ的には低消費電力を謳っているマイコンほど耐ノイズ性が劣る気がしますが、この「ML62Q1000」、これらを両立しているところにインパクトのある製品だと思います。
この特徴から家電などの民生分野に向いており、これからの時代に益々需要が増えるであろう、環境への耐性が求められるセンサーなどのIoTデバイスにも最適です。
ただ、いかんせんマイナーなアーキテクチャであることは否めなく、技術情報もネット上ではほとんど見かけません。
また、目ぼしいRTOSなども見つからなかったので、この「ML62Q1000」に「μITRON4.0」準拠のRTOS(リアルタイムOS)であるTOPPERS/ASPを移植してみました。
必要なもの
今回のターゲットとなる、ML62Q1000マイコンスタータキット「SK-BS01-D62Q1577TB」です。
ありがたいことにデバッガー「EASE1000 V2」も付いており、通販で買うことができます。
こちらであれば、最安値で26,000円くらいです。
趣味で買うにはキツイお値段ですね…。
私の場合は、たとえ仕事で使う可能性があっても確定的でない限り、こういうのを会社が絶対買ってくれないので自腹を切りましたが、あまり良いことではありませんね!
(それをやると、会社はソフトウェアの開発には金が要らないと錯覚して、益々ケチになる…。)
他の型番への移植も可能ですが、TOPPERS/ASPを搭載して動作させるならROM:128KB/RAM:8KB以上の容量を持つ型番を選びましょう。
そうなると実質的に「ML62Q1000」シリーズでも、ML62Q15xx、ML62Q16xx、ML62Q17xxなどのハイエンドの型番がターゲットになります。
このブログでは「SK-BS01-D62Q1577TB」を使用した場合の例を説明していきたいと思います。
ダウンロード/GitHub
ソースコードの入手は、こちらからどうぞ。
とは言っても、このソースコードをダウンロード、もしくは「git clone」しても、絶対にビルドが通りません。
このソースコードは未完成です。
なぜなら、ラピステクノロジー社のドライバを後から付け加える必要があるんです。
ラピステクノロジー社のドライバのライセンスの条項によれば、ソースコードの一切の再配布を認めていません。
そのため公開できるのは、それに抵触しない完全なオリジナル部分のみです。
そして、ラピステクノロジー社のドライバを触ることができるのは、上記のスタータキットを購入した方のみです。
ですので、今後この記事では、それらのソースコードの在り処やコピーする場所などを事細かに書いていくつもりです。
やや面倒ですが、お付き合いいただけると嬉しいです。
ビルドは、まだやらないでくださいね~。
ベンダーの提供するドライバなどのソフトウェアにあまり厳しいライセンスを課すと、ユーザーが気軽に試せないし、コミュニティが育たないので製品のシェアが伸びない気もするのですが…。
ただ、これらを公開してしまうとベンダー側のサポートの手間は確実に増えるので、それを懸念してライセンスを厳しくしているベンダーは少なからず存在します。
前回の「TOPPERS/ASP AVR32版」で取り上げた、Microchip社なんかもそうでしたね。
開発環境の構築
早速、開発環境を構築していきます。
ML62Q1000マイコンスタータキット「SK-BS01-D62Q1577TB」に同梱されているDVD-ROMをパソコンに挿入しましょう。
DVD-ROMは、以下のようなトップディレクトリになっていると思います。
以下の「ML62Q1000_MCU_StarterKit」というディレクトリをダブルクリックします。
次に「U8DevTool_R2_2_0.zip」という圧縮ファイルをパソコンの何処へでも良いのでコピーします。
※ファイル名は開発環境のバージョンによって異なる可能性があります。
コピーした「U8DevTool_R2_2_0.zip」を解凍すると、以下のようなディレクトリが展開されます。
この中の「Setup」ディレクトリをダブルクリックします。
移動したディレクトリの中の「U8DevInstaller.exe」ファイルをダブルクリックします。
コイツがML62Q1000マイコン開発環境のインストーラーです。
しばらくすると以下のようにインストーラーが開始されます。
ここは「次へ」ボタンをクリックしましょう。
お約束の使用許諾への同意の作業。
「使用許諾契約の条項に同意します」のラジオボタンを選択してから「次へ」ボタンをクリックです。
開発環境のインストール先の設定です。
特に理由がなければ、このままで行きましょう!
「次へ」ボタンをクリック。
セットアップの種類を聞かれます。
特に理由がなければ「標準」という表示をクリックしてください。
インストール作業が始まりました!
思いの外時間がかかりますが、気長に待ちましょう。
インストール作業中に以下のようなポップアップが表示されます。
2回位だったかな…?
おそらく、デバッガーか何かのデバイスドライバのインストールを許可してくれ~!って言ってます。
いずれも「インストール」ボタンをクリックです。
インストーラーが以下の表示になったら、ML62Q1000マイコン開発環境のインストールは終了です。
「完了」ボタンをクリックしてインストーラーを終了させましょう。
さて、インストールしたML62Q1000マイコン開発環境の環境変数の設定を行います。
開発環境は、インストーラーにより以下のディレクトリにセットアップされているはずです。
環境変数の設定方法は、このページ(TOPPERS/ASPのビルドからデバッグまで~GNUツールチェーンの導入)の「環境変数の設定」の項目を御覧ください。
ただし、パスは…
C:\Program Files (x86)\GNU Tools ARM Embedded\7 2017-q4-major\bin
…となっていて、1つだけ設定していますが、今回はそれに代えて以下の2つを設定するようにします。
※特に2つ目のパスは開発環境のバージョンによって異なる可能性があります。
C:\U8Dev\Bin
C:\U8Dev\BuildTools\V2_02_00\Bin
また、このページの「パスの確認」の項目で打ち込むコマンドも、以下のように変わります。
続きまして「Cygwin」のインストールを行います。
このページ(TOPPERS/ASPのビルドからデバッグまで~Cygwinの導入)を参考にしてください。
次に、ソースコードをゲットしちゃいましょう。
以下のコマンドでソースコードのクローンを行います。
$ git clone https://github.com/RyutaroMorita/asp_ml62q1000_u8dev.git
ダウンロードとGithub、いずれの場合も「asp_ml62q1000_u8dev」というディレクトリの名前を「asp_1.9.2」などと改名すると、上記のページと同じ状況になります。
さて、開発環境をインストールして、ソースコードもダウンロードしました。
早速ビルドを~!って思う気持ちはわかりますが、やめておきましょう。
どうせ、必ずビルドは失敗します。
なぜならば、ソースコードに色々加えなければならないからです。
その手順も追って説明いたしますので、ここはグッと我慢。
サンプルドライバのソースコードのコピー
ここで言う「サンプルドライバ」とは、いわゆるラピステクノロジー社純正のライブラリパッケージであり、これを使用するとCPUに内蔵されているペリフェラル(周辺機器)を簡単に利用することができるというものです。
今回の「TOPPERS/ASP ML62Q1000版」のカーネル内でも、割り込み、タイマーやシリアル通信ドライバなどは、このサンプルドライバを使用しています。
ところが、このサンプルドライバのソースコードのライセンスが原則公開禁止であるために再配布できません。
そのため「TOPPERS/ASP ML62Q1000版」のソースコードが不完全なものとなり、そのままではビルドが通らず、通すためには手動で不足分のソースコードをコピーしていただくという手間を強いることになってしまいました。
お手数をおかけして申し訳ない…。
では、そのサンプルドライバのソースコードを何処から入手すれば良いのか?
もう一度、ML62Q1000マイコンスタータキット「SK-BS01-D62Q1577TB」に同梱されているDVD-ROMのトップディレクトリから「ML62Q1000_MCU_StarterKit」というディレクトリをダブルクリックします。
すると、以下のようなディレクトリになってると思います。
更に「MCU_SampleProgram_v200.zip」という圧縮ファイルをパソコンの何処へでも良いのでコピーします。
コピーした「MCU_SampleProgram_v200.zip」を解凍すると、以下のようなディレクトリが展開されます。
この中の「Software_LEXIDE」ディレクトリをダブルクリックします。
移動したディレクトリの中の「driver」ディレクトリ、この中にサンプルドライバのソースコードがギッシリ入っています!
この「driver」ディレクトリをTOPPERS/ASPのソースツリーの以下に示すのパスの直下に丸ごとコピーしましょう。
(「asp_ml62q1000_u8dev」や「asp_ml62q1000_u8dev_master」を「asp_1.9.2」に改名した場合。)
C:\cygwin64\home\morita\asp_1.9.2\arch\xn_u16_100_u8dev
これで、サンプルドライバのコピーは完了です。
ここまでは簡単ですが、面倒なのはこの次…。
スタートアップファイル「start.asm」のコピーと修正
ターゲットに電源が入った後、いの一番に実行されるアセンブラのソースコード「start.asm」を作成します。
一から書くのは大変なので、既に用意されているものをベースに作成しましょう。
元となるソースコードは、「ML621577.ASM」という名前で以下のパスに配置されています。
ターゲットCPUの型番が名前になってます。
似たような型番があるので間違えないようにしてください。
この「ML621577.ASM」を以下のディレクトリにコピーします。
C:\cygwin64\home\morita\asp_1.9.2\target\rb_d62q1577tb100_u8dev
ついでに、今コピーした「ML621577.ASM」を「start.asm」に改名しておきましょう。
続きまして、改名した「start.asm」をテキストエディターなどで開き、以下の部分を修正します。
元の「ML621577.ASM」で言うところの14行目付近からの…
...
model large
romwindow 0, 0afffh
extrn code: _main
extrn data near: _$$SP
public $$start_up
...
…という部分を以下のように修正します。
...
model large
romwindow 0, 0afffh
; extrn code: _main ; コメントアウト!
extrn code: _sta_ker ; 追記!
extrn data near: _$$SP
public $$start_up
...
アセンブラソースにおいて「;」はコメントを意味します。
これは、普通のファームウェアが「main()」関数から始まるのに対し、TOPPERS/ASPカーネルを使用する場合は「sta_ker()」という関数から始まるため、このファイルの外にある「sta_ker()」関数を使用するための宣言です。
実際に「sta_ker()」関数へジャンプする部分は、この後実装します。
さて、次の修正です。
21行目付近からの…
...
cseg at 0:0h
dw offset _$$SP
cseg at 0:4h
dw $$brk_reset
...
…という部分を以下のように修正します。
...
cseg at 0:0h
dw offset _$$SP
cseg at 0:2h ; 追記!
dw $$NCODml621577lw ; 追記!
cseg at 0:4h
dw $$brk_reset
...
これは、外部リセットの際のベクタを追加しています。
これを省くと、デバッガが使えなくなっちゃうので要注意です。
さてさて、お次は…。
204行目付近からの…
...
;---------------------------------------------------------------
; far jump to main routine
;---------------------------------------------------------------
b _main
...
…という部分を以下のように修正します。
...
;---------------------------------------------------------------
; far jump to main routine
;---------------------------------------------------------------
; b _main ; コメントアウト!
b _sta_ker ; 追記!
...
これが前述した「main()」関数の代わりに、実際に「sta_ker()」関数へジャンプする部分となります。
更に更に…。
250行目付近からの…
...
cseg #03 at 0ffd0h ; address
dw 0fffdh ; 0ffd0h
...
…という部分を以下のように修正します。
...
cseg #03 at 0ffd0h ; address
; dw 0fffdh ; コメントアウト!
; 0ffd0h
dw 0fff8h ; 追記!
; コードオプション0(CODEOP0)に該当する.
; ウォッチドッグ関連ビット(WDTNMCK,WDTSPMD,WDTMD)を全て0に設定する.
; ウォッチドッグを使用する場合は適切な値に設定すること.
...
これはアドレス「0ffd0h」という場所に「0fffdh」という値に替えて「0fff8h」という値を配置しています。
プログラムメモリ空間の「0ffd0h」というアドレスは「CODEOP0」というコードオプション領域に該当します。
コードオプションというのは、リセットが掛かるとマイコンが自動的に読みに来るパラメーターのことであり、CPUの動作モードやウォッチドッグなどの基本的な設定を書いておく領域のことです。
上記の例では、このコードオプション「CODEOP0」に対し、ウォッチドッグ機能を無効化するように設定しています。
こうしておけばリセット後のマイコンは、ウォッチドッグ機能が無効化された状態で動作を開始するようになります。
コードオプションの設定はもう一箇所!
「CODEOP0」のすぐ下、253行面付近からの…
...
cseg #03 at 0ffd2h ; address
dw 0ffffh ; 0ffd2h
...
…という部分を以下のように修正します。
...
cseg #03 at 0ffd2h ; address
; dw 0ffffh ; コメントアウト!
; 0ffd2h
dw 0fffdh ; 追記!
; コードオプション1(CODEOP1)に該当する.
; CPUの動作モードを「ウェイトモード」に設定する
...
これはアドレス「0ffd2h」という場所に「0ffffh」という値に替えて「0fffdh」という値を配置しています。
プログラムメモリ空間の「0ffd2h」というアドレスは「CODEOP1」というコードオプション領域に該当します。
上記の例では、このコードオプション「CODEOP1」に対し、CPUの動作モードを「ウェイトモード」に設定しています。
ML62Q1000マイコンには「ノーウェイトモード」と「ウェイトモード」の二種類があります。
前者が初期値です。
二つのモードの違いは、マイコンのデータシートを熟読していただく必要がありますが、今回は「ウェイトモード」を使用することとします。
以上で「start.asm」の修正は終わりです。
修正が終わったら、忘れずに「start.asm」を保存してください。
コマンドラインでのビルド
さて、これで全ての準備は整いました。
お疲れ様でした~!!
早速ビルドしてみましょう。
Cygwinを開いて、TOPPERS/ASPソースツリーの場所まで移動しましょう。
$ cd asp_1.9.2/
次にその直下の「OBJ」ディレクトリに移動します。
$ cd OBJ/
コンフィギュレーターのパーミッションを実行可能に設定します。
$ chmod 755 ../cfg/cfg/cfg.exe
ラピステクノロジー社のアセンブラである「rasu8」が出力した「.prn」ファイルから依存するファイルを書き出す「makedepu8.exe」という自作ユーティリティのパーミッションを実行可能に設定します。
$ chmod 755 ../arch/xn_u16_100_u8dev/utils/makedepu8.exe
ラピステクノロジー社のリンカである「rlu8」が出力した「.map」ファイルからシンボル情報ファイル「.syms」を生成する「nmu8.exe」という自作ユーティリティのパーミッションを実行可能に設定します。
$ chmod 755 ../arch/xn_u16_100_u8dev/utils/nmu8.exe
自作ユーティリティの「makedepu8.exe」も「nmu8.exe」も、ラピステクノロジー社のアセンブラやリンカが更新されて出力形式が変わってしまえば、正常に動かなくなるかもしれません。
可能性は低いですが、その際に修正できるように、それぞれのソースコードも「exe」と同じディレクトリに置いておきますね。
その場合は「../arch/xn_u16_100_u8dev/utils/」ディレクトリに移動して、以下のようなコマンドを打てば、コンパイルできます。
「makedepu8.exe」を作る場合は…
$ gcc -o makedepu8.exe makedepu8.c
「nmu8.exe」を作る場合は…
$ gcc -o nmu8.exe nmu8.c
そうしたら、プロジェクトのコンフィグファイル(sample1.cfg)の情報を元に、OSに必要な定義を記したソースコード(「kernel_cfg.c」と「kernel_cfg.h」)を生成します。
$ make depend
以下のような表示にならずエラーが出力される場合は、残念ながらこれまでの作業に誤りがあります。
お手数ですが、最初からご確認を!
ここまで上手くいったら、ホンチャンのビルド。
以下のコマンドを実行します。
$ make all
プロジェクトの作成
ML62Q1000マイコン用の開発環境の構築が完了していれば、統合開発環境(IDE)もインストール済みのはずです。
ラピステクノロジー社のIDEは「LEXIDE-U16」といいます。
このプログラムの場所は、これまで記事の記述通りに作業していただいた場合は、以下のパスに配置されています。
なので、これをダブルクリックでIDEが起動します。
C:\U8Dev\eclipse\lexideu16.exe
すると、以下のようなスプラッシュスクリーンが現れます。
あらやだカッコいい!
しばらくして以下のポップアップが表示されます。
ワークスペースの場所を問われているのですが、特に理由がない限り、そのままで「Launch」ボタンをクリックしましょう。
ここで気付かれた方も多い(てゆうか、配置されているディレクトリの名前でバレバレ)と思いますが、この「LEXIDE-U16」、Eclipseベースですね!
しばらくすると、まっさらな状態のIDEが立ち上がります。
さて、先程「Cygwin」のターミナルで行っていたTOPPERS/ASPのビルド作業をこのIDE上で行えるようにプロジェクトを作っていきましょう。
まずは「LEXIDE-U16」上部の「File」メニューから「New」をクリックし、「Makefile Project with Existing Code」をクリックします。
「New Project」ダイアログが表示されます。
ここでは、各項目を以下の通りに入力、設定し、ダイアログ右下の「Finish」をクリックします。
Project Name:<任意のプロジェクト名(ここでは「asp_1.9.2」)>
Existing Code Location:C:\cygwin64\home\<ユーザ名>\asp_1.9.2
Toolchain for Indexer Settings:<none>
「LEXIDE-U16」の画面左側の「Project Explorer」タブに<プロジェクト名>のディレクトリが表示され、その下に「asp_1.9.2」以下のディレクトリ構造が表示されていることを確認します。
プロジェクトのクリーンとビルド
「LEXIDE-U16」から「asp_1.9.2」プロジェクトをビルド/クリーンします。
「LEXIDE-U16」の画面右側の「Outline」タブを「Build Target」タブに切り替えます。
すると、「Project Explorer」タブと同じように「Build Target」タブに「asp_1.9.2」ディレクトリ構造が表示されます。
このツリーリストから「OBJ」を選択し、「New Build Target」ボタン(ツリーリスト上方の◎と+が合わさったようなアイコン)をクリックします。
「Create Build Target」ダイアログが表示されます。
まずは、プロジェクトのクリーンを行うMakeターゲットを作成します。
ここでは、各項目を以下の通りに入力し、ダイアログ下方の「OK」をクリックします。
すると、「Build Target」タブのツリーリストの「OBJ」ディレクトリ以下に「realclean」が追加されます。
次は、これをダブルクリックします。
「LEXIDE-U16」の画面下方の「Console」タブには、プロジェクトのクリーンが行われたことを示す表示が現れます。
これは、Cygwin上で「OBJ」ディレクトリの中で「$ make realclean」を実行したのと同じ動作をしたことを意味します。
同じ要領で、「depend」と「all」のMakeターゲットも作成します。
今後「OBJ」プロジェクトをビルドするときは「depend」、「all」の順に、クリーンするときは「realclean」のMakeターゲットをダブルクリックすれば良いことになります。
さて、もう一仕事!
今までと同じ要領で、もう一個Makeターゲットを作成してください。
まず「Create Build Target」ダイアログを開いたら「Target name」に「_debug」と入力してください。
頭のアンダーバーがポイント!
次に、今入力したテキストボックスの直ぐ下、「Same as the target name」のチェックボックスをクリックして、チェックを解除します。
「Same as the target name」のチェックボックスを解除すると、その下の「Build target」テキストボックスが入力可能となります。
ここには「_debug」と入力されていますが、これの頭のアンダーバーを取って、ただの「debug」に変更しましょう。
その後、ダイアログ下方の「OK」をクリックします。
すると、「Build Target」タブのツリーリストの「OBJ」ディレクトリ以下に他のものより一番上に「_debug」が追加されます。
なぜ、「debug」のMakeターゲット名の頭にアンダーバーを付けたのか?
これは、ビルドやクリーンじゃなくてデバッガを起動するためのランチャーです。
実際のデバッガの起動方法や使い方は後ほど説明しますが、「_debug」ではなく「debug」という名前にしてしまうと、「Build Target」タブにおいて、すでに存在しているMakeターゲットの「depend」の直ぐ上に「debug」が表示(アルファベット順でソートされるから)されてしまい、これがかなりミスを誘うからです。
そんなのミスるのはオマエだけやろ!
…と思われる方は、そのまま「debug」でも別に良いですが、「depend」しようと思って、うっかり「debug」をダブルクリックしてしまい、デバッガの起動を待たされた上に「プログラムが無い」などとエラー表示されるのは相当イラッとくるので、このやり方をオススメしますよ~。
デバッガとターゲットの配線
デバッガの「EASE1000 V2」とターゲットの「SK-BS01-D62Q1577TB」の間で、こんな感じの配線をします。
まずは「SK-BS01-D62Q1577TB」にピンヘッダを取り付けます。
ここで、まず注意事項!
「SK-BS01-D62Q1577TB」のピンヘッダ用のランド(穴)が小さいので、よく使うサイズのものは使えません。
例えば、秋月電子さんで言うところの「細ピンヘッダ」を用意する必要があります。
以下、普通のものと、この「細ピンヘッダ」の比較の写真です。
上の青いのが噂の「細ピンヘッダ」です。
「細ピンヘッダ」は一列のものしか売ってなかったので、2本ずつ使ってハンダ付けしました。
デバッガの「EASE1000 V2」とターゲットの「SK-BS01-D62Q1577TB」との接続は、普通に基板左側の14ピンヘッダに専用のコネクタを接続して終わりっと…。
プログラムの転送とデバッグ
これからTOPPERS/ASPのサンプルプログラムを動かす際には、動作確認のためにどうしてもシリアルポートが必要です。
そこで、以下のような市販のUSB/シリアル通信変換ケーブルを用意します。
シリアル通信をするために必要なポートは、RXDとTXDとGNDの三本ですね。
ターゲット基板上の先程取り付けた細ピンヘッダから取りましょう。
P02(SU0_RXD0)ピンはコネクタCN1の19ピン、P03(SU0_TXD0)ピンはコネクタCN1の20ピンから取ります。
GNDは適当に…。
回路図を貼り付けたほうが良いのですが、ドライバと同様に守秘義務があって掲載できないかもしれません。
ご不便をお掛けします。
RXDとTXDは、「J11」のシルク印刷の真上くらいです。
評価ボードからこうやってGNDとRXDとTXDと、それぞれの線を出してやって…
USB/シリアル通信変換ケーブル側の配線は、上からTXD、RXD、GNDの順番でこんな感じ。
これでシリアルポートが使えるようになりました。
続いて、このUSB/シリアル通信変換ケーブルをパソコンに繋いでみましょう。
パソコン上でデバイスマネージャーを開きます。
ポート(COMとLPT)のサブカテゴリーとして「USB Serial Port」というポートが追加されているはずです。
(私のパソコンでは、「COM15」として認識されていますね。)
このポート番号、覚えておいて下さい。
ここで、デバッガとパソコンをUSBケーブルで繋げましょう。
ターゲットへの電源は、デバッガのコネクタから供給されます。
これは親切設計!
ご覧の通り、通電します。
次に「TeraTerm」をご用意ください。
インストールしていない方は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのデバッグ)の「TeraTermの導入」の項目を参考にしてください。
もちろん、シリアル通信のターミナルであれば、他のものもお使いいただけます。
今回のTOPPERS/ASPのサンプルプログラムは、シリアル通信のメッセージを出力しますので、先程「USB Serial Port」として認識されたシリアルポート番号でターミナルを立ち上げておきましょう。
設定は、こんな感じです。
ボーレートは「9600」です。
(私のパソコンは、USB/シリアル通信変換ケーブルをCOM15として認識していました。)
さて、「LEXIDE-U16」に戻りましょう。
まだサンプルプログラムをビルドしていない場合は、画面右側の「Build Target」タブの中、「OBJ」ディレクトリ直下の「all」をダブルクリックして、ビルドを完了させましょう。
次にデバッガを起動します。
画面右側の「Build Target」タブの中、「OBJ」ディレクトリ直下の「_debug」をダブルクリックです!
しばらくすると「ターゲット設定」というダイアログが表示されます。
これを以下のように設定し、ダイアログ下部の「OK」ボタンをクリックします。
カテゴリ:ML62Q1000
グループ:ML62Q1500
LSI:ML621577
ターゲットICE:On Chip Emulator
以下のようなポップアップが表示されますので、ここでも「OK」ボタンをクリックしてください。
以下のような画面が表示されましたか?
これが「DTU8」というデバッガ・アプリケーションです。
では、このアプリケーションを使って、ビルドしたサンプルプログラムをターゲットに転送しましょう!
DTU8の画面上部に並んでいるボタンの中から「プログラムファイルの読み込み」ボタンをクリックします。
フォルダーみたいなアイコンが3つ並んでいるうちの真ん中のヤツです。
すると「プログラムファイルの読み込み」ダイアログが現れます。
これを使って、ビルドしたプログラムファイル「asp.abs」を選択して「OK」ボタンをクリックします。
この記事通りに作業いただいた場合、「asp.abs」は、以下のディレクトリに生成されています。
C:\cygwin64\home\<ユーザー名>\asp_1.9.2\OBJ
しばらくアプリケーションがプログラムファイルをロードする間にワチャワチャしますが、それが終わると、DTU8は以下のような表示になると思います。
これは、ターゲットへ転送したプログラムが、現在スタートアップ・アドレスで停止していることを意味します。
ここからプログラムを続行してみましょう。
DTU8の画面上部に並んでいるボタンの中から「プログラム実行」ボタンをクリックします。
はい、ここで長らく放置していた「TeraTerm」を見てみましょう。
以下のように、サンプルプログラムが動作していることが確認できます。
プログラムを停止する場合は、DTU8の画面上部に並んでいるボタンの中から「強制ブレーク」ボタンをクリックします。
停止させてみましょう。
ブレークポイントを仕掛けましょう。
DTU8の「ファイル」メニューから、「ソースファイルの選択」をクリックします。
「表示ファイルの切り替え」ダイアログが表示されます。
このダイアログの左側の「ユニット」リストの中から「sample1.c」を選択し「OK」ボタンをクリックしてください。
これにより、「表示ファイルの切り替え」ダイアログの後ろのDTU8に「sample1.c」のソースファイルが表示されたはずです。
先程プログラムを停止した際に、タイミング良く「sample1.c」の中でブレークが掛かった場合は、元々表示されていたソースファイル表示と今回の作業で「sample1.c」が二枚表示となってしまいますが、まあまあ、ここはご勘弁を。
さて、「表示ファイルの切り替え」ダイアログには退場いただきましょう。
「キャンセル」ボタンをクリックです。
新たに表示された「sample1.c」、このソースコードの丁度中盤くらい、メインタスクの始めに仕掛けましょうか。
ブレークポイントは、ソースコード表示の左端付近の■(四角形)をクリックすることにより赤いマークが表示され、セットすることができます。
(解除したい場合も■をクリックします。赤いマークが消えます。)
これで本当にブレークポイントがかかるのか、試してみましょう。
今度は、DTU8の画面上部に並んでいるボタンの中から「リセット後に実行」ボタンをクリックします。
程なくして、以下のように正しくブレークポイントを仕掛けた位置でプログラムが停止するはずです。
ここからは、「F10」キーでステップオーバー、「F11」キーでステップインなど、おなじみの操作が使用できます。
因みに、ステップオーバーやステップインなどを行っている時に命令が飛んでしまったり前後したりする場合は、最適化のせいです。
デバッグ時は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトのデバッグ)の「サンプルプログラムのデバッグ」の項目を参考に最適化を解除しましょう。
少々古めかしい外観のDTU8ですが、質実剛健といった出で立ちで好感が持てます。
便利で豊富な機能を有していますので、添付のDVD-ROMの中のドキュメントに目を通しておくことをオススメしますよ~。
サンプルプロジェクトの説明
興味のある方は、このページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトで遊ぼう)を参照してください。
ML62Q1000版カーネルについて
以下、このカーネルにおける備考です。
OS上の割り込み優先度の扱い
このカーネルでは、割り込み優先度の設定はできません。
コンフィグレーションファイルなどにおいて、他のアーキテクチャからの移植性を考慮して、-1(優先度最低)から-6(優先度最高)を設定してもエラーが起きないようになっていますが、実際の動作に反映しません。
しかしながら、ML62Q1000に搭載されている割り込みコントローラーは、ちゃんと割り込み優先度を変更する機能を持っています。
だったら、対応しなさいよ!って言われちゃいそうですが、TOPPERS/ASP、および「μITRON4.0」の仕様に適合するカタチでの実装ができませんでした。
理由は以下の通りです。
少し小難しい話になってしまいますので、興味のない方は以下の太字の部分は読み飛ばしてください。
複雑なので、箇条書きにします。
○「μITRON4.0」は、OSの仕様として割り込み優先度の操作をサポートするために割り込みマスクを管理する必要がある。
○これを行うには、割り込みハンドラ内でその割り込みが起こった直前の割り込みマスクの値を参照できる必要がある。
○大概のCPUの場合、ステータスレジスタに割り込みマスクのビットが含まれる。
○大概のCPUの場合、割り込みが発生するとその直前のステータスレジスタの値がスタックに退避される。
○大概のCPUの場合、割り込みハンドラ内でその割り込みが起こった直前の割り込みマスクの値は、スタックに退避されたステータスレジスタの値から知ることができる。
○ところが、ML62Q1000の場合、ステータスレジスタ「PSW」に割り込みマスクのビットがそもそも含まれない。「ELEVEL」という、それらしいビットは存在するが、これは「エミュレータ専用」、「ノンマスカブル」、「ソフトウェア」、「マスカブル」という4種類の大雑把な割り込みレベルを示すものであって、ここで言う割り込みマスクとは意味が異なる。
○ML62Q1000の場合、ここで言う割り込みマスクに近いものは、割り込みコントローラー内の現割り込みレベル管理レジスタ、すなわち「CIL」レジスタである。
○しかし、この「CIL」レジスタの値は割り込み発生時にスタックには退避されない。
○よって、ハンドラ内では割り込みが起こった直前の割り込みマスクの値を回収できず、「μITRON4.0」の仕様に沿った形での割り込みマスク管理が完全には実装できない。
…う~ん、無念!
その代わり、裏技的に割り込み優先度を変更する方法を後ほど紹介します。
その裏技を使用しない場合、ML62Q1000における割り込み優先度は、割り込み番号が若いほど優先度が高くなるように固定されています。
割り込み番号の定義は「..\target\rb_d62q1577tb100_u8dev\target_sil.h」にあり、以下の通りです。
...
/*
* 「ML62Q1577」割込み番号(intno)の定義
*/
#define TINTNO_WDTINT 1U
//#define TINTNO_ 2U
#define TINTNO_VLS0INT 3U
//#define TINTNO_ 4U
#define TINTNO_EXI0INT 5U
#define TINTNO_EXI1INT 6U
#define TINTNO_EXI2INT 7U
#define TINTNO_EXI3INT 8U
#define TINTNO_EXI4INT 9U
#define TINTNO_EXI5INT 10U
#define TINTNO_EXI6INT 11U
#define TINTNO_EXI7INT 12U
#define TINTNO_CBUINT 13U
#define TINTNO_DMACINT 14U
#define TINTNO_MCSINT 15U
#define TINTNO_SIU00INT 16U
#define TINTNO_SIU01INT 17U
//#define TINTNO_ 18U
#define TINTNO_SADINT 19U
//#define TINTNO_ 20U
#define TINTNO_EXTXINT 21U
//#define TINTNO_ 22U
#define TINTNO_I2CM0INT 23U
#define TINTNO_I2CM1INT 24U
#define TINTNO_FTM0INT 25U
#define TINTNO_FTM1INT 26U
#define TINTNO_TM0INT 27U
#define TINTNO_TM1INT 28U
#define TINTNO_I2CU0INT 29U
#define TINTNO_SIU10INT 30U
#define TINTNO_SIU11INT 31U
//#define TINTNO_ 32U
#define TINTNO_FTM2INT 33U
#define TINTNO_FTM3INT 34U
#define TINTNO_TM2INT 35U
#define TINTNO_TM3INT 36U
#define TINTNO_SIU20INT 37U
#define TINTNO_SIU21INT 38U
#define TINTNO_CMP0INT 39U
#define TINTNO_CMP1INT 40U
#define TINTNO_FTM4INT 41U
#define TINTNO_FTM5INT 42U
#define TINTNO_TM4INT 43U
#define TINTNO_TM5INT 44U
#define TINTNO_SIU30INT 45U
#define TINTNO_SIU31INT 46U
#define TINTNO_SIU40INT 47U
#define TINTNO_SIU41INT 48U
#define TINTNO_FTM6INT 49U
#define TINTNO_FTM7INT 50U
#define TINTNO_TM6INT 51U
#define TINTNO_TM7INT 52U
#define TINTNO_SIU50INT 53U
#define TINTNO_SIU51INT 54U
#define TINTNO_LTB0INT 55U
//#define TINTNO _ 56U
#define TINTNO_LTB1INT 57U
#define TINTNO_LTB2INT 58U
#define TINTNO_RTCINT 59U
//#define TINTNO_ 60U
...
ソフトウェア割り込み
今回のTOPPERS/ASP ML62Q1000版においては、特別にサンプルプロジェクトにソフトウェア割り込みのサンプルコードを入れています。
サンプルプロジェクトの操作方法については前述したこのページ(TOPPERS/ASPのビルドからデバッグまで~サンプルプロジェクトで遊ぼう)を見ていただくとして、具体的には「i」を一文字ターミナルに対して入力すると、このソフトウェア割り込みが発生するようになっています。
「..\OBJ\sample1.c」の「main_task()」関数内を参照してください。
結構下の方、以下のソースコードに注目。
...
case 'i':
/*
* ソフトウェア割込み(ソフトウェア割込み10番を発生させる)
*/
#pragma ASM
swi #10
#pragma ENDASM
break;
...
こんな感じで「i」の一文字をターミナルから入力された場合の処理を追記しています。
実際にソフトウェア割り込みを発生させているのは「swi #10」というインライン・アセンブラの命令です。
これは、ソフトウェア割り込みの10番を発生させろ!…という意味になります。
ソフトウェア割り込みでも、通常のマスカブル割り込みと同様に、正しく動作させるにはコンフィギュレーション・ファイルに宣言を行う必要があります。
このサンプルプロジェクトの場合は「..\OBJ\sample1.cfg」にその記述があります。
...
/*
* ソフトウェア割込み(ソフトウェア割込み10番を指定)
*/
ATT_ISR({ TA_NULL, 0, (10 + 61), swi_isr, 1 });
CFG_INT((10 + 61), { TA_NULL, -1 });
...
ここで指定する割り込み番号は、通常のマスカブル割り込みとソフトウェア割り込みを通して連番としています。
上記の割り込み番号の定義(「..\target\rb_d62q1577tb100_u8dev\target_sil.h」」)では、60番まで使われていましたよね?(実際は空番ですけど…。)
したがって、ソフトウェア割り込みはその次、すなわち61番から指定するようにしてください。
ちょっとややこしいですが、ソフトウェア割り込み番号0は61番、今回のソフトウェア割り込み番号10なら、(10 + 61)=71番ということになります。
ソフトウェア割り込み番号は、0~63番まで、合計64個も使えます!(何にそんなに使うんだ!?)
さて、上記のコンフィギュレーションでは、「swi_isr()」という割り込みハンドラを登録しています。
これは「..\OBJ\sample1.c」に実装しています。
一番下の方です。
...
/*
* ソフトウェア割込みハンドラ
*/
bool_t debug = false;
void swi_isr(intptr_t exinf)
{
debug = !debug;
}
...
10番のソフトウェア割り込みが発生すると、この関数に処理が飛びます。
すなわち「debug = !debug;」の行にブレークを仕掛けて、サンプルプロジェクト動作中にターミナルに「i」を入力すると、この行で停止します。
ソフトウェア割り込みは、昔のCPUにはよく見られた実装ですが、最近ではあまり目にすることはありません。
しかし、上手く使うとプログラムの処理がスマートになり、ソースコードが読みやすくなったりするメリットがあります。
その分、他のアーキテクチャへの移植性は悪くなりますので、ここぞ!という時に使いましょう。
OS管理外割り込み
今回のTOPPERS/ASP ML62Q1000版においては、OS管理外割り込みに対応しています。
通常「μITRON4.0」は割り込みをも管理するOSですが、OS管理下の割り込みは、純然たるベタな記述のOS管理外割り込みとして実装した場合と較べて、パフォーマンスは若干劣ります。
そのため、例えばAD変換などの応答性を重視される割り込みなどにおいては、OSの管理が足かせになる場合があります。
割り込みをOSの管理外として実装した場合、確かに応答性は向上しますが、割り込みハンドラ内でOSのシステムコールを呼ぶことは、原則できなくなります。
なにせOSの管理外ですから…。
さて、割り込みをOS管理外に設定する方法ですが、これはコンフィギュレーション・ファイルで宣言を行います。
具体的は、以下の条件で設定します。
1.CFG_INTの引数「intpri」を優先度最高(このML62Q1000版の場合は-6)以下にする
2.DEF_INHの引数「inhatr」に「TA_NONKERNEL」フラグを設定する
例えば、前述のソフトウェア割り込みをOS管轄外に変更してみましょう。
「..\OBJ\sample1.cfg」のソフトウェア割り込み10番の設定を以下のように変更します。
...
/*
* ソフトウェア割込み(ソフトウェア割込み10番を指定)
*/
//ATT_ISR({ TA_NULL, 0, (10 + 61), swi_isr, 1 }); // コメントアウト!
//CFG_INT((10 + 61), { TA_NULL, -1 }); // コメントアウト!
CFG_INT((10 + 61), { TA_NULL, -7 }); // 追記!
DEF_INH((10 + 61), { TA_NONKERNEL, swi_isr }); // 追記!
...
「CFG_INT」では、ML62Q1000版の優先度最高の値「-6」より、更に優先度が高い「-7」を設定しています。
元の「ATT_ISR」では「TA_NONKERNEL」フラグが設定できませんので「DEF_INH」を使います。
以上で前述の条件を満たせます。
このようにすると、このソフトウェア割り込み10番のハンドラは、OSの管轄から外れ、割り込みの応答性は向上しますが…。
繰り返します。
OS管理外割り込みハンドラ内で「iwup_tsk()」などのシステムコールを呼ぶことはできませんのでご注意を!
割り込み優先度を変更する裏技
さて、前述した割り込み優先度を変更してしまう裏技についてです。
この裏技、実はすでにOS内で使用しています。
今回のTOPPERS/ASP ML62Q1000版においては、素の状態で3つの割り込みを使用しています。
1つはOSタイマーで、上記の割り込み番号の定義(「..\target\rb_d62q1577tb100_u8dev\target_sil.h」」)で言うところの「TINTNO_TM0INT(割り込み27番)」です。
2つ目は、デバッグ用のシリアル通信で、受信割り込みである「TINTNO_SIU00INT(割り込み16番)」です。
3つ目は、同じくシリアル通信で、送信割り込みである「TINTNO_SIU01INT(割り込み17番)」です。
ここで思い出してください。
「ML62Q1000における割り込み優先度は、割り込み番号が若いほど優先度が高くなる」と前述しましたね。
すなわち、普通に実装した場合、OSタイマーよりもシリアル通信のための割り込みの方が優先度が高いということになります。
TOPPERS/ASPはリアルタイムOSです。
タイムクリティカルが売りなのに、それを司るOSタイマーが、遅延の許されるデバッグ用のシリアル通信の割り込みよりも優先度が低いという状況になります。
それって、リアルタイムOSとしてどうなのよ?
なんとかしてOSタイマーの割り込み優先度を上げたいところですよね?
しかしながら、これも前述のように、このカーネルでは、割り込み優先度の設定はできません。
じゃあどうするか?
そこで裏技です。
「..\target\target_config.c」の「target_initialize()」関数を御覧ください。
この「target_initialize()」はOSが起動してから比較的早い時期に実行される関数です。
以下の部分に注目!
...
/*
* ターゲット依存の初期化
*/
void
target_initialize(void)
{
initVls_t initVls;
/*
* プロセッサ依存の初期化
*/
prc_initialize();
/*
* 割込みレベル制御許可
*/
write_reg8(ILEN, 0x01U);
/*
* 16 ビットタイマ0 割込み(TM0INT)のレベル設定
* -> 11: レベル4(割込みレベル高)
*/
ILTM0L = 1;
ILTM0H = 1;
...
一番下の2行で「ILTM0L」と「ILTM0H」のレジスタにそれぞれ「1」を設定していますね?
これらは「割り込みレベル制御レジスタ」というレジスタの中のビットで、OSタイマーに使用している16ビットタイマ0割込み(TM0INT)用のものです。
この「割り込みレベル制御レジスタ」は全てのマスカブル割り込み要因ごとに用意されています。
これらは、今回の場合は「c:\U8Dev\Inc\ML621577.H」に定義されています。
「割り込みレベル制御レジスタ」のこれらのビットは、該当する割り込み要因のレベルを設定するものであり、「H(ハイ)」と「L(ロー)」の2ビットで構成されています。
2ビットだから、レベル1~4までの4段階を設定できます。
ここで言う「レベル」とは、その値が高い割り込みが優先されるという意味になります。
つまり、前述した「ML62Q1000における割り込み優先度は、割り込み番号が若いほど優先度が高くなる」という法則を無視することができます!
(同じレベルのものは、やはり上記の法則に則りますが…。)
「H(ハイ)」と「L(ロー)」の並びで、以下のようにレベルを設定できます。
○00: レベル1(割り込みレベル低)(初期値)
○01: レベル2
○10: レベル3
○11: レベル4(割り込みレベル高)
今回は「ILTM0L」と「ILTM0H」を共に「1」にしたので、OSタイマーに使用している16ビットタイマ0割込み(TM0INT)は「レベル4」に設定していることになります。
これにより、たとえ「割り込み番号が若いほど優先度が高くなる」という法則があろうとも、レベル1のシリアル通信系のものよりもレベル4のOSタイマーの割り込みが優先して実行されることになります。
前述の通り、割り込みマスクの問題から、割り込み優先度の操作についてこのカーネルでは完璧にはサポートできませんでしたが、この裏技を使えば、大抵の場合は対処できるようになるでしょう。
例外ハンドラは未対応
コンフィグレーションファイルなどにおいて、他のアーキテクチャからの移植性を考慮して、例外ハンドラの作成はできるようになっているものの動作はしません。
理由はML62Q1000に例外処理が存在しないためです。
一部サービスコールは未対応
性能評価用システム時刻取得のための「get_utm()」サービスコールは未実装です。
拡張パッケージについて
例えば、アプリケーションによっては、メッセージバッファやミューテックスといった機能を使いたい場合が出てくると思います。
しかしながら、これらの機能は標準では実装されておらず、「..\extension」以下の該当する機能のソースコードをカーネルのソースコードディレクトリにコピーする必要があります。
ここで注意しなければならないのは、今回のTOPPERS/ASP ML62Q1000版においては、カーネルのソースコードディレクトリが2つ存在することです。
1つ目は、純正のカーネルソースコードディレクトリである「..\kernel」。
2つ目は、ML62Q1000専用の「..\kernel_u8dev」です。
なんで分かれているのか?
それは、ML62Q1000版で使用されることを想定しているコンパイラがいつものGCC系統ではなく、ラピステクノロジー社純正の「ccu8」だからです。
すなわち、GCC系統のコンパイラでビルドが通るように書かれた「..\kernel」以下のソースコードは、ラピステクノロジー社純正の「ccu8」コンパイラではビルドが通らなかったのです。
そこで「ccu8」コンパイラでもビルドが通るように「..\kernel」を書き換えたものが「..\kernel_u8dev」というわけです。
ヘッダファイルの格納ディレクトリである「..\include」と「..\include_u8dev」も同様の理由で分けています。
さて、例えば現在のカーネルにメッセージバッファの機能を加えるために、「..\extension\messagebuf」以下のソースコードやヘッダファイルを「..\kernel_u8dev」や「..\include_u8dev」に上書きすると仮定しましょう。
すると「..\extension」以下のソースコードやヘッダファイルは、GCC系統のコンパイラで通るように書かれているため、「ccu8」コンパイラではエラーが出ることが考えられます。
私が「ccu8」コンパイラ用の「..\extension_u8dev」といったものを用意すればいいだけの話ですが、そこまで手が回らず…すんません!
とはいえ、エラーが発生した場合に「ccu8」コンパイラで通るように修正するのは、それほど難しい作業ではありません。
ほとんどの場合、修正が必要なのはヘッダファイルであり、インラインの宣言の違いなど、C言語の方言にまつわる部分です。
この辺りは「..\kernel」と「..\kernel_u8dev」、および「..\include」と「..\include_u8dev」を比較して、それをヒントに移植してみてください。
ライセンスについて
このカーネルは「TOPPERSライセンス」で配布しております。
無償ですが、使用に関しては自己責任です。
このカーネルを商用利用するレアな方は、このリンク先の条項に従ってください。
さて、今回はラピステクノロジー社のML62Q1000マイコンを取り上げたわけですが、個人的には、大変気に入っております。
元々8ビットのアーキテクチャを16ビットに拡張した製品ではあるのですが、それが無理なくスマートに実現されており、命令系統も洗練されています。
コンパイラやデバッガも、純正品独特のクセはあるものの質実剛健といった印象で、好感が持てます。
それに加えてノイズに強くて低消費電力という売りを考えると、もう少し広く普及しても良いのでは?と思います。
TOPPERS/ASPに続いて、FreeRTOSも移植してみたいと思いました。
ML62Q1000マイコン、どうぞ機会があれば採用を検討してみてくださいね。