心電計プロジェクト:CooCoxでARMの表示系ソフトを開発する
UARTのテストでつまずくがデバッガーに助けられる(9/21/2014)
少しづつCooCoxの環境下での開発を進めている。Lチカはうまく行ったので、次は定番のUARTである。UARTでモニターを作ればCPUの動きをとりあえず完全に把握できる。CooCoxにはリポジトリ一覧画面があり、そこから数多くのサンプルソースを得ることが出来る。適当なUARTのサンプルを見つけてきてプロジェクトを作った。
割り込みを使った送受信サンプル、usart_txrx.cである。内容を確認する。どうも変数の名前が変だ。iとか、jなどの変数名が文字カウンターと受信データそのものに使われている。iとかjは内部のカウンターなどだけに使う名前で、具体的な意味を持つ変数には、それを連想できそうな名前にするのが、わかりやすいプログラムの定石だが、それが守られていない。
まあ、それは良いとしてもmainの中に勝手に割り込み関数の実行ステートメントが挿入されている。これおかしいよね。割り込みで飛び込んでくる関数をmainで実行しても意味がない。これ以上追及するのも大人げないので、さっさと消して先に進む。
しかけは、いつものようにPCからのキーボード受信待ちでプログラムを止め、キー入力で動く簡易なモニターである。手始めにLEDの点・消灯のコマンドを入れる。ほどなくコンパイルはOKになった。動かしてみる。送信はうまく行ってWelcomeメッセージは出るが、入力を受け付けない。 難しいことは何もしていない。それなのに、さっぱり入力データが所定のバッファーに入らない。何度もソースを見直すが間違っていない。ロジックアナライザーを登板させるのも気が引けるぐらい簡単なところなのに動かない。
そのうち、今度の環境にはデバッガーが入っていることに気が付いた。やせ我慢しないで積極的にこれを使ってみよう。ただ、このデバッガー、ブレークポイントを設定してもそこで止まってくれない(フラッシュ下では無理なのか)。
しかし、変数は表示できるので、キーを延々と打ってステップ実行で動きを追いかけてみた。AVR などと違ってさすがは32ビットマシンである。UARTの受信だけで結構なステップ数である。
その結果、原因が判明した。何のことはない、以前苦労した外部変数の宣言ミスだった。データを受け取るところと、それを取り出すところが違うので外部変数にしてあったのだが、同じ名前でもタイプが違うとエラーにもならないで別の変数になってしまう。
今度の場合は、extern宣言のとき、うっかりデータタイプをつけ忘れたのが原因である。警告は出ていたのだろうが見落とした。情けない。
それにしても、デバッガーにはお世話になった。今度のデバッガーは、UARTの入出力がデバッグ中にも動いたので助かった。デバッガーによっては、UARTのような時間依存する入出力では動かないものが多い。
これでプログラムのテストは、LEDの点滅、UARTの動作まで進んだ。ここまで来れば本番を入れても大丈夫だろう。
CooCoxに画像表示ソースを移植する(9/24/2014)
いよいよ、心電計の画像表示のプログラムをCooCoxで開発するステージに達した。2年前に開発したグラフィック気圧計のソースコード一式をCooCox環境に持ち込む。
このソースは、「ねむい」さんが開発したTFT液晶のSDカードのファイラー(ChaNさんが原型)がオリジナルで、ここの画面描画ルーチンを利用させてもらって2日分の気圧をグラフ表示している。
今回はSDカードは使わないが、買ってきたTFT液晶のコントローラーが前と同じILI9325なので(というより同じものを探して買った)、描画部分を流用しようという腹づもりである。
ねむいさんのソースは、数多くのプラットホームに対応しているだけでなく、数えきれないくらい多くの液晶コントローラーをサポートしてくれているのが嬉しい。液晶ディスプレイの初期化や、描画ルーチンはコントローラー単位に全部違うので、これだけサポートしてもらえると、安心してジャンク液晶を買うことが出来る。
ただ、その設定は、makefileでの環境変数を定義するだけで一発で動くようになっており、そのためプログラム構造が階層化され、構成は非常に複雑で一筋縄ではいかない。特に今回はmakefileが使えないので、定義をどこでやるかが問題だ。
しかし量が膨大だからと言って立ちすくんでいては先に進めない。こういうときは目をつぶってとにかくソースファイルを持ち込んでみることだ。まずは、プロジェクトのフォルダーにソース一式を放り込む。
もちろんこれだけではCooCoxはプロジェクトのリソースとしては認めてくれない。project画面でノードを右クリックすると、add group とadd filesというアイテムが出てくる。これがどうやらプロジェクトにリソースを入れるコマンドだと当たりをつける。
試しに、適当な名前で新しいgroupを定義してaddしてみるとフォルダーになった。add filesは文字通り、ソースファイルが、そのディレクトリに入るようだ。これはうまいぞ。自分の予想があたって上機嫌である。
鼻歌まじりで、沢山のソースコードをプロジェクトに入れて行く。不思議なことに、プロジェクトフォルダー内のヘッダーファイルは自動的に探してincludeしてくれる。ただしあとでも書くように、出来るところと出来ないところがある。
適当なところで、ビルドをかける。予想通り膨大なエラーメッセージが出る。まあ、これは織り込み済みだ。ここからが勝負である。ひとつづつエラーメッセージを見ながらつぶしていく。1日半かけて、やっとのことで全体のコンパイルエラーはなくなった。
動くかどうかは全く分からないが少なくとも、画面を出すルーチンはNO ERRORになった。同じようなことをやろうとしている方と、これからの自分のために(備忘録として)、遭遇したエラーの数々を簡単にまとめておく。
- _IO というデータタイプ(CMSISのvolatile の代わりに使うタイプ宣言)が何故かsyntax errorになる。--> volatileに戻してOK。うまく行っているソースもある。?である。
- stm32ペリフェラルライブラリーのincludeを明示的にしないと引かないモジュールがある。 -->わけはわからないが、その都度、#includeを追加してOK
- falseという汎用的なシンボルが未定義でエラーになるソースファイル( term_io.cなど )がある。これは前もそうだった記憶が。 -->適当に#defineして追加。
とりあえずコンパイルは通った。ちょっとした達成感に満足する。 ただこの段階は壮大なオペラで言えば単に序曲が終わったくらいのところで、これからが何幕もある本番に入る。どんなドラマが待っているか、期待と不安が高まる。わくわくどきどきのこの気分はいつもたまらない。
printfでsegment fault(9/25/2014)
とはいえ、環境の異なるところへの、まとまったソース群の移植はそう簡単にはいかない。しかも、CooCoxは、makefileもリンカースクリプトも見えない統合環境である。果たしてこのまま動くかどうかは何の保証もない。
だいたい、このプログラムのUARTそのものは、ねむいさんのコードでは、printfが使われていた。ややこしいので最初はコメント化し、自前の別の出力関数を使うつもりをしていた(そのためのUARTテストでもある)。
しかし、途中で計画を変更した。たまたまCooCoxのリポジトリを見ていると、その中にsyscalls.cがあるのを見つけた。printfは、標準入出力ライブラリを使うので、こうしたサポート関数が必要なのだが、CooCoxが持っているということは、メモリ管理をしてくれているということだ。このまま動くかもしれない。
喜び勇んでsyscalls.cをincludeし、printfのコメントをはずしてコンパイルしてみる。おおー、通った。NO ERRORだ。ただし、フラッシュは一気に30KBを越えた。まあ、フラッシュは128KBあるのであまり心配しない。
まだTFTディスプレイは実装していないので、画像表示部はコメント化したまま、とりあえずUARTだけ動かしてみる。わくわくしながらフラッシュを書き込んだ。JTAGのおかげで30KBを越えるファームも数秒でロードされる。だめだ動かない。PCには何のメッセージも出ない。しかし、今度はデバッガーという強力な味方がいるので先に進める。
よーし、USARTの初期化は順調に動いているようだ。USARTの出力直後にハングしていることがわかる。ふーむ、割り込みベクターがおかしいので、送信のあと、おかしなところへ飛んでいるようだ。そういえば、ねむいさんのオリジナルからNVICの初期化をするルーチンをmain.cからはずした。
これはベクターテーブルをSRAM領域か、FLASH領域にするかをリンカースクリプトで決めるルーチンだった。今回はリンカーが見えないので、defaultに戻そうと削除したやつだ。必須なのか。だめもとで、このルーチンを復活させる。
動いた!コンソールにWelcomeメッセージが出た。いやあ、嬉しい。いそいそと次のモニターの部分の受信ルーチンを、全くダミーだったmain()のループに入れていく。さあどうだ。あらら、またsegment faultだ。
今度のエラーはどうも根が深い。ステートメントを少しづつ増やしていくと突然ハングに入る。何か予感がしたので(このへんが長年の経験によるカンだろう)、printfをはずして、自前のcputsというUARTストリング関数に換えてみた。
ピンポン!である。全く問題なく動いた。printfのメモリー制御部分のエラーである可能性が高い。さっきのsyscalls.cがうまくいっていないことは確かだ。なにしろメモリーのレイアウトは全く手さぐりである。リンカースクリプトが見えないのでいじりようがない。
CooCoxのFAQでprintfが解決(9/26/2014)
このまえの仕事が一段落し、事務所のPCでネットを見ていたら、CooCoxの本拠サイトでprintfに関するFAQを見つけた。printfを動かす手順である。これだ、これこれ。結構複雑だ。後学のために、邦訳しておく。
(1)スタートアップルーチン(startup_stm32f10x_md.c)で以下を追加する。
#define STACK_SIZE 0x00000400 //スタックサイズの拡大(最初は0x100) //余り大きいとSRAM容量を超えるので注意
__attribute__ ((section(".co_stack"))) //スタック領域を実際にとる
unsigned long pulStack[STACK_SIZE];
(2)メインルーチン(int main())で、以下を追加する。
/* Set unbuffered mode for stdout (newlib) */
setvbuf( stdout, 0, _IONBF, 0 ); //stdoutをバッファリングしない
#include <stdio.h> //もちろん、本体をインクルード
さらに、CooCoxのRepositry画面で、commonの項目から、C Libraryを選んで、syscalls.cを加える(これはもう済んでいる)。
(3)configuration画面で、Linkタブを選び、LibraryでUse base C libraryを選択して、Linked Librariesの入力枠にm(小文字のmだけ)をAddする。これは何のためかわからないが、言われる通りにする。
帰宅して早速試してみる。Configuration画面でリンカーのオプションがいじれるようになっているとは知らなかった。少しづつCooCoxの環境に慣れてきた。
FAQはSTM32F4xxシリーズ用だが、必要なステートメントはF10xにもあったので大丈夫だと思う。動かしてみる。おおー動いた。スタックサイズが微妙で、オリジナルの256バイトではハングする。4KとるとSRAMがもう一杯と怒られる。1K(0x400)で十分動いた。
自分の予測や見込がぴったり当たって思い通りの結果が出るというのは、どんなささやかなことでも嬉しいものである。いつもながら幸福(しあわせ)な気分を味わう。電子工作の醍醐味のひとつだ。いや、喜んでいるばかりでは先に進まない。TFTはどうした。そう今度はハードの配線が待っている。
新しいジャンパーコードが活躍。しかしTFT液晶基板動かず(9/27/2014)
気を良くして、いそいそと次のハードの工作に移る。CPU基板からTFT液晶ボードへの配線は、このあいだ買ったサンハヤトのスルーホールに差すジャンパーを使うことにしている。
8ピンバスを使うので配線量は少ない。思っていた以上に簡単にうまく行った。ハードの準備はあっけなく終わって、残るはディスプレイのドライバーソフトである。最後の難関だ。TFT液晶のドライバーの初期化さえ動いてしまえば、あとの画面表示の開発は楽しいプログラミングになる。
このねむいさんのコードは、大量の数のディスプレイをサポートしている。そのための抽象化が何段にもわたっているのでとても複雑だ。不要なコードを消しつつ、慎重に何度も確かめながらアサインしていく。Eclipse風の、ソースコードでのマクロ定義や、#ifdefを区別してくれるCoIDE(CooCoxの統合環境名)の環境は、こういうときにありがたい。
ただ、ILI932x.cは何故か、16ビットモードにしかならず、新しい#defineシンボルを新設して強引に8ビットアサインに変更する。何度か失敗しながら(#undefで一旦、前の環境変数をクリアし、また#defineで定義し直すなどの小細工)、やっと実際のピンと関数の中の変数が一致した(CoIDEで確認できる)。
ピンアサインと初期化ルーチンの確認をすませ、いよいよ、これまでコメント化したTFTディスプレイの初期化のルーチンを本番に戻し、TFTを生かしたテストに入る。
ディバイスコードは出るのに反応なし。またTFT液晶基板の不良か(9/30/2014)
2日間がんばってテストしたが、結論は残念ながらタイトル通りの結果である。最初は全くの門前払いだった。printfでdeviceコードを出力させて調べてみると、何と、このTFT液晶(LM024C9325)のコントローラーはILI9325ではなく、ILI9328だった。
店のウェブ記事では9325と明記してあり、型番がいかにも9325風なので、すっかりだまされていた。あわてて、9328の初期化シーケンスをねむいさんのソースライブラリから抜き出し、取り換える。しかし、それでも液晶画面は白いままである。初期化によって画面は黒くなるはずだが変化がない。
コマンドを送って、正しいdeviceコードを返しているのに(8ビットモードであることはジャンパーをわざと外して確認)、次の初期化で画面が黒くならない(レクタングルを黒で塗りつぶす)のは、やっぱりハードが悪いと結論するのが自然なところだろう。
deviceコードを返すコマンドが正しく動いていることは、データラインのジャンパーを外してみると違った値になるので間違いはない。移植のときのミス(何しろ変則的な使い方をしている)を疑って、別のサイトから初期化シーケンスを持ってきて試してみたが、やはり同じだった。やれやれ、基板不良の可能性が高い。
もし、これでこの基板が不良なら、Aitendoで買ったディスプレイの不良率は軽く30%を越えることになる(7枚のうち2枚完全不作動、1枚画面一部欠落)。しかし、ここほど安くて沢山の種類が選べるところは他にない。こんなものと諦めてまたここで買うしかないか。
残念ながら、店は国慶節の休みに入っていてすぐに買いに行くことができない。ブログに書いた原稿を編集しながら時が来るのを待つ。
2台めも動かない。これはハードではないだろう(10/3/2014)
Aitendoの新しいリアル店舗を訪ねる。末広町の東北、もう御徒町に近いところで秋葉原から少し遠くなった。広さは倍くらいあるだろうか。店員の数も増えた。最近ニューヨークに上場したAlibabaの電子材料店舗群に比べれば値段ははるかに高いが、それでも日本では破格の安さだ。特にリアル店舗は実際に手に取ったりできるのがありがたい。
TFT液晶を2台買う。1台は、2.4インチの前と全く同じILI932xを使ったもの、もう一つはArduino用という、3.5インチで320x480のTFT液晶を衝動買いした。安かったので(¥1980)、つい買ってしまったが、また部品箱の肥やしになりそうである。
帰宅してとるものもとりあえず、TFTのテストをする。ジャンパーを取り換える。これは便利だ。すぐ終わった。期待をこめて電源ON。ややや、画面は白いラスターのままである。何と、これでも動かない。期待が大きかっただけに、がっくりくる。
まさか、2台とも不良ということは、いくらチャイナクオリティだと馬鹿にしていても、ちょっとありえない話で、これは、こちらの初期化の失敗とみるのが順当なところである。
メモに症状をもういちど書き直して、対策を練る。データシートをダウンロードして、いちから調べ直しだ。STM32の方は、オリジナルのGPIOEポートをGPIODに変更しているが、全く問題ないことを確認した。
一番あやしいのは、8ビットモードがILI932xで最初、定義できなかったことだ。強引にピンを割り当てたが、プログラム中での16/8ビットモードの書き分けが心配だ。ソースコードをしらみつぶしにして、#ifdefで分けていないか探す。コマンドを出す関数で1ヶ所、変更されていないところを見つけた。これだ!これにちがいない。喜び勇んでビルドし直し、テストする。
いや、やっぱりだめだ。同じような白ラスターが出るだけである。リセットしたときのような点滅もない。こうなったら、コントローラーの動きを最初からチェックして、少しづつ正しくコマンドがコントローラーに送られていることを確認するしかないか。
ロジアナで派手に波形を出しても正常。暗礁に完全に乗り上げる(10/9/2014)
ロジックアナライザーに目いっぱいのプローブをつけて動作解析である。液晶の制御ピンに5ピン、データバス8ピンにグランド、合わせて14ピンがジャンパーケーブルに群がる。壮観な眺めである。ただ、このロジアナ(ZEROPLUS)のプローブは出来が良く、着実にピンを捉えるので使いやすい。
救いはJTAG関係が好調で何度でも簡単にビルドしてテストが続けられることだ。ロジアナで所望の波形はすぐ得られた。最初、データバスのenable信号WRが出ていないところを発見し、これだ!と色めいたのだが、サンプリングが遅すぎることに気が付き、戻したらちゃんと波形が出ていてがっかりする。
初期化は順調にやっている。時間遅れもぴったり。8ビットコードで2回WRやRDを出していることも確認できた。何だ。ちゃんと制御信号を送っているではないか。最後の制御コマンド、0x07(display on)も、所定通りのビットが立っている。問題ない。
これで完全に暗礁に乗り上げた。ディバイスコードが正常に戻っていて、波形も正常。それで動かない。うーん、もしかして、2台目も不良? 信じたくはないが、客観的な状況はそれを物語る。しかし、ちょっと有り得ない話で、3台目を買いに行こうという気にはならない。
やることがなくなって、とうとう、また、ねむいさんに助け舟のメールを出した。これで何回目か。まあ、すぐには返事は来ないだろうから、少し頭を冷やす良い機会と、TFT液晶とARMのソースの解析を続ける。
いろいろ勉強させてもらった。 ARMのGPIOの特殊な使い方(BSRR BRRレジスター、IDR、CRLレジスター)や、ディスプレイコントローラのロジックなど、こういう機会でなければ勉強する機会がなかったところに、すっかり詳しくなった。
やっとのことでTFT液晶が動いた。カラーバーが眩しい(10/14/2014)
ほどなく、ねむいさんから丁寧な返事が来て、色々な助言を頂いた。こちらの状況を報告しながら、少しづつ言われた処理を試していく。メールのやりとり数度、しかし、事態は好転しない。ブログの記事も、もう一か月近くご無沙汰だ。そろそろ出さないと書き溜めた記事が古くなってしまうと思っていた矢先、問題は一挙に解決した。
これが面白いことに、ねむいさんがソースの不具合に気づいて知らせてくれたのと、自前で暫定的に初期化に成功したのと1時間も差がないというドラマティックな展開となった。いやあ、みなさんから時々、波瀾万丈とか七転八倒とからかわれるけれど、まさしく今度も劇的な結末となった。
発見の端緒は、CS(チップセレクト)ピンの不審な挙動である。初期化の途中、なぜかCSがdisableになってしまっている。始め気が付かなかったが、長いスパンで波形を見ていた時発見した。ねむいさんにはこれを知らせてあったので、これをヒントに不具合を見つけられたのだと思うが、ロジアナの波形には、はっきり映っている(添付のロジアナ画像の丸で囲んだところ)
もしかしたら、CSの結線がされていないからかもしれない、と最初は思った。でも、Highにするとdeviceコード読み取りそのものが動かなくなるので、CSが効いていることは間違いない。しかし、初期化の途中で何故CSが上がるのか。
試しに、コマンドの中に、CSをset/resetするコードを加えて動かしてみる。これで大部分は、その通りになったが、まだごく一部でCSが暴れる。おやあ、TFT画面を見ていると何か少し変化したぞ。ふーむ、ピンへの出力がパワー不足か。ピンをプルダウンしてみる。これは効果なし。ただ、前のように全く無反応ではなく、画面がほんのわずかだが暗くなった(ような気がする)。
それではいっそのこと、CSピンを強制的にグランドに落としてはどうか。STM32のGPIOピンに悪影響があるかもしれないが、まあ壊れることはないだろう。そうだ、はずしておけばよい。乱暴だが入力ピンをはずして、液晶のCS端子をグランドに落として(enable)、リセットする。
あっあっあ、画面が真っ暗になった。ひやっほー、初期化に成功した。間違いない。念のため、clearを赤でしてみる。見事、画面が赤くなった。やったやったぞ。いやあ嬉しい。これを電子工作の醍醐味というと誤解されそうだが、うまく動かないからこそ、この喜びは何にも代えがたいのだ。
気分が落ち着き、PCでネットを見たら、ねむいさんからメールが届いていた。おおお、不具合が見つかったという知らせだ。時間を見るとちょうど自分が見つけた時とほぼ同じ時刻が発信時刻だった。何という偶然。
ILI932x.cというドライバーを8ビットモードで使って、しかも、データピンとコントロールピンを同一のポートで定義しているときにのみに起きる現象のようだ。恐らく、私のCSピンの動きをみて発見されたのだろう。
原因は、実にささいな1ステートメントの定義違い(8ビットのところへ16ビットデータをぶちこむ)なので訂正は、わずか一か所(8ビットキャストをするだけ)である。これで、めでたく、CSを強制的にenableにしなくても正常に初期化された。
動きの確認のため、早速やっつけでカラーバーを出すコマンドを作ってテストする。問題なく出た。赤、緑、黄、青の4色の鮮やなカラーバーが眩しい。いやそれにしてもこの10日余りは地獄の日々だった。 しかし解決の美酒はこのうえなく美味い。でもソフトウエア開発の難しさを改めてかみしめる。これが仕事でなくてよかった。
| 固定リンク
「電子工作」カテゴリの記事
- 生存証明2(2022.10.19)
- 生存証明(2022.01.23)
- パソコン連動テーブルタップの修理を諦めて自作(2021.02.16)
- 半年ぶりのブログ更新に漕ぎつけた(2019.09.19)
- 研究所活動は停滞したままでCCDカメラ顕微鏡導入など(2019.02.08)
「ARM」カテゴリの記事
- 心電計プロジェクト:スケールが出ると心電計らしくなる(2015.01.08)
- 心電計プロジェクト:TFT液晶に念願の心電波形が出た(2014.12.18)
- 心電計プロジェクト:STM32F103の心電波形表示で悪戦苦闘(2014.12.03)
- 心電計プロジェクト:CooCoxでARMの表示系ソフトを開発する(2014.10.16)
- 心電計プロジェクト:表示部のARM基板の開発環境を一新する(2014.09.19)
コメント
shuji009さん、コメントありがとうございました。
記事にも書きましたけれど、この達成感がたまらない。
今回のも、ねむいさんのソースが16ビットモード専用だったのを
無理やり8ビットにして、はまっていました。
昔、私の先輩で、PCゲームソフト全盛の頃、ショップに行って、
「一番コピープロテクトの強いやつをくれ」といって一生懸命
はずしていた猛者がいましたが、これに近いかも。
ロンドンはもうそろそろ1年になるんじゃないですか。
すっかりお慣れになったようですね。
あちこち旅行されると楽しいですよ。
投稿: がた老 | 2014年10月17日 (金) 23時04分
がた老さん、お疲れ様です。
16ビットのカラーTFTを8ビットで使うのは色々と泣かされますね。
私も以前ATMEGA128のバスモードでAitendoの液晶を使うときにはまりました。バスモードでダメだったのでGPIOモードにしてなんとか動作させ、その後、「妥協の電子工作」さんHPを参考にしてバスモード動作までさせました。
http://shuji009.blog.eonet.jp/default/2012/10/qvgasd-atmega12-3fb1.html
ところで、今週、訳あってロンドン内で引っ越ししました。まだ片付いていない状況です(笑)。近場から近場です。色々と勝手が違ったりして困っています(汗;)。特にガスが使えたり使えなかったりしているのがorz。
来週は、前に住んでいた家のクリーニング(900ポンドほどするので引っ越しy利も高いです)と、大家さんの立ち入りチェックがあります。日本だと結構甘いのですが、こっちは厳しいみたいです(どきどき)。
尚、以前アドバイスしてもらったように、車をやっとこの夏に買いました。快適です。
投稿: Shuji009 | 2014年10月17日 (金) 19時44分