« 2009年5月31日 - 2009年6月6日 | トップページ | 2009年6月14日 - 2009年6月20日 »

2009年6月7日 - 2009年6月13日の1件の記事

2009年6月 8日 (月)

STM32基板のRTCを動かす

 それにしてもデバッグは難しい。わかってしまえば、何でこんなことに今まで気づかなかったのだろうというお馬鹿な間違いなのだが、気がつくまでの道のりは決して短くない。まあこの謎解きが面白くて電子工作をやっているようなものだが、今度のSTM32のRTC(リアルタイマークロック)プログラムも結構手こずった。「デバッグは外へ、外へ」などと偉そうなことを常日頃言っているくせに、頭に血が昇るとつい我を忘れてしまう。

軽い気持ちで手をつけたがまるで動かない(6/2/09)
 このところ1年前の雑誌の付録基板、STM32F103(Cortex-M3) の開発に熱中し、先週、高速化したUSB仮想UARTのモニタープログラムを完成させて意気が上がっている。ウェブでもこの石を使ったCPUボードを時々見かけるようになった。価格もそう高くない(2インチ160x128のカラー液晶付きの評価ボードが¥9000で手に入る)。クロック72Mhzの32ビットプロセッサーだ。ARMコアの中では普及版だそうだが、アマチュアが遊ぶには十分すぎるスペックである。

 RTCはUARTモニターの開発のときから次の目標に決めてある。せっかくバッテリーバックアップ回路を追加したのだ。電池と32.767khzのクリスタルの顔を立ててやらねばならない。RTCはファイルシステムには欲しい機能だし(書き込みの記録)、これが動くと俄然マイコンがプロっぽくなる。幸いSTマイクロの提供するライブラリには、RTCのライブラリを使ったデモソースが収録されている。これを使えば簡単に出来るはずだ。Stm32vbat

 早速Eclipseの新規プロジェクトを作り、そこへソースコード一式を放り込む。このソースはIARなどの開発環境用なので、仮想UARTモニター同様、GNUで必要な、Makefileや、リンカースクリプト、スタートアップルーチンを入れて調整する。Makfileを換えるだけでうまく行くはずだ。必要なライブラリを取捨選択し、ビルドする。殆ど問題なくバイナリーが出来た。

 わくわくしながら、フラッシュローダーにかける。おやあ、赤ランプがついて送れない。ええー、hexファイルがないだと? ほんとだ。ファイルはあるけれど中身は0バイト。これは一体どうしたことだ。elfファイルは60KB以上あるのに。コンパイラーもリンカーもエラーは出ていない。こうなると何が悪いのか見当がつかない。

 マップファイルは出来ていたので、良くわからないままこれを調べる。あれ、関数のエントリーがみな同じ値だ。これはおかしい。でも、エラーは起きていない。念のため、必要なライブラリの数をMakefileで確かめる。一つ少ない。あれえ、stm32f10x_vecter.cが抜けている。デモソースのreadmeには、これを入れろとは書いていない。

 何と言うことだ。こいつがないからに違いない。とにかくこれを含めてビルド。おお、ちゃんとしたhexファイルが出来た。readmeを信じてえらい目にあった(このあと各開発環境のプロジェクトフォルダーにはこのモジュールが入っているのを発見した。GNUのときは注意しないといけない)。それにしても、ビルドやリンクのときのNO ERRORは安心できないことを学ぶ。

 お膝元のメーカーのデモソースである。バイナリーが出来たので簡単に動くかと思ったが、これが全く動かない。おかしい原因はおおよそ見当がついている。UARTへの出力関数printfが恐らく暴走の原因だ。これを、これまで使っていたsprintfに置き換え、受信関数も自前のものにして再度、実行。

 おお、やっとメッセージが出た。しかし、RTC not configured...のメッセージを出したまま、それっきりになる。ロジックを追うと、RTCのセットアップが終わるのをループで待っていて、ここがreadyになっていないようだ。やれやれ、ハードか。念のため電圧を測る。3.24V。この程度なら問題ないはずだ。オシロで周波数を確認する。立派に32.767khzが出ている。大丈夫だとは思うが、要因を減らしてみよう。

 バッテリーバックアップをやめてVccにつなぎなおす。うわあ、RTC configuredのメッセージが出て先へ進んだ。何だ、何だ。電池が原因か。何か部品が足らないのか。

 ハードの問題は別として、これでうまく行ったと思ったら、そうは問屋が卸さなかった。時刻の設定をする受信関数が、がんとしてデータを読まない。受信関数は自前だ。自信がないので、プログラムの頭でテストステートメントを挿入してみた。いや、ちゃんと動く。しかし、時刻設定の入力では、受信データのフラグがあがらない。

 それにしても、UARTぐらいの機能で、このソースの複雑さは何だ。読みにくいことおびただしい、と悪態をつきながらデバッグする。また最適化が原因かと思ってループに、NOP_Processなどを入れるが変わらない。UARTなら、このあいだのGNUサンプルソースにもあった。こちらは至極簡単なソースだ。こいつを持ってきて動かすが、これも駄目。万策がつきる。

原因はUARTではなかった。あっけない幕切れ(6/5/09)
 UART受信が出来ない。本質と関係のないところでつまずいている。RTC不調も電池でない可能性が強い。電源を入れたままリセットをすると、RTCの初期化が途中で止まる。

 UARTの方は、その後ステータスレジスターを問題のところで出力させ不正なビットが立っていないことを確認した。どうもUARTがハングの原因ではなさそうだ。LEDとUART出力を処理の始めから、少しづつ挿入し、ハングアップするステートメントを探していった。

 その結果、RTCの割込みをenableするところでハングすることがわかる。RTC割込みがおかしい。試しに割込みルーチンにLEDを点灯するステートメントを入れるが、点かない。そうだこれに違いない。

 デモソースのバグは考えられないので、これは明らかに、Dfuのためにずらしたプログラムのエントリーアドレスが、ベクターテーブルに反映されていないことを物語る。しかし、ソースの何処を探しても、テーブルのアドレスを設定するところはない。ベクターテーブルは、リンカーの最初のプログラムのスタートアドレスから相対的に展開しているからだ(これが大きな勘違い)。そうすると、リンカースクリプトか、スタートアップルーチンか。しかしここは良く分からないところで手が出せない。

 思い余って、最近お世話になっている「ねむい」さんが、RTCを動かしたと言うので、質問しようかとページを開いたら、ソースを公開されている。質問する前に調べてみようとありがたくソースを頂く。(会社ではダウンロードできなかった)

 おお、このソースは情報の宝庫だ。ユーザープログラムで割込みを止めるステートメントもある。で、ベクターテーブルを設定するところは、どこだ。見つかった。あ、あ、あ、なーんだ。明示的に設定するのだ。

void NVIC_Configuration(void)
{ NVIC_InitTypeDef NVIC_InitStructure;
  /* Set the Vector Table base address at 0x08003000    for Dfu  */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x3000); 

 早速、このステートメントを追加し、コンパイルしなおす。苦もなく動き始めた。全く問題ない。1秒ごとにLEDが点滅し、UARTに時刻が表示される。RTCの出来上がりである。これで、この週始めから悩んでいた問題がすべて解決した。いやあ、知らないと言うことは恐ろしい。NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); のステートメントでもあれば気がついていたかも知れないが、それにしても「ねむい」さんに感謝である。Stm_rtc

 しかし、何故、割込みが原因だということに気がつかなかったのだろう。UARTの不具合と頭から思い込み、こればかりを追求していた。RTC割り込みは1秒である。ちょうど時刻設定の入力と重なる頃だ。一瞬入力が出来たときもあり、少し冷静に考えれば、このとき不具合がUARTでないことにもっと早く気がつくべきだった。

 電池が入っているときに動かないのは、時刻設定をしないで単に時刻表示に行くからで電池が原因でハングアップしていたわけではない。しかも、付録の雑誌の7月号には、このベクターのオフセットをしないとデモなどは動かないよ、とわざわざ解説がステートメント付きで載っていて、これを読んでいたはずだ。この前の仮想UARTのhw_config.cにもちゃんとベクターのシフトがコーディングされている。今になって考えるとヒントはそこらじゅうにころがっていたのだ。お恥ずかしい限りである。

| | コメント (10) | トラックバック (0)

« 2009年5月31日 - 2009年6月6日 | トップページ | 2009年6月14日 - 2009年6月20日 »