2007-09-02
IDCODE読めた
C#, FT2232, JTAG, ADuC7026 | |
ようやくここまで来ました。ターゲットはDWM 2006 4月号の付録基板。
IDCODEは、3F0F0F0F。これは以前FTDIのサンプルプログラムで読んだ値と同じです。これを読む部分のコードは、こんな感じ。
private void IdCodeButton_Click(object sender, EventArgs e)
{
byte[] idcode = new byte[4];
int readBytes;
FTDI.JTAG.Write(
handle,
true, // instruction
target[1].inst_bitlength,
target[1].inst_idcode,
target[1].inst_idcode.Length,
FTDI.JTAG.TapState.TestLogicState
);
FTDI.JTAG.Read(
handle,
false, // data
32, // idcode is always 32 bit
idcode,
out readBytes,
FTDI.JTAG.TapState.TestLogicState
);
textBox1.AppendText(
"IDCODE is : " +
idcode[3].ToString("X2") + " " +
idcode[2].ToString("X2") + " " +
idcode[1].ToString("X2") + " " +
idcode[0].ToString("X2") + Environment.NewLine
);
}
テキストボックスへの表示を除けば、関数2つを呼ぶだけでJTAGのIDCODEを読み出すことができます。とっても簡単。ですが、最初の関数のtarget変数を組み立てるためにはXMLによるターゲット宣言ファイルの読み込みルーチンを書かなければなりません。それに、Amontec JTAGKEY(実はベステクのTINY-JTAG)の初期化を支えるルーチンも必要です。たとえばこんな感じ。
public static void EnableTap(int handle)
{
FTDI.JTAG.InputOutputPins gpioL, gpioH;
gpioL.bPin0InputOutputState = true; // Output. Tap Enable Pin
gpioL.bPin1InputOutputState = false; // Input
gpioL.bPin2InputOutputState = false; // Input
gpioL.bPin3InputOutputState = false; // Input
gpioL.bPin0LowHighState = false; // L. Tap Enable
gpioL.bPin1LowHighState = false; // L
gpioL.bPin2LowHighState = false; // L
gpioL.bPin3LowHighState = false; // L
gpioH.bPin0InputOutputState = true; // Output;
gpioH.bPin1InputOutputState = true; // Output;
gpioH.bPin2InputOutputState = true; // Output;
gpioH.bPin3InputOutputState = true; // Output;
// amontec circuit dependent
gpioH.bPin0LowHighState = true; // deassert TRST;
gpioH.bPin2LowHighState = false; // enable TRST
gpioH.bPin1LowHighState = false; // keep it L always
gpioH.bPin3LowHighState = true; // Hi-Z SRST
errorCheck(
FTDI.JTAG.SetGPIOs(
handle,
true, // control GPIO_L
ref gpioL,
true, // control GPIO_H
ref gpioH
)
);
}
そんなわけで、優雅な水鳥も水面下では激しく水をかいているのでした。
2007-03-29
1秒休止
TOPPERS/JSP, ADuC7026, サンプル | |
昨日のプログラムは、1行印字して終了するだけでした。次に連続して何行も印字させるプログラムを作って見ましょう。
今回紹介するのは、終わりなく延々と印字するプログラムです。そのため、syslog()関数はwhile(1)ループの中にいれます。
syslog()関数では、現在何回目のループであるかも印字させることにします。C言語の標準ライブラリを使っている場合には、このような印字はprintf()で行います。TOPPERS/JSPのsyslog()関数はprintf()関数と同じように使うこともできます。今回の例ではフォーマット文字列"%d"を使って10進数の印字を行います。
syslog( "answer= %d", ans );
printfと異なるのは、勝手に改行される点です。したがって、一行にまとめたい出力は、syslog()関数一回で出力する様にしてください。
一行印字を連続して行うと、あっという間にものすごい数の行が出力されてしまいます。そこで、今回は出力後に1000mS休止させることにします。
tslp_tsk( 1000 );
tslp_tsk()関数はuITRON4のAPIです。この関数は関数を呼び出したタスクを休止状態にいれます。休止状態に入ったあと、引数で指定したミリ秒経過すると、タスクを実行可能状態に戻します。
これらを使って1秒ごとにメッセージを出力するプログラムにまとめたのが以下のコードです。ファイル名はsample1.c。
#include <t_services.h> #include "kernel_id.h" #include "sample1.h" void main_task(VP_INT exinf) { int i; i = 0; while(1){ syslog(LOG_NOTICE, "Hello, ADuC7026! %d", i ); i++; tslp_tsk( 1000 ); } }
sample1.hとsample1.cfgは昨日のものを使いまわします。
このタスクが印字する周期はおよそ1秒であることに気をつけてください。tslp_tsk()は引数で指示した時間休止することを保証しますが、それよりわずかに長くなるのが普通です。これは、TOPPERS/JSPの内部時間がティック・タイマーと言われるタイマーを元に計測されるためです。ティックタイマーの生成する割り込み(ティック)が時間計測の分解能になり、その分解能より高い精度は望めません。
また、仮に正確に1000mS休止して復帰しても、syslog()などの実行時間が余計にかかるため、やはり全体の周期はやや長くなります。
2007-03-28
最小プログラム
TOPPERS/JSP, ADuC7026, サンプル | |
TOPPERS/JSPの最小プログラム*1です。起動するとタスクを一つだけアクティブにし、メッセージをシリアル・ポートに出力してタスクを終了します。メッセージの出力には、ロギング機能を使っています。
プログラムのビルドやダウンロードに関しては組込みプログラミングにEclipseを使う(2)を参照してください。
手順としては、
- sample1を構築
- それを改造
という流れになります。
プログラム本体
筋から言えばここはコンフィグレーション・ファイルから説明するべきかもしれません。しかしそれでは色気も何もないので、一番楽しそうなメイン・プログラムから。ファイルはsample1.cです。
#include <t_services.h> #include "kernel_id.h" #include "sample1.h" void main_task(VP_INT exinf) { syslog(LOG_NOTICE, "Hello, ADuC7026!" ); }
三つあるインクルード文はそれぞれ
- TOPPERS/JSPの標準ヘッダ・ファイル
- コンフィグレータが出力したヘッダ・ファイル
- ユーザーが用意したヘッダファイル
を、読み込みます。一番基本的な構成です。
関数main_task()はその名の通りメイン・タスクとして実行されます。実行するとsyslog()関数を呼び出して終了します。
syslog()関数はTOPPERS/JSPの持つロギング関数で、どのような媒体に出力するかは処理系依存です。しかし標準的な実装ではシリアルポートへログデータを記録します。PizzaFactory3.1 Expressに同梱されているADuC7026用のTOPPERS/JSPも、シリアルポートにしゅつりょくします。
9600bps,8bit,non-parityに設定した端末ソフトをつないでプログラムを実行すると、システム起動メッセージに続いて"Hello, ADuC7026!"と端末に表示されます。
ヘッダ・ファイル
ファイルはsample1.hです。このファイルは通常はアプリケーション自身で使うほか、コンフィグレーション・ファイルからも読み込まれます。今回のアプリケーションは規模が小さいため、コンフィグレータが使う資源のみを宣言しています。
コンフィグレータは関数プロトタイプを理解できません。コンフィグレータは_MACRO_ONLYマクロを事前に宣言しますので、プロトタイプは_MACRO_ONLYマクロが宣言されていないときにのみ有効とすることで、問題を回避しています。
タスク優先度とスタックサイズはいずれもコンフィグレーションの中で使います。この二つはプログラム中で使うことはないと思われますので、コンフィグレーション・ファイルに直接値を書きこんでもかまいません。しかし、タスクの構成に関するパラメータは、関数宣言などとともにヘッダ・ファイルにまとめたほうが、全体の見通しはすっきりするでしょう。
#include <t_services.h> /* メインタスクのパラメタ */ #define MAIN_PRIORITY 5 /* 優先度 */ #define MAIN_STACK_SIZE 512 /* スタックサイズ */ #ifndef _MACRO_ONLY extern void main_task(VP_INT exinf); #endif /* _MACRO_ONLY */
コンフィグレーション・ファイル
ファイル名はsample1.cfgです。
コンフィグレーション・ファイルはコンフィグレータに対して静的にセマフォやタスクといった資源を作り出すよう指示するためのファイルです。コンフィグレータが作り出した資源は、実行中にアプリケーション・プログラムから利用することができます。
TOPPERS/JSPはタスクやセマフォをアプリケーションの実行中に作り出す手段を持っていないため、コンフィグレーション・ファイルがこれらを作り出す唯一の手段になります。
コンフィグレーションファイルには二つのインクルード文が存在します。
#includeは、コンフィグレータの実行中にファイルを読み込み、コンフィグレータに利用させるためのものです。INCLUDEはコンフィグレータの出力ファイル、つまりkernel_id.hとkernel_cfg.hの中に#include文を埋め込むためのものです。両者は実際にファイルが読み込まれる時期が異なりますので注意してください。
CRE_TSKは、タスクを静的に作るためのAPIです。詳しくはuITRON4の仕様書を参照してください。今回の例ではMAIN_TASKという識別子がコンフィグレータによって生成されます。この識別子は、アプリケーション・プルグラム中で「この」タスクを示すIDとしていつでも利用できます。
コンフィグレーション・ファイルの最後にある3つのインクルード文は、ティック・タイマーとロギング機能を実装するためのタスクやセマフォ、割り込みハンドラを宣言するためのものです。
ティック・タイマはOSの必須機能ですから、必ず宣言しなければなりません。
ロギング機能は便利ですので、特に理由がない限り使うほうがいいでしょう。
インクルード文のパスはシステムによって異なります。PizzaFactory3 Expressを使った場合にはプラグイン内部へのパスがここに現れます。したがって、以下のコンフィグレーション・ファイルをそのままPizzaFactoryで使おうとしてもうまく行きません。PizzaFactoryがsample1用に生成したパスをそのまま使ってください。
#define _MACRO_ONLY #include "sample1.h" INCLUDE("\"sample1.h\""); CRE_TSK( MAIN_TASK, { TA_HLNG|TA_ACT, /* 高級言語記述、最初からアクティブ */ 0, /* extinfに渡す値 */ main_task, /* タスクとして使う関数 */ MAIN_PRIORITY, /* タスク実行順位 */ MAIN_STACK_SIZE, /* タスク・スタックの大きさ[Byte] */ NULL /* スタックのアドレス。NULLなら自動割付 */ }); #include "/your/path/systask/timer.cfg" #include "/your/path/systask/serial.cfg" #include "/your/path/systask/logtask.cfg"
実行結果
ADuC7026でTOPPERS/JSPアプリケーションを動かすには、プログラムを内蔵フラッシュROMに書き込みます。そしてターゲットのシリアルポートに9600bps,8bit,non-parityのターミナルを接続し、ターゲットをリセットします。
正しくビルド、書き込みができていれば以下のような出力がターミナル上に現れます。
*1:の、ちょっと先
2007-03-04
フラッシュが書き込まれていない事がある
ADuC7026 | |
安定して動くツールが手に入ったので、次第に他の部分の問題がはっきり見えてきました*1
TOPPERS/JSPの標準アプリケーションsample1をきちんとトレース、ブレークできるようになったので、sample1を改良してみました。といっても、コードを削りまくって小さなプログラムにするだけです。ところが動いたり動かなかったり。その後フリー・スタンディングに進んだのはこのプログラムの動作をちゃんと見たかったからです。
念願かなって見えるようになりました。で、見てみると、とても不安定です。pcを0に設定してリスタートをかけてもうまく動作しません。そこでARMWSDでベリファイをかけると0番地にエラーがあります。もう一度デバッガで覗くと、最初の16byteが0xFFでした。
ADuC7026の最初の16バイトは例外ベクトル領域です。特に最初の4byteはリセットベクトルです。これが正しく設定されていないなら、まっとうに動くわけがありません。HEXファイルを開いてみたところ、最初の16byteのデータレコードはきちんと生成されています。FLASHは書きこみで0のビットを1にすることはできません。と言うことは、一度正しく書かれたデータが0xFFで上書きされたのではなく、最初からかかれなかったということになります。昨晩はここで力尽きて寝ました。
で、今朝調査を再開。HEXファイル当該レコードのチェックサムはあっているようです。
ためしに最初の2行*2分のレコードを残して残りのデータレコードを全部消し、ARMWSDにかけて焼いてみました。するとなぜかきちんと焼けているようです。何かのタイミングでしょうか。
さらににフルレコード状態で最初の1レコードのみコピーして重複させると、これもうまく行きます。ちゃんと実行できました。
まとめておく
原因が何かは特定できていません。データシートでは1万回書き込みできることになっています。一方で、DWM基板ですので当初VDDintに3Vかかっていました。ダメージがあるかもしれません。
とりあえず以下の方策でしばらく凌ぐことにします。まず、ARMWSDですが、
- 毎回全領域を消去する
- 必ずベリファイを行う

