Knowledge | ||||||
OAKS16-MINIと戯れる
2004/08/22 |
OAKS16-MINI 考えてみるとOAKS16-MINI、なんとなくですが、AKI-H8/3664より安くてパフォーマンスがいいような気がします。I/O数はほぼ同じ(1本だけOAKS16-MINIの方が多い)ようですし、ROMはH8/3664の倍、クロックもちょっと速いです。 今回、フルキット(テスト用マザーボードからコンパイラ、本体、電源まで一通りついている)を購入したので、5000円越えましたが、CPUボード単体でみたら1500円ぐらいです。またフルキットも、秋月で出ている「H8/3664開発キット」より1000円ほど高いのですが、電源も同梱されているので、比較しても高いものではないと思います。 ただ、箱の写真には、「LCDがついたボード」が載っていますが、中身には含まれていませんので、要注意です。事前に、オークス電子からマニュアルを落とせれますので、これでチェックしておけばわかることなのですが、オプションです。でも、「無いと思っていた」のに、「箱にLCDの写真がついていて、FullKitと書いてあった」ので、ちょっと期待してしまいました。 OAKS16-MINIのピン
さて、「あのボードについているピンは、特殊なものなのではないだろうか?」ということがずっと気になっていたんですが、手元にあった秋月で購入した26Pのものと比較してみたら、ぱっと見とか、挿してみた感じとかはそんなに差はありませんでした。手持ちの部品でも使えそうです。 次期コアにしようかどうか、まだそこまでは考えていませんが、最近、だいぶマイコンプログラミングに慣れてきましたので、「ローコスト、ハイパフォーマンス」なものがあれば、いろいろ試して、公開していきたいと思っています。ま、まずはコテ試しに、LEDの点滅でもやってみることにします。
| ||||||||||||||||||||||||||||||||||||
2004/08/28 |
隙間が多すぎて心が落ち着かない… ようやく組み立てました。やっぱ、サラリーマン、どうしても作業は週末になってしまいます。SIPHA COREとかと比べるとものすごく密集度が低いので、どうも心が落ち着きません。きっと、自作コアでサイズにこだわっている方はみんな同じかと。 組み立ては、説明書どおりなんですが、1つだけ替えました。CPUボードのピンフレームをつけるところ、裏をよく見たら、3列全部パターンがつながっていました。というわけで、2列のピンフレームをつけてみました。手元に50Pがあれば楽だったんですが、無かったので、40Pと10Pを2つずつ、削ってつけています。 ピンフレームって、どうして縦方向にきっちり並べられないんでしょうね〜。縦方向に密着してつけるときは、いつも削ってから載せています。 で、これをどう使うかといいますと…(使うかどうかは、実は、全然考えていないんですが…) ピンヘッダのほうに電線くっつけて、こんなコネクタのような物を作っておけば、テスト用にCPUのそばから直に信号が取り出せるようになります。 もし、便利そう!と思われた方はトライしてみてください。はい。 というわけで、デバッガ経由でプログラム実行できました。明日は、いよいよ、モニタプログラムをつぶして「ROM書き」しようと思います。さて、この基板、どんな風に使っていきましょう。
| ||||||||||||||||||||||||||||||||||||
2004/08/29 |
フラッシュROM書き込みテスト完了 前提としては、OAKS16-MINI付属の、「Man_miniFullKit.pdf」に従って一通りの作業が終わっているものとします。また、実際に実行したプログラムですが、サンプルにあった「mini1.c」を修正して使っています。 ■プロジェクトの新規作成とデバッガで実行
次に、「Man_miniFullKit.pdf」の7.1.2.を読むと、「STARTUPファイルはCDからコピーして云々」とあるので、よくわからないのですがCDからコピーします。KD30を使わない場合は不要かもしれません。 そしてプログラムを書きます。今回は、軽く勉強ということで、mini1.cを、sfr26.hにあわせて書き換えたものを使いました。このsfr26.hというヘッダファイル、M16C/26のレジスタ定義等が定義されているヘッダーファイルです。H8/3664とかやられている方ですと、「3664.h」とか言うとわかりやすいでしょうか? ※追記:以下のソースコードですが、後で"sfr26.h"を見直していたら、p7_addr.byteはp7へ、pd7_addr.byteはpd7に#defineされていました。よって、main()関数の中は、特に修正は不要であることに気づいてしまいました。 //-------------------------------------------------------------------------------------- // ファイル名: LedBlink.c // 内容: LED点灯(LED2,3を交互に点灯 ソフトウエイト) // OAKS16KITのmini1.cを基本として、sfr26.hを使用するように変更 //-------------------------------------------------------------------------------------- // インクルードファイル #include "sfr26.h" // プロトタイプ宣言 void _main(void); // マクロ定義 #define LED2_on 0xdf // LED2(p75)点灯 #define LED3_on 0xef // LED3(p74)点灯 #define LED_off 0xff // LED消灯 main(){ unsigned long i; p7_addr.byte = LED_off; // ポート7出力H(LED消灯) pd7_addr.byte = 0xff; // ポート7方向出力 for(;;) { p7_addr.byte = LED2_on; // LED2点灯 for(i=0x4ffff;;){ // 時間待ち(ソフトウエイト) i--; if(i==0) break; } p7_addr.byte = LED3_on; // LED3点灯 for(i=0x4ffff;;){ // 時間待ち(ソフトウエイト) i--; if(i==0) break; } } } 後はビルドして、とりあえずデバッガ(KD30)でテストしてみましょう。LEDがmini1.cと同じようにチカチカ点滅するはずです。 ■TMにMOTファイル作成の設定を追加 アイテムの編集」−「コマンド」を選択すると、次のウィンドウが表示されます。これには、ビルドの最後に実行されるコマンドが記述されています。 「新規」ボタンを押して、ここに、「$(LMC) $(LMCFLAGS) $(OUTDIR)\$(ABSFILE)」を追加します。 これでビルドすると、拡張子が「mot」のファイルができあがります。これを「Flash Starter」で書き込めばOKです。 ■SAKURAエディタ ■最後に
| ||||||||||||||||||||||||||||||||||||
2004/08/30 |
.tmkを眺めていたら というわけで、昨日、motファイルのために追加した「$(LMC) $(LMCFLAGS) $(OUTDIR)\$(ABSFILE)」ですが、.tmkファイルの上のほうに、$(LMC)の定義が書いてありました。「LMC30」というプログラムです。ビルドすると、 「LMC30 -L 出力ディレクトリ\ほにゃらら.x30」 というコマンドラインとして実行されると思います。試しては無いですけど、コマンドライン派の方は、よかったらお試しください。 ところで、TWO LEGSさんのところで、「OAKS16-MINIで遊ぶ」というコンテンツが追加されています!おおっ。オークス電子でテクニカルニュースがあるんですね!早速チェックしてみよう。さらに…ネコの顔が丸くなっています。え?え?いつから丸くなってました???(前のも捨てがたい…)
| ||||||||||||||||||||||||||||||||||||
2004/09/02 |
OAKS16-MINIのサンプルmini5.c シリアル通信速度の設定 20,000,000/19,200/16 - 1 とあります。20,000,000は20MでCPUクロック、19,200は転送速度、じゃあ、この「/16」はいったいなんなんだ〜?ハードウェアマニュアルを読んでも、周辺クロックを使用するようなことは書いてありますが、「1/16」なんてのはでてきません。 そういうものと覚えておけばいいのかな〜?と悩んでいたら、TWO LEGSのわたなべさんがヘルプしてくれまして、手元のマニュアルでも確認してみました。転送速度レジスタのところには書いてないのですが(そもそも、これが原因)、「rjj09B0033_m16chm.pdf」のP118のブロック図をよく見ると、「UiBRG」の前に、「1/16」と書いてある箱があるのを発見しました。そして、遂に!P133に「fj/16(n+1)」の計算式を見つけたのです。ふうふうふう。大変でした。きっと、わたなべさんからの書き込みが無ければ、一生、「そういうもんだ」とあきらめていたに違いないです。 よし、これで、「u0mr」とかを「u1mr」に変更すればOK!(UART0とUART1は、たぶん同じ機能) そう簡単にはいきませんでした。 割り込みベクタテーブル??? ロボットやり始めの頃、ちょっと秋月電子で扱っているコンパイラを触った時に、そんなようなことがあったような気がしました。というわけで、「sect30.inc」に書いてある .lword dummy_int ; uart2 receive(for user)(vector 16) .lword dummy_int ; uart0 transmit(for user)(vector 17) .glb _receive ; .lword _receive ; uart0 receive(for user)(vector 18) .lword dummy_int ; uart1 transmit(for user)(vector 19) .lword dummy_int ; uart1 receive(for user)(vector 20)こんなふうに修正します。 .lword dummy_int ; uart2 receive(for user)(vector 16) .lword dummy_int ; uart0 transmit(for user)(vector 17) .lword dummy_int ; uart0 receive(for user)(vector 18) .lword dummy_int ; uart1 transmit(for user)(vector 19) .glb _receive ; .lword _receive ; uart1 receive(for user)(vector 20) これによって、M16マイコンは、receive()という関数が、UART1の受信割り込みになっていることを知るわけです。「sect30.inc」を眺めていたら、一通りの割り込みが書いてありますので、必要に応じて書き換える必要がありますね。 よく考えてみると、これって、マイコンプログラミングをしていたらあたりまえのことなんですよね?う〜む。いやいや、何事も勉強勉強!
| ||||||||||||||||||||||||||||||||||||
2004/09/06 |
うぅ、夏ばて? OAKS16-MINI、引き続き、シリアル通信です。新しいものをやるのは、実に楽しいです。でも、オークス電子さん、こういう誰でも作りそうなものは、サンプルライブラリみたいな形で用意しておいた方が、よく売れると思います(ひょっとして、もうある???)それか販売してる方とか…最近、OAKS16-MINIも取り扱っている、チャーリーさんとことかでやってくれないかなぁ〜。 シリアル通信の初期化方法 それでは、先日の式で、転送速度レジスタにセットする値を計算してみます(四捨五入してます)。
うむ。4800bpsと2400bpsは255をオーバーしてしまいました。転送速度レジスタ(UiBRG)は、8ビットですから、セットできません。う〜ん。どうしましょう。てぃろりろりん♪送受信制御レジスタ(UiC0)で、f1sioを使用しているのを、f8sioにすれば、さらに1/8になりますから、それでOKです。 というわけで、4800、2400bpsの場合は、こんな式になります。
でも、これはプログラムで切り替えることにします。というわけで、まずは、転送速度を定義します。ついでに、GDLに慣れてしまっているので、_BYTEと_WORDも定義してしまいました。 typedef unsigned short _WORD; typedef unsigned char _BYTE; typedef enum { BPS2400 = 521, BPS4800 = 260, BPS9600 = 130, BPS19200 = 65, BPS38400 = 33, BPS57600 = 22 } RSCbps; はたと、「H8/3664の時みたいに、charが実はunsignedとかでハマることは無いだろうか?」と心配になりました。どうやら予感的中です。M16もunsignedみたいです。ま、でも、わかっていればそれまでなので、気を取り直して、今回作った初期化ルーチンです。ポイントは、渡された値をチェックして、f1sioかf8sioを再設定するようにしてみました。 void RSCinit( RSCbps tBps ) { u1mr = 0x05; // 送受信モ−ドレジスタ 内部クロック、非同期、 // 8ビット、パリティなし、スリープなし if( tBps > 0xFF ){ u1c0 = 0x11; // 送受信制御レジスタ クロックはf8SIO u1brg = (_BYTE)( tBps/8 - 1 ); // CLKが1/8になるので、BRGも1/8にする。 } else{ u1c0 = 0x10; // 送受信制御レジスタ クロックはf1SIO u1brg = (_BYTE)( tBps - 1 ); // 転送速度レジスタ } u1c1 = 0x05; // 送受信制御レジスタ1 送受信許可 } 送信処理 2つ、同じ意味と思われるフラグが存在します。 送受信制御レジスタ0の「送信レジスタ空フラグ(UiC0/TXEPT)」と、送受信制御レジスタ1の「送信バッファ空フラグ(UiC1/TI)」は、説明文は違うのですが、どうやら動作は同じようです。ただ、割り込み要因として指定できるのはTXEPTの方みたいなので、こっちの方が由緒正しいのかもしれません。試しに、両方やってみたのですが、どちらも結果は同じでした。 void RSCsend( _BYTE bData ) { while( ti_u1c1 == 0 ); // ti_u1c1が1になるまで(バッファが空)待つ u1tb = (_WORD)bData; // 送信バッファレジスタにセット } 受信処理 _BYTE RSCrecv( void ) { _WORD wData; while( ri_u1c1 == 0 ); // 受信完了が1になるまで待つ wData = u1rb; // 受信バッファから取り出す。 return((_BYTE)( wData & 0xFF )); } ふむ。これでOKって感じです。今回、バッファチェックは、それぞれの処理中に書いていますが、これを、チェックルーチンとして独立させると「受信待ちせずに、データがある時だけ受信する」という処理ができます。SIPHA COREでも、送受信両方とも、このような使い方をしています。 こんなんでいいのかな???間違ってたら教えてくださいね〜。 で、この後、まだ未解決のよくわからない問題にブチあたるのであった。う〜ん。また後日。 いや、文字列送信関数RSCputs( char* )なんてのを作ってね、RSCputs("abc....")って書いてみたらコンパイルで警告(far pointer (implicitly) casted by near pointer)がでるんですよ。んで、よくわかんないんで、RSCputs( const char* )にしてたら出なくなったんですが、端末に表示されるはずのデータが表示されないわけです。う〜む。現在、調査中です。
| ||||||||||||||||||||||||||||||||||||
2004/09/09 |
送信処理続編 ハードウェアマニュアル(rjj09B0033_m16chm.pdf)の「図13.2 UARTi 送受信部ブロック図」をよく見ると、「UiTB(送信バッファレジスタ)」から「送信レジスタ」データが転送され、そこからデータが送信されている図画描いてあります。つまり、送信処理は、プログラムから「送信バッファレジスタ」にデータを書き込み、それが「送信レジスタ」に転送され、そこからシリアル化されて送信されるわけですね! そんなわけで、送受信制御レジスタ0の「送信レジスタ空フラグ(UiC0/TXEPT)」は、実際にデータを完全に送りきった場合にフラグがセットされ、送受信制御レジスタ1の「送信バッファ空フラグ(UiC1/TI)」は、「送信バッファレジスタから送信レジスタにデータが転送された時」にセットされるということみたいです。図で書くと、次のような感じでしょうか。
そんなわけで、「UiC1/TI」をチェックして送信バッファレジスタにデータを設定すると、「データは送っているとは限らないけど、プログラムからみたら、新データを設定していいタイミング」で設定することになり、「UiC0/TXEPT」をチェックして送信バッファレジスタにデータを設定すると、「完全にデータを送りきった後のタイミング」で設定することになりますね。 実際、送信レジスタが空であれば、Step 2からStep 3は一瞬だと思いますし、プログラムでのフラグチェックも、シリアル通信速度から見ればぐっと速いので、一番確実そうな「UiC0/TXEPT」でのチェックで送信するようにしようと思います。なんとなくもったいないのですが、ベーシックなものとしては良さそうです。文字列送信とかでスピードが気になることがあったら、連続データ送信用に別途用意すればいいかと思います。というわけで、割り込み無しの送信処理は、 void RSCsend( _BYTE bData ) { while( txept_u1c0 == 0 ); // txept_u1c0が1になるまで(送信レジスタが空)待つ u1tb = (_WORD)bData; // 送信バッファレジスタにセット } としておくことにします。 と、書いていたら、TWO LEGSのわたなべさんからもフォローの記事が…みなさん、ありがとうございます〜。
| ||||||||||||||||||||||||||||||||||||
2004/09/15 |
2004/09/06のTOPICの最後にボソボソっと書いた、「関数に文字列を渡すのに警告が出て、あげくの果てに渡されていない模様」みたいな話ですが、未だに解決してなかったりします。たぶん、コンパイラのクセだと思うんで、解決すれば早いんでしょうけど…。 というわけで、ちょっとシンプルなコードを作ってみました。デバッガ前提なので、シリアル出力処理はつけていません。 #include "sfr26.h" void main( void ); void strCopy( char* szDest, char* szSrc ); char szWorkG[32]; void strCopy( char* szDest, char* szSrc ) { int nCnt; for( nCnt = 0; szSrc[nCnt] != '\0'; nCnt++ ){ szDest[nCnt] = szSrc[nCnt]; } szDest[nCnt] = '\0'; } void main( void ) { char szWorkL[32]; strCopy( szWorkG, "ABC" ); strCopy( szWorkL, "ABC" ); strCopy( szWorkG, szWorkL ); while( 1 ); } これをコンパイルすると、無情にも、
といわれます。さらに、デバッガで動作を追いかけてみると、思ったような値がstrCopy()のszSrcに入ってないようです。警告を読むと、なんかnear pointerのところに、far pointerを無理やり入れてしまったようです。このnearとfar、直訳で「近い」と「遠い」という意味でなんのことやら?ですが、実はポインタ(データや関数のアドレスを指す変数)には2種類あるようで、nearは2バイト - FFFFのアドレス空間を指せる、farは4バイトだけど実は3バイトで 0 - FFFFFFのアドレス空間を指せるポインタになります(わたなべさん、説明ありがとうございました)。で、ハードウェアマニュアルを読むと、RAMは前の方、ROMは後ろの方にあって、ROMがfar pointerなようです。対して、RAMは前の方なのでnear pointerになると。 これをコードで意識するとなると、結構、大変な気がするのですが、みなさんどうされているんでしょうか?例えば、strcpy()のコピー元って、"ABC"と渡したい時もあれば、文字列を編集して渡す(RAM上の変数)こともあるわけです。どうしたらいいんでしょう?悩んだあげく、コンパイルオプションを試してみることにしました。 -ffar_RAM 「RAMデータのデフォルト属性をfarにします。」というオプションです。意味が良くわかりませんが、それっぽいので、試してみることにしました。どうやってTM上でコンパイルオプションを変えるのか、わからなかったので、makeファイル(〜.tmk)のCFLAGSの行を直接編集しました。 リビルド〜! 何か、深そうなもの変更した時は、何はともあれリビルドしましょう。
う、また難しそうなものが…。0FFFFFHを越えているぅ???う〜む、なんか違うっぽい…。
| ||||||||||||||||||||||||||||||||||||
2004/09/16 |
いろいろ考えていたんですが、なんか、根本的に理解しないといけない部分がある(ようは知らないコトがある)ような気がしてきました。というわけで、オークス電子さんがアップされている、自習用テキストを読み始めました。今はOAKS16プログラミングテキストの方を読んでいます。ふむふむ。NC30が管理するセクションがウンたらかんたら。何はともあれ、環境(クセとか決り文句)を覚えて慣れないとね! ところで、デバッガでデバッグするのって、フラッシュROMの書き込み回数にカウントされるのかな?素朴な疑問です。
| ||||||||||||||||||||||||||||||||||||
2004/09/17 |
_farですよ、_far 「標準関数はどのように定義されているんだろう?」 NC30は、標準関数ライブラリが用意されているので、このヘッダを覗いてみることに。探してみると「MTOOLS\INC30」にヘッダが入っていました。
う、ここにそう書いてあるではないか…。先に、こういうところからチェックすればよかった…。みなさん、すいません。わたなべさんのいわれるように、"far"は、"_far"なんですね。うむうむ。というわけで、宣言を修正(ついでにヘッダファイルに書いてあるように、変数名を書かないタイプに修正)して、実体の方も修正して…と。
りびるど〜! あ、ビルドできました。 よし、デバッガで確認だ!strCopy()を呼び出しているところでブレークポイントを仕掛けて 「りせっとよぉぉしぃ、ごぉぉぉっ!すてっぷ、すてっぷ、すてぇ〜っぷぅぅぅ!」 お、いいですね。ちゃんとデータが設定されるようになりました。よし、これでまた一歩、この環境へ馴染みました。というわけで、明日は、シリアル通信プログラムに戻ることにします。 みなさん、どうもご指南ありがとうございます〜! というわけでデバッグのやり方・変数内容チェック
はい、ここで、表示するソースファイルを指定します。 で、ソースファイルが表示されたところで、変数を選択状態にして、右クリックメニューを表示し、「Add C Watch...」を選択すると、「C Watch Window」が開き、変数が追加されます。もちろん、「C Watch Window」をあらかじめ開いておいて、「Add」操作で開いても構いません。
「文字列データじゃわからない〜」ってことはありません。この「C Watch Window」で変数を選択してダブルクリックすると、中身を見ることができます。よくできてる、うんうん。 というわけで、先ほど修正したソースコードで、ステップ実行させた時の変数表示です。思ったとおりの値が入っていることがわかります。 また、このように、グローバルなデータだけではなく、ローカルなデータも表示することができます。 ふぅぅ、長かった〜。でも、偉大なる第一歩!
| ||||||||||||||||||||||||||||||||||||
2004/09/23 |
送信処理、結局こうなりました。
んで、考えたんですが…実は、「送信バッファレジスタから送信バッファに送る速度は、実は超高速ではない」のではないか?と推測しています。良く考えてみれば、送信レジスタが空になったからといって、送信バッファレジスタにデータ突っ込むのは紳士じゃないですね〜。 ということは、「送信レジスタ空フラグ(UiC0/TXEPT)」と、送受信制御レジスタ1の「送信バッファ空フラグ(UiC1/TI)」の両方をチェックしてやるのがベスト!ということになるのですが、ま、そこまではいいかな?ということで、送信バッファレジスタをチェックするだけにしておきます。
今は、puts()とかgets()とかを作っていますので、もう少しテストができてきたら、まとめてアップします。
|
SISO-LAB Knowledge