さてさて、H8向けのTOPPERS/JSPには、シリアルインタフェースドライバ内にシリアル受信割込ハンドラとシリアル受信エラー割込ハンドラの2つが定義可能です。しかし、後者は #ifdef の条件分岐によってコメントアウトされており、前者内でエラーの割込も処理するようになっています。
ちなみに、実装は jsp/config/h8/hw_serial.c 内の SCI_in_handler です。
さて、SCI_in_handler の実装を見てみましょう。
void SCI_in_handler(ID sioid)
{
SIOPCB *pcb;
UB status;
pcb = get_siopcb(sioid);
status = sil_reb_mem((VP)(pcb->inib->base + H8SSR));
if (status & (H8SSR_ORER | H8SSR_FER | H8SSR_PER)) {
/* エラー処理 */
/* エラーフラグをクリア */
sil_wrb_mem((VP)(pcb->inib->base + H8SSR), status & ~(H8SSR_ORER | H8SSR_FER | H8SSR_PER));
}
if (status & H8SSR_RDRF) {
if (pcb->openflag) {
/* 受信可能コールバックルーチンを呼出す。*/
SCI_ierdy_rcv(pcb->exinf);
} else {
sil_wrb_mem((VP)(pcb->inib->base + H8SSR), status & ~H8SSR_RDRF);
}
}
}
ううむ・・・真ん中当たりに「エラー処理」と書かれて放置されている(っぽい)辺りが怪しい。ここに書けば良いのかな。
とりあえず、フレーミングエラーの場合はシリアルチャネルのRxDを調べて、ブレーク信号かどうかを判断すれば良いそうです。こんな処理を入れちゃいましょう。
/* フレーミングエラー発生時 */
if (status & H8SSR_FER){
/* RDR (Receive Data Register) がブレーク信号受信状態 (全ビットがLOW = 0x00) であるかどうかをチェック */
if (sil_reb_mem((VP)(pcb->inib->base + H8RDR)) == 0x00){
/* ブレーク信号受信時には SCR (Serial Control Register) の RE (Receive Enable) フラグを落とす */
sil_wrb_mem((VP)(pcb->inib->base + H8SCR),
sil_reb_mem((VP)(pcb->inib->base + H8SCR)) & ~H8SCR_RE);
}
}
RxDを調べるとブレーク信号かどうか分かるって言うんですが、それってRDR (Receive Data Register) の値を調べれば良いって事と等価ですよね?RSR (Receive Shift Register) は直接CPUから読み書きできませんので、これで合ってると思うんですが。
そして、このコード修正をカーネルに反映してアプリを再コンパイルします。カーネルをアプリとは別にコンパイルしている場合は、
% cd jsp/(kernel_build_dir)
% make realclean
% make depend
% make libkernel.a
とかやっときましょう。たぶん最後の行の「make libkernel.a」だけで良い筈ですが、チキンな私は「make realclean」からやっときました(^^;)
さて、アプリをコンパイルしてH8に転送し、実行します。そして、シリアルコンソールのminicomから「Ctrl-a f」でブレーク信号を送信しますが・・・あ、シリアルコンソールからのデバッグ出力が止まった。カーネルがハングしたっぽい。
何でやねん!!
今入れたコードは何だったんだ・・・orz
(苦悩は続く・・・)
あああ、、、やってしまった。
前回のエントリでは、一生懸命SH2向けのTOPPERS/JSP実装をベースにH8 3069F向けのブレーク信号検出時の割り込みハンドラについて想定しましたが、やってしまいました。そもそも、H8にはブレーク信号検出割り込みというものは無いのです。代わりに、受信エラー割り込みの割り込みハンドラ内で、ブレーク信号の検出時の挙動を書いてやる必要が有りそうです。
ちなみに、受信エラー割り込みハンドラは既に jsp/config/h8/hw_serial.c 内に実装されており、シリアルステータスレジスタ(SSR)の3つのフラグ(ORER: オーバーランエラー, FER: フレーミングエラー, 及び PER: パリティエラー)をチェックし、フラグが立っていれば単にそれらをクリアする、という実装になっています。
ここに何かを実装すれば良い気がします。
引き続き備忘録です。
TOPPERS/JSPカーネルのH8向け実装には、シリアルインタフェースの受信時にブレーク信号を検出した際の割り込みハンドラが実装されていない様です。これで相当にハマりました。しょうがないので、自分で作ることにします。
幸いな事に、TOPPERS/JSPカーネルのソースツリーを調べると、SH2プロセッサのSH7615向けにはブレーク信号検出の割り込みハンドラが実装されていますので、それを参考にします。というか、他のプロセッサ/プラットフォーム向けにはブレーク信号検出の割り込みハンドラが実装されていない様に見受けられます。みんな必要なかったんでしょうか。。。謎だ。
さて、以下は作業予定ですので、実際にこの通りやってうまくいかない可能性も有ります。作業が終わったらまたアップデートする予定です。
作業のレシピはこんな感じ。
ソース:
- jsp/config/sh2/sh7615scif.c
- 割り込みハンドラの実体である sh2scif_isr_siop_brk 関数があります
- シリアルチャネル0向けの割り込みハンドラである sh2scif_isr_brk 関数があります(その実体は sh2scif_isr_siop_brk 関数です)
- シリアルチャネル1向けの割り込みハンドラである sh2scif_isr2_brk 関数があります(その実体は sh2scif_isr_siop_brk 関数です)
- jsp/config/sh2/hsb7616it/hw_serial.h
- 割り込みハンドラの名前を付け変える以下の#defineディレクティブがあります
- #define sio_handler_brk sh2scif_isr_brk
- #define sio_handler2_brk sh2scif_isr2_brk
- jsp/config/sh2/hsb7616it/hw_serial.cfg
- 割り込みハンドラを登録する以下の静的APIがあります
- DEF_INH(INHNO_SERIAL_BRK, { TA_HLNG, sio_handler_brk });
- DEF_INH(INHNO_SERIAL2_BRK, { TA_HLNG, sio_handler2_brk });
なんか、これだけ材料があったら負ける気がしません(笑)。
さて、私がターゲットにしているのはH8 3069を搭載した秋月電子製マイコンボード(H8 3069F LANボード)ですので、上記のレシピで以下の様な読み替えを行います。
- sh2 => h8
- hsb7616it => akih8_3069f
また、シリアルチャネルの数が最大3に増えます。
この読み替えを行うと、H8 3069F LANボード向けには以下の作業をすることになります。
作業:
- jsp/config/h8/akih8_3069fscif.c を作成する
- 割り込みハンドラの実体である h8scif_isr_siop_brk 関数を実装する
- シリアルチャネル0向けの割り込みハンドラである h8scif_isr_brk 関数を実装する(その実体は h8scif_isr_siop_brk 関数である)
- シリアルチャネル1向けの割り込みハンドラである h8cif_isr2_brk 関数を実装する(その実体は h8scif_isr_siop_brk 関数である)
- シリアルチャネル2向けの割り込みハンドラである h8cif_isr3_brk 関数を実装する(その実体は h8scif_isr_siop_brk 関数である)
- jsp/config/h8/akih8_3069f/hw_serial.h を作成する
- 割り込みハンドラの名前を付け変える以下の#defineディレクティブを定義する
- #define sio_handler_brk h8scif_isr_brk
- #define sio_handler2_brk h8scif_isr2_brk
- #define sio_handler3_brk h8scif_isr3_brk
- jsp/config/h8/akih8_3069f/hw_serial.cfg を作成する
- 割り込みハンドラを登録する以下の静的APIを記述する
- DEF_INH(INHNO_SERIAL_BRK, { TA_HLNG, sio_handler_brk });
- DEF_INH(INHNO_SERIAL2_BRK, { TA_HLNG, sio_handler2_brk });
- DEF_INH(INHNO_SERIAL3_BRK, { TA_HLNG, sio_handler3_brk });
ここで、H8プロセッサ、及びH8 3069F LANボードにおける、TOPPERS/JSPのファイル構成を考慮して、少し修正を施します。
- jsp/config/h8/akih8_3069fscif.c を作成する
- 既存の jsp/config/h8/hw_serial.c に追記する
- jsp/config/h8/akih8_3069f/hw_serial.h を作成する
- 既存の jsp/config/h8/hw_serial.h に追記する
- jsp/config/h8/akih8_3069f/hw_serial.cfg を作成する
- 既存の jsp/config/h8/hw_serial.cfg に追記する
さらに、既存のH8向けシリアルインタフェースドライバの関数名を踏襲しましょう。修正された作業内容は以下の通りです。
- 既存の jsp/config/h8/hw_serial.c に追記する
- 割り込みハンドラの実体である SCI_brk_handler 関数を実装する
- シリアルチャネル0向けの割り込みハンドラである sio_brk_handler 関数を実装する(その実体は SCI_brk_handler 関数である)
- シリアルチャネル1向けの割り込みハンドラである sio_brk2_handler 関数を実装する(その実体は SCI_brk_handler 関数である)
- シリアルチャネル2向けの割り込みハンドラである sio_brk3_handler 関数を実装する(その実体は SCI_brk_handler 関数である)
- 既存の jsp/config/h8/hw_serial.h に追記する
- 既存の jsp/config/h8/hw_serial.cfg に追記する
- 割り込みハンドラを登録する以下の静的APIを記述する
- DEF_INH(INHNO_SERIAL_BRK, { TA_HLNG, sio_brk_handler });
- DEF_INH(INHNO_SERIAL2_BRK, { TA_HLNG, sio_brk2_handler });
- DEF_INH(INHNO_SERIAL3_BRK, { TA_HLNG, sio_brk3_handler });
さて、これでやることが決まりました。
作業を始めますか。。。
その後、すっかり記述がご無沙汰してしまいました。結局、Vine 4.2ではRPMによるクロス開発環境構築を諦め、通常の様にソースからconfigure & make & make installを行いました。但し、インストール先はユーザのホームディレクトリ以下です。これで、binutilsとgcc、そしてnewlibが揃いました。次は、開発に用いる組込向けOSを用意します。今回はμITRON 4.0に準拠したオープンソースのOSである、TOPPERS/JSPを用います。TOPPERS/JSPは、実はOSと言うよりも大きなライブラリです。ソースが公開されていますし、既に様々なCPUやプラットフォームに移植済です。当然、今回のターゲットであるルネサスH8 3069Fプロセッサや、秋月電子 H8 3069F LANボードに対応しています。ところで、TOPPERS/JSPを使うプログラムは、TOPPERS/JSPカーネル(実体はソースをビルドする事で得られるlibkernel.aという静的ライブラリ)とリンクされ、H8 3069Fの内部フラッシュROMに書き込まれることで、実行可能となります。しかし、H8 3069のフラッシュROMは100回の書き込みしか保証されていません。そこで、毎回毎回フラッシュROMに書き込まなくても良い様に、フラッシュROMには簡易モニタプログラムを書き込むことにします。H8用の簡易モニタプログラムはこちらからダウンロードできます。H8簡易モニタは、既にコンパイル済のバイナリが配られているアーカイブに含まれていますし、それをビルドするためのソースも同梱されています。特にバイナリ版で問題が無ければ、バイナリ版をH8 3069のフラッシュROMに転送します。ちなみに、転送するにはROMライタプログラムが別途必要です。今回は、ソースが手に入るOpen H8/SH Writeを利用することにします。ソースファイル「h8write.c」をダウンロードし、そのまま例えば以下の様なコマンドラインでコンパイルします。% gcc -o h8write h8write.c出来上がったROMライタを使って簡易モニタをH8 3069のフラッシュROMに転送します。% h8write -3069 -f20 mon3069.mot /dev/ttyUSB0但し、簡易モニタプログラムのモトローラSレコード形式ファイルのファイル名をmon3069.mot、また今回はUSB/シリアル変換ケーブルを用いているので、シリアルポートのデバイスファイルを/dev/ttyUSB0としています。これでとりあえずH8簡易モニタが起動する様になります。H8 3069ボードのシリアルポートコネクタにUSB/シリアル変換ケーブルを接続し、Vine上でrootにsuしてからminicomを起動します。root権限が無いとシリアルポートのデバイスファイル/dev/ttyUSB0がオープン出来ませんので、ご注意下さい。また、ターミナルソフトはminicomじゃなくても構いません。minicomを起動する場合は、まず最初にシリアルポートの接続設定を行う必要がありますので、コマンドラインオプションに”-s”を指定します。% su -% minicom -sもしくは、普通にオプション無しでminicomを起動し、”Ctrl-a s”で設定画面を呼び出しても同じです。シリアルポートの設定は、以下の通りです。- 通信速度: 38,400bps
- データサイズ: 8ビット
- パリティ: 無し
- ストップビット: 1
H8 3069ボードに接続し、簡易モニタの起動が確認出来ればひと段落です。
引き続き備忘録です。
- 特定のI/OポートのHigh/Lowを見る方法。
- 例えばポート4に属する8つのI/Oポート(H8 3069のピン配置では#18-21, #23-26)の値は、H8P4DRマクロを使ってアクセスします。
- ポート4の1ビット目は(*((UB *) H8P4DR) & 0x01)でRead/Writeアクセスできます。
- 電圧Highは1、電圧Lowは0となります。
- 特定のI/Oポートの入出力方向の取得/設定方法
- まず、H8ではI/Oポートの入出力方向を設定するレジスタ(DDR: Data Direction Register)が書き込み専用です。その為、現在の設定値を保持する為にTOPPERS/JSPでは特別にカーネル内部に設定値保持の為の変数を設けています。
- 入出力方法の設定には、sil_wrb_ddrサービスコールを用います。例えば、ポート2の1ビット目から6ビット目までは出力、7ビット目と8ビット目は入力、と設定する場合は、sil_wrb_ddr(IO_PORT2, 0x3F)とコールします。出力に設定するI/Oポートのビットは1を、入力に設定するI/Oポートのビットは0を指定します。
- 設定済みの値を読み出したい場合は、sil_reb_ddr(IO_PORT2)とコールし、その返り値をチェックします。
- 設定済みの値に対して特定のビットだけをON/OFFしたい場合は、sil_anb_ddr (既存値とのAND演算)、sil_orb_ddr (既存値とのOR演算)を用います。
- タスクのウエイト
- 通常のCプログラムにおけるsleep関数のような事をしたい場合は、dly_tskサービスコールを用います。引数は1つだけで、ミリ秒単位の時間を表す整数です。
- 例えば、1秒間ウエイトしたい場合は、dly_tsk(1000)とコールします。
本エントリは備忘録です。
μITRON4の実装であるTOPPERS/JSPを使って、秋月電子製のルネサステクノロジH8 3069を搭載したボード上で稼働するプログラムを書いています。
H8 3069はH8 300Hファミリ、最大クロック25MHz (但し当該ボードでは20MHzで駆動)、内部フラッシュROM 512KB、内部RAM 15KB、外部RAM 2MB (16Mbits)といったところです。シリアルインタフェースは3ch搭載されています。
- シリアルポートI/O
- ER_UINT serial_rea_dat(ID portid, char * buf, UINT len)
- portidのシリアルポートからbufが先頭アドレスのバッファにlen文字読み出す
- ER_UINT serial_wri_dat(ID portid, char * buf, UINT len)
- portidのシリアルポートにbufが先頭アドレスのバッファからlen文字書き出す
- ログ出力
- void syslog(UINT prio, const char * format, ...)
- prioのプライオリティでログを出力する
- format以降の引数については標準Cライブラリのprintf関数と同様
- 但し、formatより後ろの引数は最大5個まで
Macで敗北したので、会社のVAIOをWindows XP Home + Vine Linux 4.2のデュアルブートにすることに。Vineを本格的に触るのは、学生時代以来だから実に7年半ぶり。すっかりインストーラも洗練されて、特に問題無くグラフィカルログイン可能な状態にまで持って来れた。Vine 4.2の特筆すべき点は、WinXPに比べた時に格段に軽く感じる点ではないかと思う。Firefox 3.0.3を起動するにしても、WinXPに比べてかなり速い。これは良い。今回はクロス開発環境を追い求めてLinuxを選択し、かつ非力なノートPC (Pentium M 900MHz + 256MB RAM) だったのでVineを選んだが、Vineのラップトップというのも良いかも知れない。さて、Linuxが一旦動き出すと、H8用のクロス開発環境の準備も格段に楽になる。「Tools for Linux」のページから、MES2.0、H8ユーザプログラム用の GNU binutils、GNU gcc、及びRedHat newlibのソースRPMを頂き、件のVineでバイナリRPMをリビルドするだけ。この際には、以下のコマンドを実行した。% cd ~/rpm/SRPM% (カレントディレクトリにソースRPMをコピー)% rpm -i <パッケージ名>.src.rpm% cd ~/rpm/SPECS% rpmbuild -bb <パッケージ名>.spec% cd ~/rpm/RPMS/i386% su% rpm -Uvh <パッケージ名>.i386.rpm但し、上記ソースRPMのSPECファイルそのままではリビルドが出来ない。SPECファイル内に書かれている”Copyright: “という行が互換性エラーを吐くので、ここをエディタで”License: “と書き換える。RPMコマンドのバージョンによってSPECファイルの書式が変わったのかな?あと、newlibのリビルド中にstripコマンドが「このファイル形式は認識出来ん」とエラーを吐く。これは、先にインストールしたH8用のbinutilsに入っているstripではなく、ホスト環境(i386)用のstripを使ってしまっているため。H8用のstripがどこに入っているか調べるには、いかのコマンドを実行する。% rpm -ql h8-binutils-elf | grep strip結果、”/usr/local/bin/h8300-elf-strip”としてインストールされているのが分かるので、とりあえずnewlibのリビルド中だけ対症療法としてstripという名前のシンボリックリンクを作っておく。ホストのstripは/usr/bin/stripだが、PATH環境変数によって/usr/binより/usr/local/binを先に見るようになっている。従って、以下のコマンドでリンクを張る。% cd /usr/local/bin% ln -sf h8300-elf-strip stripこれで無事ビルド完了。このシンボリックリンクはnewlibのリビルド後に消せば良い。(※追記: 残念なことにnewlibのSRPMからのビルドは出来なかった)これだけでクロス開発環境が導入できる。楽ちんである。Macであれだけはまったのは何だったんだろう・・・。
MacPortsからGNUのgcc v4.3を入れたところ、コンパイルに4時間も掛かった・・・orz いくらC以外の言語(C++とかJavaとか)も含まれているとは言え、Core2 Duo 2.0GHzでこんなに掛かるとは・・・。ちなみに、無事入ったgccでbinutils-2.16.1をh8300-hms向けにコンパイルしたところ、相変わらず以下のエラーが。これはXcodeのgcc v4.0.1でも出る。checking for gcc... (cached) /opt/local/bin/gcc-mp-4.3checking whether the C compiler (/opt/local/bin/gcc-mp-4.3 -g -O2 ) works... noconfigure: error: installation or configuration problem: C compiler cannot create executables.
gccはちゃんとインストールされているのに、何故”worsk... no”って出ちゃうんでしょう・・・。もう五里霧中です。とりあえずMac上でのクロス開発環境構築はpendingとします(汗)# 現在Windows XP Homeが入っている会社PCにVine Linuxをdual bootで入れることにしますです。ああ、なんか敗北感。
とりあえず、コンパイラが怪しい感じがするのでMacPortsからXcodeとは別のgccを入れることに。% sudo port install apple-gcc42インストールは成功するが、インストールされたgcc (v4.2.1)を使ってもbinutilsのビルドが通らない。ウガー!しょうがないので、今度はバージョンを落としてみる。% sudo port install apple-gcc33今度は、Intel Mac用のApple版gccにはv3.3が無い事が発覚。更にGNU版gccを試みる。% sudo port install gcc33するとビルドエラーでストップ。Undefined symbols: "__init_keymgr", referenced from: ___darwin_gcc3_preregister_frame_info in crt2.old: symbol(s) not found for inferred architecture i386
諦めきれずにリビジョンアップしたgcc v3.4もやってみる。% sudo port install gcc34やっぱりビルドエラー。/gcc/gcc.c:1095: error: syntax error before ',' tokenなんでこんな初歩的なコンパイルエラーが出るんだろう。う〜む・・・どうしたものか。
MacOS X Leopard上でのH8 3069向けクロス開発の環境構築にはまっています。ターゲット”h8300-hms”向けのgccクロスコンパイラを準備しなければいけないわけですが、サポートツール(arとかldとか)としてbinutilsパッケージもクロス開発に対応させなければいけません。ところが、こいつのコンパイルが通らない。やったことは以下の通り。- binutils-2.19のソースコードをゲット
- 適当なところに上記ソースを展開
- 展開後のbinutils-2.19ディレクトリに移動
- “build”ディレクトリを作成
- 上記作成済みディレクトリ内に移動
- % ../configure --prefix=<パス> --target=h8300-hms
- % make
- “This target is no longer supported in gas”というエラーと共にmake失敗
ウガー!!何故なんだー。ちなみに開発ツールとしてLeopardのDVD-ROMから入れたgccのバージョンは以下の通り。% gcc -vUsing built-in specs.Target: i686-apple-darwin9Configured with: /var/tmp/gcc/gcc-5465~16/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9Thread model: posixgcc version 4.0.1 (Apple Inc. build 5465)トラブルシューティングは続く・・・
仕事でH8マイコンをベースにしたソフトウェアの開発をやっているんですが、ここでは備忘録がてら情報を残しておこうと思います。1. EclipseのC開発環境のTIPSEclipse 3.4.1のC開発環境を導入すれば、基本的にMacOS上でのC言語によるソフトウェアの開発の準備はOKですが、1点だけポイントがあります。Cプロジェクトで[staticライブラリ]を選択するとstaticアーカイブ(拡張子.a)を生成するプロジェクトが作れますが、このプロジェクトのツールチェインを内部ビルダに設定すると、ツールチェインにranlibを実行する段が無く、生成されたstaticアーカイブを実行ファイルとリンクする際にシンボルテーブルが無いと言われてしまいます。これは、ツールチェインの[GCCアーカイバ]でarのオプションに"-s"を手作業で加えることで回避できます。(元々arのオプションは”-r”なので、結果的に”-rs”となります)