カテゴリー「ARM」の45件の記事

2015年1月 8日 (木)

心電計プロジェクト:スケールが出ると心電計らしくなる

みなさま明けましておめでとうございます
 当ブログも開設以来7年が経ち、電子工作歴は何と、もう足掛け8年になりました。毎年のお正月には、これまでの総括と今後の抱負を一言載せるのが恒例になっていますが、今年はどうも適当なことが思いつきません。電子工作が、仕事をやめてからの第二の仕事のようになり、余りにも生活に溶け込んでしまったからでしょうか。

 昨年、嬉しかったことをひとつご報告しておきます。IT企業に勤めている娘の職場の友人が数名、ブログを読んで、ぜひ話を聞きたいと当研究所を見学してくれたことです。電子工作の面白さをみんなで熱く語りました。ブログのおかげで、色々な人と交流ができる。ありがたいことです。

 それはともかく、プロジェクトの続きです。心電計のプロジェクトもいよいよ大詰めに近づき、2.4インチTFT液晶に、それらしい心電波形が出てきました。昨年暮れからの作業の状況を以下にご紹介します。

keiさんありがとう。ピークが出ました(12/20/2014)

 心電波形はひとまず出たが、前記事にも書いたように、どうもピーク値(R波)が低すぎるような気がする。これは心臓疾患ではなくてセンサー部からのデータを端折っている(2回に一回しか送っていない)ため、ピーク値を逃している可能性が高い。

 UARTで10ビットのデータを2バイトに分けて送出しているが、先頭バイトを識別するため、データの送出を1回休んで間隔を空けている。これをもう少し縮めるか、このあいだコメントで頂いたように、2バイトの先頭ビットに細工をして10ビットデータを送れば、間隔を空けなくてもよさそうだ。

 実は、こうしたデータの内部構造にまで立ち入るプロトコルは、なるべくならやりたくなかった。しかし擬似コーディングしてみると、この先頭バイトに識別ビットを載せる方が、下手に時間を空けるより(1回分より少ない時間を作るのが難しい)、はるかに簡単に実装できそうなのだ。keiさんという方からコメントでご提案をいただいた方式である。

 10ビット(ADC値)データを2つに分割し(等分に分ける必要はない)、第一バイトのMSBに1を立てて(つまり128以上)、128より小さい第二バイトと区別する。ロジックそのものは至って簡単だが、AVR、ARMの両方のコードを同時に変更する必要がある。

 まず、AVRの送出側を変更し、PCのバイナリ―端末アクノリッチでデータを確認する。想定通りのデータを確認してから、ARM側を変更する。何度もロジックを確認してビルドし、祈る気持ちで接続した。 Pc246789 テストする。一発で動いた。良いぞ、コーディングミスはなかったようだ。よーし、ピークのR波が鋭くたち、世間でよく見る心電波形の形になった。良かった、良かった、自分の心臓がおかしくなったわけではない。keiさんありがとうございました。

 久しぶりにAVRをいじったので、ついでに気になっていたAVR側のデバッグをした。稀れにだが、デジタルフィルターを通さないノイズの入ったままのデータが送られる時がある。電源の抜き差しを頻繁に行ったときに多い。リセットすれば直る。サンプリングに失敗しているとみられる。

 コードを調べていくと、ADコンバーターのサンプリングを10回もやっていることがわかった。一回9μsのADCサイクルで10回というと100μs近くになる。送出間隔は、635μsなので、この程度なら大丈夫だとは思うが、試しにこれを2回に減らしてみた。

 あてずっぽうだったが、これが原因だった。何度電源を抜き差ししても一回もトラブルは起きなくなった。よーし快調だ。心電波形はこれでほぼ完全になった。

 いよいよ画面に、枠線や、数字を出すステップに来た。それと、トリガーを考えなければならない。今は連続して波形を出しているので、心拍のピークは一定のところに出ない。これを一定の位置から画面に出すようにしたい。これが出来れば本格的な心電図になるのだが、この実現はそう簡単ではない。

画像表示関数をデバッグする(12/21/2014)
 この間トラブった描画関数について、作者のねむいさんから丁寧なお詫びコメントが入った。こちらが好き勝手に使ってこけているのだから、恐縮されるとかえってこちらが戸惑ってしまう(オープンソースは無保証が大前提)。

 自分だって昔に開発したコードのバグを指摘されるのは、有り難い反面(建前)、実は何となく昔の思い出したくない古傷に触れられる感じで、そう手放しで喜べる出来事ではない(本音)。これが仕事なら本当に助かるけれど、遊びで作ったのにケチをつけられるのはたまらないと思う。

 なので、何かこのところ狙い撃ちをするみたいに不具合に遭遇してしまい、かえって申し訳ない気持ちでいっぱいである。荒さがしをしているつもりはないのに結果としてそうなっている。こちらこそ、ごめんなさい、ごめんなさいである。

 まあ、それはともかく、新版で解消したので差し替えて下さいということだが、全部を差し替えるのは大変なので、ソースをみてどこが違っていたのか確かめてその修正だけをすることにした。不具合は2つあった(関数Display_DrawLine_If())。

 ・差分を積み上げるときの数をせっかくABS()で正数にしているのに、元の数で計算。

 ・if(数値)は、0がfalseで0以外がtrueなのだが、数値>0とすべきをif(数値)としていたために負数がすりぬける。

いずれも、全くのケアレスミスである。しかし所長も正しいコードと比較するまで机上デバッグでは見つけられなかった。ソフト開発というのはこういうものである。まさしく書いたようにしか動かない。どんな簡単なソフトでも動くまで信用してはいけない。

 グラフの描画は最初、2重線を引いていたが、折れ線だと1本線でも十分綺麗にでることがわかり一本に減らす。ロジックが少し簡単になった。これで残っている不具合は、電極の装着が依然不安定なことだけになった。

 電極は、前にも書いたように暫く(1分程度)同じ位置に固定していると接触抵抗が下がって波形がでてくるのだが、5分以上置いておいても出てこないときがある。始めつけた場所によると思っていたが、どうも断線の可能性が高い気がしてきた。

 しかし導通テストでは大丈夫である。しつこく調べるうち、遂に、1本のコードで断線を発見した。かしめてあるコードの中の部分で断線していたのだ。かしめた部分をドライバーでこじてゆるめ、コードを引っ張ったらポロッと切れた銅線が出てきた。こういう微弱電位の断線はたちが悪い。

意外に簡単にトリガーはかけることができた(12/26/2014)
 トリガーである。波形を常に一定の場所から描くことである。だんだん、オシロスコープに近い処理が必要になってきた。リアルタイム性は余り求められていないので、トリガーは出てきたデータを一旦バッファーに貯めて、そこから考えれば大抵の方法は思いつく。

メモに沢山思いついたことを書きとめながら色々考えていたが、結局、以下の簡便な方法でやることにした。

・1フレーム分のデータを蓄積し、その中の最大点のポイント(R波)を記録しておく。

・描画は、その最大点より少し前からスタートする。このポイントがフレームの先を越えたらフレームの最初から描く。ここで少しずれるときがあるが、余り厳密には考えない。

・描画と記録の速度を同期させておけば、オーバーランやアンダーランの心配なく、描画が続く(はずである)。

・ただし、フレームの最初の方にピークがあるときは、最大1画面程度まで描画は遅れる。リアルタイムな心電波形ではない。また、最初すぐに波形は出てこない。

 仕様はできた。コーディングする。1画面(300ポイント)のバッファーを定義し、バッファーがいっぱいになったタイミングで、描画の位置を計算する。決まればバッファーの中のデータから描画する。あとはリングバッファーの処理と同じである。

 少々、トラブルがあったが思ったほど難しくなく、ほどなくトリガーの効いた画像が得られた。タイミングが早くなってもピークを含む心拍波形を常に表示することができるようになり、俄然心電計らしくなったきた。

 いやあ、苦節うん十年ではないが、これで、だいたい想定通りの機能は実現した。満足感に浸る。残るは力仕事の枠線(スケール)描画である。そう、数値も出してやりたい。

枠線を出す。やっぱり数値表示が欲しい(12/29/2014)

 枠線は簡単に出ると思ったがやはり落とし穴があった。線を増やしていくと全体がハングするのだ。おかしい。デバッガーを動かすが、落ちるところが一定しない。うーむ、何かオーバーフローか何かでデータが壊されている感じだ。

 オシロで動きを確かめて原因が判明した。何と枠線を引くのに80msもかかっている。一方、UARTは絶え間なくデータを取り込んでいる。UARTのバッファーは256バイトもあるが、ここが怪しい。

Pc286791  そう、やっぱりオーバーフローだった。0.6ms単位に2バイトのデータを出すから、80msも待たされれば、266バイトのデータがバッファーに溜まる。はい、これではだめです。UARTのバッファーを256バイトから倍の512バイトに拡張する。

 ところが、UARTはバッファーサイズを拡げただけでは動かなかったのである。バッファーの変数は16ビットでとってあるのにおかしい。ソースコードを詳しく調べて原因はすぐわかった。関数の中の一時的な変数が全部8ビットで定義されていたというオチである(ねむいさん、ごめんなさい。また見つけちゃった)。

 これを直して無事、枠線も出た。しかし、枠線だけでは何となく物足らない。やっぱり数字がついていないと雰囲気が出ない。文字の表示は、この液晶を縦位置で使うために今度の心電計では、この文字表示列を90°右に回転させる必要がある。これは簡単にはできない。

 ねむいさんのソースはもちろん2バイトコードの漢字まで表示できるのだが、今度のARMはフラッシュが128KBしかないので全部含めてビルドができない。しかも、開発環境がCooCoxという全く違う環境である。必要なところだけソースツリーからつまみ食いするような形でモジュールを取り出してくるのは、とても気を遣う。

 自慢にもならないが、こういう開発の方が、まるごと持ってくるよりはるかに難しいのだ。しかもこればっかりは開発者に聞くわけにはいかない。しかし、やりだしたからにはやめるわけにはいかない。黙々とソースコードを調べては持ち込む作業を続ける。

 ねむいさんのソースは相当進化していて、新しいバージョンではフォントのサポートが滅法増えている。最新版ではFONTX2タイプのフォントが10以上もある。ディレクトリの構造が悩ましい。CooCoxで動くかどうか。

 ふむ、ふむ、FONTX2のファイル.FNTファイルはバイナリーなので、includeは簡単ではない。どうしているのだろう。おお、ChaNさんのテクニックが使われている。なになに、.incbinというgccのアセンブラーgasのディレクティブだ。うーむ、CooCoxの環境でライブラリーパスはどうなる。

CooCox環境で、ARMの文字表示に成功(1/4/2015)

 あっと言う間に2015年を迎えた。今まで我が家で男は、所長とオス猫だけだったのだが、ここ数年婿殿が増えて正月は男女同数になっている。家内が和装にこっていて正月は全員で和服に着替えるのだが、今年はさらに男3人全員が和服に揃えたのでちょっと壮観だった。

P1016809_x  自宅の前で記念撮影をする。自宅は近くの神社の参詣経路にあたっている。通行人の視線が眩しい。その足で元旦の初詣に行く。今年は思ったほど混んでいなかった。寒かったからかもしれない。お正月は酒を飲むので電子工作はお休みである。

 3日の箱根駅伝が、史上始めての青山学院大の完全優勝で終わって、電子工作の再開である。暮れから始めた文字出力の開発を続ける。文字フォントのincludeが出来ないでいる。環境が、CooCoxなのでリンクの方法が全く見当つかない。

 CooCoxのConfiguration画面のcompilerオプションで環境変数の定義は簡単に出来るようになったが、includeパスでは.incbinがファイルを認めてくれない。色々やったがだめである。CooCoxのパスは、実際のディレクトリパスとは全く違う仮想的なパスを定義することが出来るので余計ややこしい。

 試行錯誤の末というより、愚直にソースコードのFNTファイルが入るところにフルパスを入れたら見事に認めてくれた。いやあ、最初からこれでやれば良かったのだ。コンパイルが通って一息ついた。ここまで来ればあと少しである。

 コマンドを新設して、適当な文字を出すテストルーチンを作る。 ふむ、出ない。ああ、そうだ。初期化を忘れている。前の気圧計の時の初期化ルーチンをそっくり持ち込んで再度テストする。 出た出た。12X6のポイントの小さいフォントだが、画面に文字が出た。

 さて、これからまた一仕事である。この文字フォントを右に90°傾けて縦置きにしなければなならない。

縦置きフォントが出た。文字が出て画面は一気にそれらしくなる(1/6/2015)
 文字フォントの回転に頭を抱えている。最初、素直にフォントグリフを縦にスキャンするルーチンを擬似コーディングし、実際のソースをみながら開発に入ったところ、描画ルーチンの実装で重大な思い違いを発見して愕然となった。

 ねむいさんの描画ルーチンは色々なところで高速化が図られており、文字フォントはひとつづつのピクセルを描画するのではなく、文字フォント枠(レクタングル)をあらかじめ描画ドライバーの原始関数で設定してから、そこへ連続したピクセルデータを送って、ドットが流し込まれる方式がとられている。

P1066837_2  画像処理ドライバーで良く使われる高速化手段である。この方式ではスキャンする方向が決まっており(もちろんコマンドで方向は換えられるが、原始関数を駆使する必要あり)、今のままでは、フォントグリフを縦に並べることは出来ない。

 一旦、文字を作ってから、縦のドットを横にスキャンするような形でドットを拾って送り込む必要がある。うーむ、単純に考えていたが、文字を回転するのはえらく難しくなってきた。文字が画面上縦になるのを我慢すれば、このまま出しても良いが、やっぱりみっともない。

 暫く考えていたが、ここまできて辞めるわけにはいかない。速度は遅くなるかもしれないが、2次元配列にフォントを流し込んでから、これをさらに縦横に転置するロジックを作ることにする。

 コーディングしてみると意外に捗った。既存のルーチンをうまく活用してFONTX2形式のフォントを、fontdata[x][y]などの二次元配列に流し込み、このxとyを逆さまにしてやれば良いだけである。

 ついでに既存のフォント出力も、この方式に替え、パラメーターでフォントの回転が出来る関数をでっちあげた。意気揚々とテストに入る。まずは、ノーマルの出力(画面の赤)。うむ、問題なく表示された。

 次は、問題の回転出力である。うーむ、ゴミが出るだけだ。あ、配列番号が間違っている。配列の番号は0からスタートするので最後からスキャンするときは、1少ない数値から戻らないといけない。一番最後も0を含める必要がある。P1076846

 よーし、見事に文字列が縦に表示された(画面上では横の緑文字 ABはオリジナル関数から)。ここまで来れば実際の心電波形に数値を入れてみよう。勢いが止まらない。いそいそとコーディングする。数値はとりあえずは固定値で良い(増幅率や時間で変数にするのはあとで)。

 出ました。出ました。数値が出ると枠線も俄然本式に見えてくるから不思議だ。急いでリストバンドをはめて実際の心電波形を出し、写真撮影をする。いやあ、ここまで来るのは長かったが、とりあえずは、ちょっと見映えのする画面になった。

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

2014年12月18日 (木)

心電計プロジェクト:TFT液晶に念願の心電波形が出た

 プロジェクト開始から半年かけて、やっとのことで2.4インチTFT液晶に想定通りの心電波形を出すことに成功した。まだ、枠線を引いていないし、振幅や時間幅の調整は、UARTによるPCコンソールからで、ケースにも入っていないバラックである。実用性はまだ限りなくゼロだが、とりあえずは一段落である。当初の計画いえば第4ステップの終了にあたる。

 それにしても、このプロジェクトは次から次に課題が発生して苦難の連続だった。今回も最後の最後で、画像ルーチンのバグに悩まされ、結局、コードを書き換えるという姑息な方法でバグを回避した。以下はその顛末である。

息抜きのつもりがストレス。1005チップ部品は手では無理(12/4/2014)
 前回のブログ記事は、センサーからのデータをフォトカプラー経由でSTM32F103が受け取り、TFT液晶にその値をグラフ描画するところまでだった。このときは心電波形をまだ確認していない。でもここまで来ればあともう一息である。

 画像が無事に出て、ちょっと息抜きに別のことをやりたくなった。こういう道草が今回のプロジェクト遅延の大きな要因でもあるのだが、なかなか止められない。寄り道のタネは秋月が最近出した、極小USBシリアルアダプターである。Pc056735 こいつは、秋月の定番のFT232RLを使ったUSBシリアルアダプターより、小型で(USBコネクターはマイクロだが)、値段も安い(¥600)。特にあてはないが買ってあった。しかし、今までのUSBアダプター同様、送信口(マイコンから見れば受信側)の電圧が2.7V近く上がる。例の「セパレーター」が必要だ。

 それより気に入らないのが青色ダイオードのパイロットランプである。日本人3人がノーベル賞を受賞したのであまり大きい声で言えないが、実は所長はこの青は好きではない。パイロットランプというのは、人の神経に触らない暖色系が良いのだが、青色というのは何となく人を不安にさせる。

 で、当然換装することにした。大きさは1608なのでこのチップLEDなら、緑、赤などの手持ちがある。低温ハンダを使わずに少し強引に青色LEDをはずす。何とかはずれた。ありゃま、隣の1005の制限抵抗(1kΩ)も一緒にはずれかかった。つけなおすためこれもはずす。

 ところが、この豆粒のようなチップ抵抗が行方不明になったのである。ピンセットで少し強くつまんだら、飛び跳ねたのだ。テーブルを慎重に見回し、床を這いずり回って調べたが見つからない。やれやれ1005の抵抗なんて手持ちはない。

 探し回るうち、こんなことに時間を浪費している自分がさすがに恥ずかしくなって、パイロットランプなしで行こうと決め、周辺を片付けているときに偶然発見した。何とチップ抵抗は、ハンダ付けのための固定に使っていたミニブレッドボードの表面と中の接続端子板の隙間に入っていた。

 難儀はこれですまなかった。ハンダごての熱で基板のLEDのパターンがはがれてくる。万事休す。あきらめきれず、銅線の切れ端で強引に新しい緑LEDを固定しようとして、今度はLEDをまたピンセットで飛ばしてしまう。そのうちハンダの熱で新しいLEDも表面をはがしておしゃかにする。

 こうなったら我慢くらべのようなものである。3つめのLEDを意地になって取り付け、やっと換装が終わった。ところがこのLEDが点かないのである。息抜きのつもりで始めた電子工作がこのありさまでストレスが一気に貯まる。何もかも放り出して大声を出したい気分である。

 ばかばかしいことをしている自分に無性に腹が立つが、ここで爆発しては今までの苦労がすべて無駄になる。ぐっとこらえて(笑ってください)、気分を鎮め、状況を最初から確認する。そのうち、基板を触ると一瞬LEDが点いたのが幸運だった。ハンダ付け不良の疑いが濃い。

 しかし、ちょっと見た所では問題はなさそうである。さらに色々触って試してみる。その結果、1005のチップ抵抗の一方が完全にハンダ付けされていないことを発見した。ハンダが多すぎてチップをとりかこんではいるが接触していなかったのである。やれやれ。

コンペアマッチが効かないのもお恥ずかしい基本的なミス(12/10/2014)

 雑事で忙しかったこともあるが、わかってしまえば極く当たり前のことに、この3日間頭を抱えていた。今度もここに書くのもお恥ずかしい基本的なミスである。

 心電波形の表示は、時間軸を可変にしておきたい。というのでARMのタイマーにコンペアマッチのステートメントを入れたのだが、これが、がんとして指定の時間に割り込みが入らないのだ。

 気に入らないのが、コンペアマッチの割り込みは順調にかかっているのに、どうしても時間が指定の時間にならない。必ずタイマーのオーバーフローの時間になる。

 いざとなれば、オーバーフローのタイマー設定値を変えても良いのだが、これまでARMのタイマーでコンペアマッチの機能は使ったことがない。経験値を高めるためにも、動かしておきたい。しかしAVRと違って、ARMのタイマーは高機能なので設定することが山ほどある。どれが正しい設定かわからない。

 PWM出力ピンも使わない単純なコンペアマッチだが、それだけでも10近いステートメントで定義しなければならない。ひとつひとつを何度も参考書やウェブのサンプルと見比べるが、どこも間違っていない(ように見える)。謎は、割り込みは正常にオーバーフローと区別しているのに時間が変わらないことである。

 結局、オーバーフロー割り込みとコンペアマッチ割り込みの2つの時間をオシロに出して、始めてその間違いに気づいた。画面にはコンペアマッチの指定分だけ遅れた同じ幅の波形が出た。あ、あ、あ、何という事だ。もう情けないというか、ただ笑うしかない、基本的な勘違いである。

 要するにカウンターがコンペアマッチしたときにリセットしていないのが原因である。AVRではコンペアマッチするとカウンターがリセットされていたので、そのままにしていた。あーあ、何で今まで気が付かなかったのだろう。

 ちゃんと、コンペアマッチで割り込みがかかっても、レジスターをそのままにしておけば、次の割り込みは、レジスターが一周してくるときだ。つまりオーバーフロー値から一歩も動かない時間となる。当たり前だ。

 ARMの関数一覧から、レジスターの値を設定する関数を探し出し、ゼロにするステップを加えて、めでたくタイマーは指定の時間に割り込みがかかるようになった。コンペアマッチで必ずカウンターがリセットされるという思い込みが招いたお粗末である。

グラフもそれらしい波形が出てきた。増幅が難しい(12/12/2014) 
 PCコンソールからのコマンド入力で、表示速度が変化できるようになった。表示される心電波形も、腕のサポートを少しきついハンカチにして、時間をおくと(数分)、だいぶそれらしい波形が出てきた。皮膚と電極の間の抵抗は、時間をかけないと低くならないようだ。Pc116761 ただ、表示波形は、振幅がまだ小さいので、増幅してやる必要がある。しかし、やみくもに、出た数字を大きくしても電圧の高いところでの変化はオーバーしてしまう。AC測定のような工夫が必要である。

 中位電位の設定が難しい。出てくるデータが必ずしも、中間で上下しているわけではない。しかも移動する。始め、中位電圧をコマンドで指定するようにして、そこを起点にAC測定ということにしたが、中位点を固定してしまうと波形がそこからずれると表示されなくなる。難しいものだ。

 そのうち、うまい方法を思いついた。1フレーム(画面)程度のデータの平均値をとり、それを次の画面の中位電位にして、そことの差分を増幅する。画面ごとに中位電位が変動するが、これにより、相当程度増幅(10倍近く)しても、折れ線グラフがはずれなくなった。

 増幅度も、コマンドで調整できるようになり、これで心電波形もかなりはっきりでてきた。嬉しい。やっと完成に近づいてきた。やはり、腕に電極をしっかりつければ倍率を上げなくても明瞭に出てくる。しかし、グラフ表示がドット単位なので、値が飛ぶところは、点だけになってしまう。Pc146773

 これは、以前からわかっていたことで、大きく値が変化したところは何らかの補正をしてドットを補っていく必要があるが、考えているうちもっと良い方法を思いついた。しかし、この実現にはまた難儀が待っていたのである。

ラインを引く描画関数のバグに悩まされるが、回避した(12/16/2014)
 折れ線グラフの補正は、何も、大きく変動したときだけに限定する必要はない。始めから、ドットではなく、前の値からの線分を引けば、完全な折れ線グラフになる。おお、これは完全な解決だ。こういう解決は気分が良い。線を引く関数は、たいていの描画関数には揃っているはずだ。

 あった、あった。Disply_DrawLine_If()という関数を見つけた。画面上の2点を指定すれば、そこに指定した色で線を引いてくれる。これまでのDisplay_FillRect_If()という描画関数(グラフを太くするため2X2の領域塗りつぶし関数)をこれに換えるだけで良いはずだ。

 ただし、起点と終点がいるので、起点となる前の値を残しておく変数を新たに設定する。コーディングはあっという間に完成した。上機嫌でテストに入る。

Pc166774 おやあ、変な斜め線が入って正しい波形にならない。これは何だろう。値が急激に上昇するときにヒゲが沢山入る。下降の時は問題ないが、よく見ると上昇のときはわずかな変化でも正しい線が引かれていない。

 最初は、符号付の指定である関数の引数に符号なしのデータを入れているのが原因かと思って、データを揃えたが変わらない。仕方なく関数のソースコードを調べ始めた。

 何やら難しい手法で線を引いている。コメントによれば Bresenham Algorithum(ブレゼンハムアルゴリズム)というのらしい。ウェブで調べると、こういう描画の時の古典的な定番のテクニックらしく、色々なサイトで紹介されている。

 少し調べたが、間違いはなさそうだ。こういうソースコードにバグは考えにくい。何か、前提となるところが間違っているのだと思うが、思い当るところがない。もしかしたら、入れている数値がおかしいのかもしれない。

 こうなると意地になるのが所長の特徴である。コマンドを新しく作って、心電波形に近いピークの波形(一方が最少の変化で、もう一方が激しく動く)をリテラルで指定し表示させてみた。見事に間違った波形が表示された。よし、関数のバグであることに間違いない。

 しかし、どこが間違っているのか特定できない。机上の計算では間違いないのに何故か暴れる。暴れる原因は、線分のX座標の低いところから高いところの線だけがおかしく、逆は問題ない。Y座標はどちらでもセーフである。

 考えているうち、簡便な解決法を思いついた。線を引くだけなら、どちらを始点にしても変わらない。関数のバグは解明できなくても、描画する前に始点と終点を調べて、バグが出ない方向で関数を呼び出せばよいのだ。

 早速、コードを追加し(ifで同じ関数を引数だけ換えて呼び出すだけ)、テストに入った。でました。でました。これまでのような飛び飛びの描画ではなく、連続したグラフが美しく表示されるようになった。ラインを2重に引いた(座標を1つずらす)ので折れ線グラフがはっきり見えるようになった。

Pc176775

 まだ、細かいところや、枠線などがないので完璧とは言えないが、当面の心電波形の表示はこれで完成と言える。いやあ、長かったけれど何とかここまできた。達成感で胸が膨らむ。

 このあとは、スケールを描くこと、PCコンソールではなく、ロータリーエンコーダのようなもので調整が出来るようにすること、ケースに入れることなどが残っているが峠は越した。

 ただ、少しひっかかるところがある。表示波形のR波(一番鋭いところ)のピーク値が低いことだ。後のT波、U波と同じくらいである。もしかしたら病気なのかも知れないが、そうではなくて、サンプリングが少ない可能性の方が強い(希望的観測)。

 AVRとARMのUARTインターフェースで、第一バイトを識別するためデータを端折っている。残さずデータをARMに送るのは、以前、コメントでいただいた、5ビットづつの2バイト送信ロジックを検討してみるのも面白いかもしれない。いやいや、やることはまだ山ほどある。

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

2014年12月 3日 (水)

心電計プロジェクト:STM32F103の心電波形表示で悪戦苦闘

 かれこれ半年かけた心電計プロジェクトは遅まきながらARM(STM32F103VB)で2.4インチTFT液晶に心電波形を表示するソフト開発まで進んだ。それにしても、液晶を動かすだけに大騒ぎしたり、フォトカプラーの選定に川崎まで高速カプラーを買いに行ったり、センサー部のTiny861のUARTにはまったりして、やたら脱線が多い。 Pb296721

 前の記事から20日余り、少しづつ作業を進め、やっとのことでTFT液晶から実際のグラフが表示されるようにはなった。しかし以前、DACでオシロに出したような綺麗な心電波形はまだ出てこない。これを待っていると次の記事がいつになるかわからないので、とりあえずこのあたりで経過報告をしておくことにする。

USI-UARTは動いた。送信プロトコルを決める(11/11/2014)

 センサー部のTiny861で動かなかったUARTは、もともとISPケーブル経由でPCとつなぐUART(ISP-UARTと勝手に命名)で、ARMへのUARTインターフェースは、最初からバッファリングの出来るUSI-UARTを予定していた。I2Cを通してDACに送っていたデータは今度はARMに送られる。このUARTの移植は問題なく終了し、プログラムは動き始めた。

 UARTらしい波形がオシロから出ている。念のためロジアナで出力波形を確かめた。ところが、これが全くでたらめなデータなのである。ISP-UARTに続きこれもダメかとがっくり来る。どうしてなのだ。何を間違えたのだろう。

 気を取り直して、慎重に状況を最初から調べる。ほどなくロジアナのプロトコルアナライザーのボーレートが設定と違っていることを発見した。早速、設定を合わせる。おお、ちゃんと正しい出力データが出てきた。やれやれ、ほっと胸をなでおろす。

 通ったのは良いが、ここは送信プロトコルが問題で、まだ具体的な仕様を決めていない。10ビットのバイナリ―データが2バイトでセンサー部のディジタルフィルターから送られてくる。データの時間間隔は625μsで、38400bpsのUARTなら2バイトだと、260μs(スタートストップいれて10ビット)の2倍、520μsかかるので、ほぼ連続してデータが送られることになる。

 何もしないで送ると、どれが第一バイトかわからなくなるので、何らかのロジックが必要である。10ビットは、1023が最大値なので、最初、第一バイト(右詰めとして)が3以下という、洒落たロジックで第一バイトを識別しようとした。しかし0~1023の中で、それでも区別できない数値が20個近くあることがわかり(0,1,2,3,256,257,258,259など)、あきらめた。

 結局、採用した方式は、精度を犠牲にして連続して送るのをあきらめ、2バイトと2バイトの送出単位の間に一定の待ち時間を設け、受信側は、必ずその待ち時間だけ待ってから第一バイトを受け取る方式にした。Ws000000

 グラフ表示が最大320ドットで長くでもスキャンは一秒間隔なので、3.3ms単位以下のデータは表示しても意味がない(前の記事の33msは間違い)。1ms程度の待ち時間を入れても大勢には影響ないはずだ。

 テストを進める。Tiny861のPCコンソールモニターでの値と、ロジアナのデータの値がほぼ一致した。待ち時間は、625μsの送出を1回休んで間隔を明ける。従って、送信頻度は、約1.25ms単位となる。  まだ、ARM側のソフトが動いていないが、ロジアナの波形は正しいデータを示している。間違いないようだ。これで、AVR側のソフト開発は一段落である。ARM側のソフト開発の前にフォトカプラーの実装をすませてしまおう。

フォトカプラーとインバーターをつける。インバーターは不要か(11/12/2014)
 センサー基板のすみに、フォトカプラーTLP512と、一緒に買って来たシングルチャネルインバーターTC7S04Fをつける。SOT23-5の極小のチップだ。持ち合わせの変換基板にハンダ付けする。フォトカプラーは論理反転するので元のUARTにするためである。Pc026733

 SOT23-5の変換基板が結構大きく6ピンのフォトカプラーと同じくらいだ。この変換基板はもう1ノッチ小さくできるような気がする。それはともかくハンダ付けは簡単に終わった。配線を確かめて早速テストに入る。

 Tiny861のUART出力ピンを一つ間違えて、出ない出ないと騒いでいたが、オシロをあてて間違いを発見し、フォトカプラー経由でも問題なくUART波形が出た。テストしているうちに、このインバーターもいらないような気がしてきた。Pc026728

 フォトカプラーの出力側を、エミッタフォロワーの形にすれば、順論理になる。どうしようか迷ったが、まあ、配線してしまったものを取り外すほどのことでもない。このままにしておく。バイナリ―端末アクノリッチでUART出力が正しく出ていることを確かめた。これでAVR側は完全である。少しづつではあるが、完成に向けてことが進んでいく。気分が良い。

Ttl  ちまちましたハンダ付けをやっているうち、もう少し手を動かしたくなった。こういうのはやりだすと止まらない。SOT23のインバーターチップを見ていて、これを汎用基板に直接ハンダ付けすれば、変換基板を使わずにもっと小型化ができる気がしてきた。

  そういえばUSBのUART TTLアダプターの受信側に電圧(負論理なのでNO DATA)がかかってAVRが幽霊動作をする現象をさけるため、かなり昔に、トランジスターのエミッタフォロワーで受けて受信側を遮断する「セパレーター」を基板の切れ端に作ったことがある。Pb266713

  AVRは低電圧でも動作するので、USB経由のUARTをつないだままにしておくと、power on resetがかからない。この現象は今度のプロジェクトでも起きて迷惑している。しかし、このセパレーターはブレッドボード用で、こういう基板同士の接続では不便で使っていない。そうだ、SOT23のチップトランジスターなら在庫がある(2SC4116)。これを使って小型化してみよう。

 いつもの脱線である。本題が順調に進んでいないときは、こうした工作を無性にやりたくなるものだ。ちょうど秋月で極小TTL UARTアダプターを買ってきたところだ。こいつにもつけられるよう汎用基板の4×4の切れ端に、ピンヘッダー、チップトランジスターとチップ抵抗2つを実体顕微鏡でハンダ付けする作業に入った。Pc016725

 ほどなく、写真のようなアダプターが完成した。配線図を参考までに。抵抗やスピードアップコンデンサーはチップ部品である。もちろん38400bps程度なら問題なく動く。いやあ、こういう道草を食っているから本題がちっとも進まない。

ARM(STM32F103)のUARTが2つ同時に動かない(11/18/2014)
 ゆるゆるとARMの開発に戻る。Tiny861からの送出データを受け取るUARTの増設だ。ねむいさんから頂いたソースコードは、複数のUARTが定義できるようになっている。始めは簡単に増やせると思っていた。しかし、これがまた難儀したのである。

 ソースのUARTの初期化ルーチン(conio_init(UARTn))が、どうも良くわからない。この初期化ルーチンは引数にUARTの番号を入れてやれば、それに応じたUART(この石はUARTを3つ持っている)を初期化しているので、併設が出来るものだとばかりと思っていた。

 しかし、2つUARTを初期化すると、2つとも動かなくなる。ソースコードを調べ直す。ふーむ、case文以外に#ifのプリプロセッサ―でUARTルーチンを制限している。なぜだろう。調べていくうち、どうもこのコードではUARTをダブって定義できないような感じがしてきた。

 見かけは、引数にUART番号を入れさせて、独立してUARTが併存できるようなコードにはなっているが、2つめを定義すると動かなくなるというのは、何か変数が被っているに違いない。しかしARMのUARTの初期化は、GPIOピンの定義から始まってややこしくAVRのように簡単ではない。ちょっと見ただけでは何が何だかわからない。

 さらに、仔細にコードを調べて行って遂にUARTの構造体が共通であることを発見した。こいつを独立させて(もうひとつ分ける変数があったが)、めでたく2つのUARTを動かすことに成功した。そもそも、2つ同時にUARTを動かす初期化ルーチンではなかったことに早く気付くべきだった。 Ecg_arm_in

 いよいよ、センサー部のTiny861とARM(STM32F103)をフォトカプラー付きUARTでつなぐ。まず、ARMを立ち上げてPCにコンソールを出してから、センサー部の電源を入れる。よっしゃー、PCコンソールから16進表示したセンサーのデータが溢れるように出力された。良いぞ。

UART2つが同時に動いたが、データの取り込みはうまくいかない(11/20/2014)
  このままではコンソールからデータが溢れて中味がわからないので、PCからのコマンドで一部だけ表示するようにソフトをいじり、中味の検証に入った。おやあ、第一バイトと第二バイトを取り違えているデータが頻々と入っている。

 皮肉なことに、正直に何もしないでデータを読む方がかえって間違いが少なくなる。何とも馬鹿にした話である。待ち時間がおかしいのか。コンソールデータだけではわからないのでロジアナを持ち込んで精密に波形を調べ始めた。どうも1msだけでは区別がつかないようである。

 仕方がない。AVRに戻って、待ちの間隔を2倍にした(2回休む)。しかし、2回休むと、AVR側が2バイトづつ送らなくなったり、どうも不安定だ。コードのなかでcontinue文を使ったのが原因のようだ。愚直にif文を区分けして、このトラブルは解消したけれど、これに係っている暇はない。先に進む。

 間隔は、データ2個分1.25msまで空いた。1msの待ちで最初のデータを識別するには十分な時間である。しかし、データは頻々と第一バイトと第二バイトを逆さまに読むケースが続出する。ARMの待ち時間がおかしいのかとGPIOピンでわざわざ時間を出してみたが正しく1msだった。

 うーむ、何が悪いのだろう。この方式では識別ができないのか。別の方法も考えるが、こんな簡単なロジックがうまく動かないというのが気に入らない。別の方式の検討に力が入らない。頭を抱える。

素晴らしく美しい富士をめでる(11/22/2014)
 ちょっと息抜きに、電子工作以外の話題をご紹介。こんなに美しい富士山の姿は、これまで見たことがなかったので、その感動のおすそわけである。 Pb226692

 知人に伊豆高原に別荘を持っている人がいて、毎年、季節の良いころに仲間で利用させてもらっている。今年は紅葉を目当てに友人と何台かの車ででかけた。伊豆は観光シーズン中は海岸沿いの道が大渋滞するので少し遠回りになるが箱根に上がって尾根伝い(天城スカイライン)に行くことが多い。

 箱根の山は、紅葉が中腹から美しく色づき歓声を上げながら山を登っていたが、圧巻は峠を登り切って振り返った時の富士山の姿である。十国峠からの景観が特に素晴らしい。

 晩秋の裾野から雪をかぶった富士山が丸ごと見える。こちら側からの富士は、宝永山の火口壁が目立って山梨側に比べると少し見劣りがするということだが、そんなことを感じさせない迫力である。

  この峠周りルートは、霧が出たりすると地獄になるが、こんなに晴れるのも珍しい。駿河湾から裾野、頂上にいたるまで雲一つないというのは、これまで何回もここを通っているが初めての経験だ。道行く車やツーリングのバイクもあちこちで車を止め、盛んにシャッターを切っていた。

  この景観がめったに見られない証拠は、帰りの道中で明らかになる。この話を聞いた海岸沿いで来た別の車の友人が、天気が良いので帰りは山に上がったのだが、靄(もや)がかかって富士山は全く見ることが出来なかったそうだ。相模湾側は青空が出ていて雲も高かったのだが山の天気というのはこういうものである。

やっと間違いなくデータを受け取れるようになった(11/25/2014)
 旅行から帰って電子工作に戻る。データの受け取りはまだ正確に行えない。こんなにエラーの多い状況ではグラフは曲線にはならず、散布図状態にしかならないだろう。

  ARMのUARTをなめてかかってえらい目にあっている。毎日が暗い。下らないことにこだわっている自分がみじめで余計気持ちが落ち込む。しかし数日後、このトラブルはあっけなく解決した。たまたま居間から地下室のPCルームに降りる階段の途中で間違いに気が付いた。

  これが、電子工作の醍醐味だなどとうそぶくのも悔しい基本的なミスである。今度もわかってしまえば何でこれに気が付かなかったのだろうと思う基本的なミスだったのだが、わかるまでほぼ2日間かかった。

  要するに、keypressed()という関数をキーに受信データの到着時間(バッファーにデータが揃ったとき)を一生懸命測っていたのだが、実際にはデータを読まなかったため、バッファーに次々にデータが貯まり、条件が揃ったときに読むデータは、ずっと前に受信したデータだった、というオチである。

  これでは、何もしない方がデータが正しく読めるはずである。原因がわかってしまえば修正はあっというまだ。データが来たときは、必ず受信関数でデータを読み、バッファーを空にしておくだけである。修正に要した時間は1分もかからない。

  コンパイルしなおして、正しくデータが読めていることを確認する。よーし、画面一杯にデータを出しても、全く乱れはない。やれやれ。あっけなく治ってしまった。 トラブルが解消するたびに、いつも何とかならないかとは思うが、こればっかりは仕方がない。考えたようには動かない。書いたようにしか動かないという格言をかみしめる。

悪戦苦闘が続く。まだ心電波形は出てこない(11/30/2014)
 いよいよ最後のステップ、得られたデータの画面表示である。枠や数字、スケールの表示はあとにするとして(これは面倒だが力仕事)、気になる数値のグラフ表示のロジックをコーディングしながらつめる(本当はおすすめしません)。

  以前考えた通り、出力値(0~1023)を液晶表示ドットY軸(240ドット)に正規化して、2X2ドットのピクセル(最初は赤、画面が暗くなるので黄色に変更)を打っていく。ロジックは何も難しくない。グラフはX軸の最後(320ドット)まで行くと最初に戻る。

  描画のとき、以前、打った値を覚えておき、表示と同時に消せば(黒で描画)、常に一つの波形が表示される理屈である。コードそのものは簡単で開発はすぐ終わった。わくわくしながらビルドする。NO ERRORだ。CoIDEは快適で、コネクターを一切いじらずに、テストまで一気に進める。Pb276718

  デバッガーを抜けてスタート。画面に待望のグラフが出た!おやあ、これはグラフではなく、単なる散布図だ。それに、やけに画面表示が早い。タイマーが機能していないのか。オシロで画像表示のタイミングを調べる。何い150μsだとー、早すぎる(設定は2ms)。ARM(STM32F103)のタイマーにコンペアマッチのコードを入れたが、これが機能していないようだ。

  タイマーの問題はあとにするとして、この散布図状態は明らかにロジックミスだ。何とかしなければいけない。ソースコードを調べる。ここのミスはすぐわかった。保存すべき描画ポイントを間違えている。前の描画ポイントではなく、出すべきポイントを消している。

  それなのにどうして描画されるのだ?このあたりを追及しているヒマはない。とにかく間違っていることは確かなので、正しく描画の後にデータをセイブするロジックに変える。再度テスト。おおー一本線のグラフが出た。いや、何本も線が出る。しかし夜中も2時近い、もう寝よう。

  表示が早すぎるのはタイマーを間違えているからで、これは時間を調整すれば良いのだが、問題は多重に出る線である。値が不安定になっていることを示している。またデータの第一バイトと第二バイトが正確に読めていない可能性が高い。

  寝る前に入った深夜の風呂の中で、また突然、原因に思いあたった。第一バイトと第二バイトをループを別にして読んでいるのだが、描画ルーチンが入ったことによって時間遅れが生じ、第二バイトを飛ばしてしまっているに違いない(第二バイトの読み込みにも時間条件をつけて離れていると無効にしている)。

  考えてみたら、第一バイトを読んだ後、第二バイトが来るまでここで待っていても全く問題ない。無理に非同期に動く必要は何もないのだ。むしろ、描画ルーチンのタイミングによっては、第一バイトだけ読んで表示をする可能性もあり、ここは2バイトを読むまで動かない方が良い。

  ゆっくり風呂に入っていられなくなった。迷ったけれど、風呂から出てジャンバーを着込み、地下の工作ルームに降りてPCの電源を入れ直しCoIDEを立ち上げる。思い立ったら寝られない性質(たち)である。眠気は吹き飛んでいる。Whileを使って第二バイトを待ち、そのあと描画ルーチンに行くように制御を変えた。

 よし、グラフは一本線になった。まだ描画タイミングが150μsと早すぎるので線はめまぐるしく動くが、少なくとも1本だけのグラフで動くようになった。少なくとも多重な線が出ることはない。時間を遅らせるのは明日にしよう。

  次の日、タイマーのデバッグに入る。ARMのタイマーについては、4年前の以前の記事を参考にしていたのだが、結局、このサンプルソースに誤りがあることがわかった(修正してあります)。プリスケールを決めるステートメントに重複があり、2番目のTIM_PrescalerConfig()は、無駄だったのだ。

  これを消去し、やっとタイマーは想定通りの時間で動き始めた。当然、画像もそれらしいゆったりとした心電波形(らしきもの)を表示し始めた。嬉しい。苦労が多ければ多いほどこの喜びはなににもかえがたい。Pb296722

  しかし、プローブを腕に巻き付けて心電波形が出るのを待ったが、穏やかな直線が続くだけで、一向に心電波形らしきものは出てこない。この状態は前にも経験がある。ピークが0.5V P-Pなのに4Vスケールで出しているからだ。

  この改修には少し時間がかかる。どの電圧範囲を広げるかを決めるのは簡単ではない。この前の記事からもう20日が経っているので、そろそろこのあたりでブログに報告することにする。

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

2014年10月16日 (木)

心電計プロジェクト: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メッセージは出るが、入力を受け付けない。Ws000002 難しいことは何もしていない。それなのに、さっぱり入力データが所定のバッファーに入らない。何度もソースを見直すが間違っていない。ロジックアナライザーを登板させるのも気が引けるぐらい簡単なところなのに動かない。

 そのうち、今度の環境にはデバッガーが入っていることに気が付いた。やせ我慢しないで積極的にこれを使ってみよう。ただ、このデバッガー、ブレークポイントを設定してもそこで止まってくれない(フラッシュ下では無理なのか)。

 しかし、変数は表示できるので、キーを延々と打ってステップ実行で動きを追いかけてみた。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には何のメッセージも出ない。しかし、今度はデバッガーという強力な味方がいるので先に進める。Ws000000

 よーし、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液晶ボードへの配線は、このあいだ買ったサンハヤトのスルーホールに差すジャンパーを使うことにしている。 201410010001

 8ピンバスを使うので配線量は少ない。思っていた以上に簡単にうまく行った。ハードの準備はあっけなく終わって、残るはディスプレイのドライバーソフトである。最後の難関だ。TFT液晶のドライバーの初期化さえ動いてしまえば、あとの画面表示の開発は楽しいプログラミングになる。

 このねむいさんのコードは、大量の数のディスプレイをサポートしている。そのための抽象化が何段にもわたっているのでとても複雑だ。不要なコードを消しつつ、慎重に何度も確かめながらアサインしていく。Eclipse風の、ソースコードでのマクロ定義や、#ifdefを区別してくれるCoIDE(CooCoxの統合環境名)の環境は、こういうときにありがたい。201410010002

 ただ、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)のプローブは出来が良く、着実にピンを捉えるので使いやすい。

201410090003  救いはJTAG関係が好調で何度でも簡単にビルドしてテストが続けられることだ。ロジアナで所望の波形はすぐ得られた。最初、データバスのenable信号WRが出ていないところを発見し、これだ!と色めいたのだが、サンプリングが遅すぎることに気が付き、戻したらちゃんと波形が出ていてがっかりする。

 初期化は順調にやっている。時間遅れもぴったり。8ビットコードで2回WRやRDを出していることも確認できた。何だ。ちゃんと制御信号を送っているではないか。最後の制御コマンド、0x07(display on)も、所定通りのビットが立っている。問題ない。 Ws000001

 これで完全に暗礁に乗り上げた。ディバイスコードが正常に戻っていて、波形も正常。それで動かない。うーん、もしかして、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)、リセットする。

201410140004  あっあっあ、画面が真っ暗になった。ひやっほー、初期化に成功した。間違いない。念のため、clearを赤でしてみる。見事、画面が赤くなった。やったやったぞ。いやあ嬉しい。これを電子工作の醍醐味というと誤解されそうだが、うまく動かないからこそ、この喜びは何にも代えがたいのだ。

 気分が落ち着き、PCでネットを見たら、ねむいさんからメールが届いていた。おおお、不具合が見つかったという知らせだ。時間を見るとちょうど自分が見つけた時とほぼ同じ時刻が発信時刻だった。何という偶然。

 ILI932x.cというドライバーを8ビットモードで使って、しかも、データピンとコントロールピンを同一のポートで定義しているときにのみに起きる現象のようだ。恐らく、私のCSピンの動きをみて発見されたのだろう。

201410140005  原因は、実にささいな1ステートメントの定義違い(8ビットのところへ16ビットデータをぶちこむ)なので訂正は、わずか一か所(8ビットキャストをするだけ)である。これで、めでたく、CSを強制的にenableにしなくても正常に初期化された。

 動きの確認のため、早速やっつけでカラーバーを出すコマンドを作ってテストする。問題なく出た。赤、緑、黄、青の4色の鮮やなカラーバーが眩しい。いやそれにしてもこの10日余りは地獄の日々だった。 しかし解決の美酒はこのうえなく美味い。でもソフトウエア開発の難しさを改めてかみしめる。これが仕事でなくてよかった。

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

2014年9月19日 (金)

心電計プロジェクト:表示部のARM基板の開発環境を一新する

 心電計プロジェクトは迷走を続けている。心電波形をオシロで確認してから、もう2か月近くたつが、次のステップの波形の画面表示は、道草(無関係なAVRのUARTのデバッグ)ばかり食って、一向に進まない。

 そのせいなのか、このブログのアクセス回数がこのところ減ってきたように思う。商売にしているわけではない、別に何の問題もないのだが、気分的にはあまり良くない。ということもあって、少し発破をかけてプロジェクトを進めることにした。

 これまで、オペアンプで増幅した心電波をディジタルフィルター(AVR)にかけてノイズを除去しI2CのDAコンバーターでアナログに戻して波形をオシロで見たが、実はこれは波形を確認するための寄り道で(ステップ3)、本来はフォトカプラーのUART経由でARMに送り、2.4インチTFT液晶画面に表示をするのが最終目的である。これで初めてスタンドアロンの心電計が出来上がる。

 久しぶりのARMである。プラットホームはSTM32F103という今や時代遅れのチップだが、心電計のグラフを表示するくらいなら問題ないはずだ。在庫整理にもなる。

Aitendoの生基板で2つめのARM基板を作る(9/5/2014)
 ARMの基板は以前作ったグラフィック気圧計のときと同じ、AitendoのSTM32F103用の生基板(¥450 [PCB-STM32F103V])を使う。必要な部品は、大分前から少しづつ揃えてきている。 前に同じものを作っているので特に迷うところはない。雑誌付録(CQ-STARM)の基板からはずしたCPUチップは既にハンダ付け済みだ。201409140001

 RTC(Real Time Clock)は今回のプロジェクトでは使わないが、基板にはパッドが用意されている。せっかくなので時計用の32.768khzクリスタルを秋月で買った。これが何と¥100で4つも入っている。しかもえらく小さい。世の中の進歩はこんなところにもあるのだと感心する。

 チップ抵抗やコンデンサーは、これまでジャンク基板から昆虫採集のように集めてきたものが沢山ある。それでもさすがに足らないものが出てきて、千石電商の地下で買い足した。ここはすごい。1608と2012の大抵のチップ部品が揃っている。リールを短く切ったものが10ケ¥50で手に入る。 目に優しい2012で揃える。

 表面実装部品のハンダ付けは楽しい。どんどんはかどる。プリント基板なので誤配線の心配もない。あっというまに20ケ以上の部品が実装され、コネクターも揃った。さて、いよいよ残るはソフトである。PCが新しくなっているので、まずは開発環境を一から作り直さなければいけない。Eclipseを入れるかどうか迷っている。

日本のテニス界がすごいことになっている(9/9/2014)
 電子工作以外で最近感動したことをひとつ。想像もしていなかったことがニュースになっている。テニスの錦織圭選手の全米オープンテニス大会決勝進出である。10代の初め頃から逸材といわれ、いずれはグランドスラム(4大大会のこと)で活躍すると言われてはいたが、怪我に悩まされて、いつも今一歩のところで涙を呑んでいた。

 それが、今年になって人が替わったように突然勝ち始め、あれよあれよという間にランキングを上げて、遂にこれまで日本人の誰もが到達できなかったところまで勝ち進んでしまった。それも世界ランク1位のフェデラー相手に互角以上の試合をしての決勝進出である。そうなるかも知れないとは思っていても、いざ本当になると改めて感動する。

 野球ファンには申し訳ないけれど、イチローや松井がどれだけ活躍してもWorldwideということではテニスとは比較にならない。何十年も前、ホンダがF1レースで優勝した時も、世界に与えた衝撃は大きかったのだが、日本ではそれほど騒がなかった。今度のこともこれに近いかもしれない。

 それにしても今までにない快挙である。日本の評価を上げたということでは国民栄誉賞を2個や3個あげても良いくらいだ。今回は優勝を逃したが、まあ、まだ24才だ。あまり早く頂点に登りつめないで落ち着いてやるほうが長持ちするのではないか。

 新聞記事の中では、今、世界的に通用する日本人アスリートがすべてゆとり時代に少年少女時代を送ったという指摘が面白かった。確かにそうかもしれない。彼らの日本人離れした度胸や自信は、これまでの日本人と一味違うような気もする。

レイアウトが難しいので、スルーホール用ジャンパーセットを買う(9/11/2014)
 それはともかく意気込んで工作を始めたのだが、レイアウトが難しい。普通にやると、TFT液晶基板、CPU基板、それをつなぐメイン基板の3枚になってしまう。これを避けたいのだが、なかなかうまいアイデアが浮かんでこない。

 さらに、時間軸、波形高の調整をロータリーエンコーダーで格好よくやろうと考えているのだが、このレイアウトも決まらない。接続は当面、フォトカプラーを使った有線にしようと考えているが、無線のXbeeにしたい気持ちもある。201409140002

 そんなこんなでなかなか具体的に進まない。CPU基板はすべて配線を終えたのだが、何となく怖くて通電できない。全体の構成が決まらないので、ハードの工作はこれ以上進めない。I/Oピンをソケットにするか、ピンヘッダーにするのかでも迷う。

 ちょうどそのころウェブで、基板のスルーホールに差して使えるジャンパーが売られていることを知った。これならまだ基板の構成が未定でも安心してテストが出来る。ストロベリーリナックスのジャンパーは、何故か目茶目茶高い(10本で¥4720)のだが、さらに検索してみると他にもあった。

 この、サンハヤトのものが安い(TTW-200 10本で¥738)。サンハヤトにしては珍しくリーズナブルな価格だ。アマゾンでも売っている。ここなら送料もかからない。迷わず2袋を注文した。ほどなく届いた。早速試してみる。201409140003

 ちょっと固いが良さそうだ。ただ、抜き差しを繰り返せば甘くなることは考えられる。しかし恒久的に使うものではないので、そう心配しないで良いだろう。レイアウトは考えていてもきりがないのであとにすることにして、次のソフトウエア開発環境の導入を進めることにした。ファームの書き込みは前と同じシリアル経由か、JTAGか。

ARMの開発環境を整理してみる(9/12/2014)  
 ARM系は気圧計以来すっかりご無沙汰で、開発環境が大きく変わっている。たくさんのハードやインターフェースが登場し、何が何やらさっぱりわからない。いちから勉強しなおすことにする。紙にでも書いて全体を整理しないと、とても理解できそうにない。

 それでも、ウェブ情報を読み進めるうちに、だいぶ事情がわかってきた。開発環境が激変したのは、JTAGまわりではなく、HLA(High Layer Adapter)といわれる、新しく加わったハードの開発環境で、JTAGそのものは変わっていないようだ。

 STマイクロには、STLink(/V2)というハードがある。例の激安のDiscovery評価基板に、必ずついているやつだ。汎用のCPUがついていて、USBを経由してターゲットCPUのファームを焼くプログラムが内蔵されている。ターゲットとのインターフェースはJTAGではなくて、新しい規格のSWD(Serial Wire Debug)などを使う。

 NXPのLPCシリーズにも同じようなハードが用意されている。LPCLinkと称している。mbedは最初は独自のインターフェースだったが、その後このLPCLinkでも扱えるようになったようだ。こうしたハードのデバッガー(プログラマー)とターゲットとのインターフェース規格も、昔はJTAG一本だけだったのが、SWDとかDFU、CMSIS-DAPなどの新顔が登場し、話がややこしくなっている。

 こうした商用ツールと、新しいインターフェース規格が次々に市場に投入されているところへ、GNUなどのオープンソース勢がからんで互換品を出したりして、話が余計わからなくなっているようだ。いずれにしろ、JTAGそのものがなくなったわけではないことは確認した。

 以前ARMで、お世話になった「ねむい」さんが活躍されている。ウェブの情報収集では必ず彼(彼女?)の名前が出てくる。しかも、ねむいさんのサイトが一番詳しくて親切だ。暫くしてその理由がわかってきた。

 要するにGNU環境で(無料で)、無制限にソフトを開発できる環境を作ろうと考えると、日本語で検索する限り、必然的にここに行き着くのだ。ねむいさん自身がオープンソースのデバッガーの開発にコミットしておられるようで、情報が早い。

 今度の生基板は旧来の20ピンのJTAGインターフェースがついている。JTAGのためにチップ抵抗を10ケ近くもハンダ付けした。これを利用しないとこの手間は無駄になる。これまでのOlimexのJTAGドングル(ARM-USB-TINY FT2232系)とOpen OCDで問題ないはずだ。

 ただ、Open OCDのバージョンが大幅に上がっているので、その対応をしなければならない。ねむいさん謹製のバイナリをしっかり頂戴する。

Open OCDのインストールはしたがCooCoxへ浮気する(9/14/2014)
 万が一JTAGが動かなくてもこれまで愛用していたROMモニターによるシリアルの書き込み環境がなくなったという情報はどこにもないので、あのMCUISPやFlashMagicでも書き込めるはずだ。ファームの書き込み手段についての不安はもうなくなった。

 開発環境のもうひとつの大きな要素、ソースコードなどの処理環境である。ARMではEclipseを使おうと思っているのだが、頼りのねむいさんが、蛇蝎(だかつ)のようにEclipseを嫌っているので、ねむいさんのインストールガイドのまま行くとEclipseを使わない環境になってしまう。

 自分だってEclipseにこだわっているわけではない。あれば便利というだけで、当初苦労してスクリプトを入れたOpen OCDのプラグインは殆ど使わなかった。ただ、階層化しているソースコードを検索する強力な機能がついているので、何度か助かった記憶がある。入るのなら入れたい。

 それはともかく、バージョンの上がったOpen OCDのインストールである。Open OCDは問題なく入ったが、Win7のPCが、OlimexのJTAGドングル(ARM-USB-TINY)を認めない。ドライバーのアイコンに!がついたままになる。

 あわてて、ウェブを探し回る。みなさん苦労しているようで、すぐ対応策は見つかった。 これで、ディバイスマネージャーのアイコンにちゃんとOlimexのサインが出た。

 いよいよ、Open OCDのテストである。DOS画面でコマンドを入れる。動いた。しかし、cfgファイルがないと怒られる。ここからは、次の環境を意識しないと設定ができない。ねむいさんのガイドではinsightなどGNU系のデバッガーソフトのインストールが待っている。さらにエディターを別に用意しなければならない。

 うーむ、もう少し楽な方法はないか。ねむいさんのガイドをもういちど読み直す。すると、「初学者向け」の開発環境としてCooCoxを勧めているところを見つけた。Eclipse風なのだという。ちょっとサイトを覗いてみる。すると、

  • Eclipseをベースにした統合開発環境
  • ARM系全体で使える
  • JTAG SWD双方サポート
  • フラッシュ制限なし
  • もちろん無料

となかなか良さそうである。こちらの要件にも合っている。

 「初学者向け」というのに少し抵抗を感じたけれど、なに、初学者に違いないのだから何もこだわることはない。無償なのはありがたい。入れてみることにす る。CooCox公式ガイドによれば、本体を入れる前にまずgccコンパイラー一式を落とせということである。素直に従う。Ws000000

 CooCox指定のgccは、ねむいさんの勧めるgccツールチェーンと同一だった。おお、これは幸先が良さそうだ。ツールチェーンは問題なくダウンロードできて展開もスムーズに終了した。

 本体のCoIDEのダウンロードを始める。これがサーバーがやたら遅い。サイズは450MB少々なのだが、スピードが100KB/secいかない。全部落とすのに一時間以上かかった。

CooCoxでデバッガー環境が出来てしまった(9/16/2014)
 ダウンロードは時間がかかったが、インストールは早かった。ただ立ち上がりはEclipse並に遅い。似たような画面があらわれた。手さぐりで動かしてみる。まずは、ダミーのプロジェクトを立ち上げ、Configuration画面でデバッガーを設定する。OlimexOpenOCDを選ぶ。

 マニュアルは殆ど見ないでも先に進める。Device画面で、STをクリックするとSTM3210x系のチップがずらりと並び、そこからSTM32F103VBに行き着く。残念ながら富士通のFM3は載っていなかったが、SpansionというメーカーのMB9BF36..,というチップが気になる。

 ググってみたらピンポンだった。Spansionが富士通セミコンダクターを買収したらしい。ただし、雑誌付録のMB9BF618Tはラインナップされていない。しかし、もしかしたら使えるかもしれない。ちょっと楽しみになってきた。

 それはともかく先に進もう。Debug画面に戻って、フラッシュ書き込みを指示する。おやあ、エラーメッセージを吐いて動かない。赤文字でUSBの接続が出来ていないというメッセージだ。おかしい。PC上では認めているのにどうした。初手からつまづいた。

 定石通り、ウェブに、「CooCox Olimex ARM-USB-TINY」のキーワードで探す。今度も一発で対応策がでてきた。Olimex本体のサイトのページである。 英語だけど読みやすい(外国人の英語だからか)。なになに、なんだと、PCの設定は全部未定義に戻せとある。  言われるままに、ディバイスマネージャーでドライバーを全部削除する。未定義の!のついたアイコンに戻った。

 CooCoxのDebug画面に戻り、ファームの書き込みを選ぶ。なんと、沢山のメッセージを出しながらCoFlash(恐らくOpen OCDのラッパー)が動き、あっけなく、JTAG環境が動いてしまったのである。

 メッセージによれば、しっかりファームを書き込んでいる。NO ERRORだ。何もしないプログラムだが、int  main()のループのなかに矢印がでて止まっている。レジスターの値もそれらしい値だ。Open OCDでさまよっていた部分は全てすっ飛ばして、いきなりフラッシュを書いてGDB状態になっている。今までの苦労は一体何だったのかと思うほどの拍子抜けである。 Ws000001

 しかし、まさしく「初学者向け」の環境である。OpenOCDらしい沢山の経過メッセージが目にも止まらない速さでconsole画面を流れるが、コマンド入力などは一切受け付けず、全く触(さわ)ることは出来ない。

 いずれにしてもデバッグ環境だけでなく、スタートアップルーチンから、各ペリフェラルのディレクトリチェーンまで今までとは全く異なってしまった。すべてCooCox任せである。これまでのプログラムは全部このあたりが書き直しになる。これも少し困ったものだ。

Lチカまで成功。しかし道は遠い(9/17/2014)
 テストしたプログラムは何もしないループするだけのダミープログラムなので本当にプログラムを書き込んだのかどうかを確認することにした。OlimexのCooCoxガイドにあるLED点滅のプログラムをsampleフォルダーから引き出し、実際に動くかどうかのテストをしてみた。

 今度はComponent画面である。ここのComponentの意味は、ペリフェラルライブラリ―のGPIOやRTC、ADC、USART、SPI、DMAなどの要素の意味である。ここで必要なペリフェラルを選ぶと、CooCoxが依存する他のコンポーネントも自動的にディレクトリごと読み込んでくれる。このあたりがミソだろう。

 Lチカなので、クロック関係のrccと、I/Oポートのgpio、それにスタートアップのCMSIS coreを選ぶ(これは指定しなくても自動的に入っていた)。Lチカのsampleソースも選ぶと、gpioピンをトグルするソースが入る。そのソースコードのピンを現在のAitendo基板のピンに揃える。それだけである。ビルドし、デバッグに入る。

 何と、これで簡単に動いた。赤と緑のLEDが賑やかに点滅する。やれやれ、何もしないでARMプログラムが動いてしまった。難しい話は何もない。 あっというまに、CooCoxでプログラム開発が出来た。ソースコードをなめ回し、ライブラリーを探し回り、ウェブで情報を求め、何度も門前払いを喰らいながら、やっとのことで動かしたことを考えれば、実にあっけない結果である。201409190004

 しかし、こちらはARMの開発を既に少しやっていたのでCooCoxのしたことが大体わかるが、初めての人が言われるままにサンプルソースからLチカを動かせたとしても、中身を理解することはこれではほとんど不可能だろう。

 Arduinoあたりはこれに徹しているので(情報の隠蔽化)、それはそれで良いのだが、ARMの直接の開発で、この方法が先まで全部通用するとは思えない。英語のマニュアルには、良く「今からやることを理解できてない人は、やってはいけない」という言い回しがあるが、こういう開発法は、これに反しているし、理解しないまま先に進んでも、いずれ挫折することになる。

 ちょうど目隠しされて歩かされるようなもので、所長のもっとも嫌うところなのだが、これだけ簡単にLチカが出来てしまうと、何ともはや、こちらを行くしかなくなってきた。OpenOCDのあの豊富なコマンドとメッセージに未練があるのだけれど、ここから出発するしかないか。

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

2013年6月17日 (月)

RaspberryPiのライブカメラを外からアクセスする

とんすけさんのMotion Playerシールド
 RaspberryPiの話の前に、報告しておかねばならないことをひとつ。すんさんの掲示板にも書いたが、とんすけさんのMotionPlayerシールドのことである。少しトラブルがあったのだが、とんすけさんの手助けで簡単に解決したので、ここでお礼を兼ねてご紹介する。 S_p5265875_2

 とんすけさんには大変お世話になった。この場を借りてあらためて御礼を申し上げておきたい。このMotionPlayerシールドとは、STM32F4-DiscoveryをベースにSDカードに入った音楽ファイルや動画ファイルの再生を液晶のタッチパネルで操作するプレーヤー基板のことで、ファームウエアが提供されており、ピンヘッダーをハンダ付けするだけで動作する。

 これを知った、そもそものきっかけは、例によってshuji009さんが、すんさんの掲示板で絶賛紹介されたことからであるが、とんすけさんそのものは2年ほど前、やはりshuji009さんの紹介で、STM32F103の外部メモリインターフェースFSMCを使ってLCDをドライブし、60fpsの動画を成功させた人として記憶に残っている。凄い人だなあと感心していたが、驚いたことに、この道のプロではなくアマチュアの方だそうである。いや凄すぎる。

 それはともかく、所長は、何度も言うように、「格安」とか「破格の値段」というのに弱い。秋月で多種類に亘って売り出されているCPU基板、STM32(8もあるが)Discoveryシリーズは販売促進という狙いで何しろみんな思い切った価格設定である。用もないのについ手が出てしまう。

 MotionPlayerのCPU基板STM32F4-Discoveryは秋月で発売後すぐ売り切れになり、直前に手に入れて、ひとりほくそえんでいたのだが(悪い性格だ)、間もなく潤沢に出回り始めて、そのうち興味も薄れ、現物はパッケージから出すこともなく部品庫に眠っていた。

 もうひとつの必要なパーツ、Aitendoの3.2インチTFT液晶は以前、直営店の店頭で見つけて、あてもないのに買い込み、これも部品庫のこやしになっていた。部品番号を確かめる。間違いない。同じ液晶基板だ。これで2つも長期在庫がさばける。これはもうこのシールドを買うしかないだろう。週末にネットで銀行振り込みをしたら月曜の夜にもう届いた。恐るべき早さである。

 ところが、これが動かない。画面は白いラスターのままで、何の映像も映らない。シリアル端末をつないでメッセージを出してみるとソフトそのものは動いているようだ。タッチパネルも何か感じているが肝腎の画像はでない。

S_p5145868

 ピンソケットの接触不良などは念入りにテスターで測って問題なし。TFTの初期不良が一番疑われるが確信はない。買ったのはもう2年近く前で今さら交換を要求するのも気が重い。それに、わざわざ出かけて行って交換して同じだったら目も当てられらない。思い余って、とんすけさんに、何か情報はないかとメールを出してみた。

 すると本人から、すぐ返事があり、送ってくれれば調べてあげると言われた。販売元でもないのにそれは申し訳ないと断わろうと思ったが、彼は複数台持っているとのことなので、正常に動く1台を貸してもらえば嬉しいのだがと少しあつかましいお願いをしてみた。

やっぱり初期不良だった。AitendoでTFT液晶は買いなおし(5/19/2013)
 まもなく返事があって、こちらの申し出を快く承諾されて完動品を送るとの報せが届いた。いやあ、これは有難い。待つこと数日。分厚いエアシートに包まれて、TFT液晶が届いた。感激、感激である。

 早速、接続してみる(ピンソケットは接続済み)。全く問題なく稼動した。音楽再生でpauseをかけると時々大きなノイズが入るのが少し気になるが(これはSDカードのバッファーサイズを大きくすると殆ど解消した)、動画も出る。タッチパネルの操作も楽だ。いや素晴らしい出来映えである。やっぱり2年前に買ったTFT液晶の方は初期不良だった。

 とんすけさんに借りたTFTを返却しようとした時、ふと思いついた。不良品のTFT液晶をAitendoに持ち込んで交換してくれる保証はない。お店で不愉快な気持ちになるくらいなら、これを、お礼がわりにとんすけさんに差し上げてはどうだろうか。

 とんすけさんが言うように、ちょっとしたことで直るのかも知れないが、こちらにはテスト環境もないし、不具合を特定できる技術も持っていない。とんすけさんのところで生き返ってくれれば、生きとし生けるものに少しでも幸せが訪れるというものだ。

S_p5265876

 何か、修理を催促しているようで、最後まで迷ったのだが、こちらで持っていてもしようがないし、その旨、説明すれば理解してもらえると期待してメールを送る。予想はあたって快く受け取ってもらえた。2台を送る。ささやかなことだが、気持ちが通じると言うのは嬉しいものだ。

 次の日、秋葉原に出て、Aitendoを訪ね、件のTFTを買いなおした。幸い在庫はまだ沢山あった。ここに来るとついいらないものを買ってしまうのだが、今日は、USB-TTL(CP2102の方)ブレークアウト基板だけで我慢する(RasPi用)。買って帰ってTFTを早速テスト。もちろん何の問題もなく稼動した。

画像のフレームレートを上げる(5/31/2013)

 RaspberryPi(以下RasPi)の話に戻ろう。LogicoolのウェブカメラC270を使ったRasPiのストリーミングビデオは、自宅内のLANでは、問題なく画像を見られるようになった(ただし、motionの画像を見るのは、IEでは不能、FireFoxはメモリーリークでハングする。Chromeは全く問題ない)。

 画像の解像度は、358X288(motionのデフォルト解像度)ながら、前の30万画素のカメラに比べれば、格段に綺麗な映像である。次は、これを外から見られるようにすることと、このカメラの可動部を制作することだが、その前に解決しておきたい問題がある。

 それは、画面のフレームレートである。現在は、motionのパラメーターファイルをいじっても、1秒に2~3回程度(2~3fps)にしかなっていないので、動きの早い猫などの姿は満足に捉えられない。もう少し多くないと実用的とはいえない。Moti_conf

 motionの設定ファイル(motion.conf)は、非常に多くのパラメーターがあって、ともかくわかりにくい。少々いじっただけでは改善されなかった。PCのUbuntuで動かしてみたら全く同じようなフレームレートなので、低いのはRasPiのハードウエアの限界ではなく、この設定のせいに違いなのだが、どこを直せば良いのかわからない。

 何度目かのmotionの設定ファイルの見直しで、やっと見つけることが出来た。ファイルの最後の方にある、Live Webcam Serverという設定項目群の中にフレームレートを規定するところがまだあったのを見落としていた。

 motionのフレームレートを設定するパラメーターは、いくつものところにあり、2ヶ所まで変更してあったのだが、最後の設定が、defaultの1の(1fps)のままだったのである。

 いくら、その前の設定でframe_rateを上げていてもストリーミングのときには、ここで下げられてしまうのである。このwebcam_maxrate というパラメーターを1から、30にすると、映画並みの滑らかさになった。

 おーし、猫がケージから飛び降りても、しっかり画像がとれている。良いぞ。ただし、ネット上のデータ転送量は、これまでの毎秒12KBから50KB以上に跳ね上がった。まあ、これはとりあえずそんなに大きな問題ではない。次は、このストリームを外からアクセスするしかけの開発である。

ポートマッピングのテストは成功(6/4/2013)
 本来の目的は、留守宅にいる猫たちの監視である。外からライブカメラ的に見えなければ意味がない。一般家庭のルーターは、一応セキュリティ機能がついていて、外部からのアクセスリクエストは殆ど中に入れないようなしかけになっている。このままでは外から見ることは出来ない。

 というより、殆どの家庭用のルーターは、1つのグローバルアドレスをいくつかのローカルアドレスを持った機器で共用しているので(IPマスカレードともいう)、届け先を指定しない限り、外部からのパケットは届かない。

 外からのアクセスを可能にする方法が、ポートフォワードとか、ポートマッピングというしかけである。外部からのリクエストパケットのポート番号をキーに特定のローカルアドレスの機器に振り分ける。こうすることによって外部とのネットワークゲームや、ストリーミングが可能になる。

 ただ、不用意にポートを開けると、前にも書いたように、ネット上を飛び回っているロボットのポートスキャンを受けてあらぬ攻撃を受ける恐れもあるので、細心の注意が必要だ。画像転送以外に、カメラの位置制御もやりたいのでポートは複数あける必要がある(Apacheを立ち上げて、HTTPプロトコル(80)一本でやる方法もあるが)。

 偉そうなことは言っているが、実は、これまでは講釈だけでこういう実際の作業は始めてである。恐る恐るルーターのポートマッピングのテストを始める。motionのストリーム用のTCPのポート番号は8081なので、まず、こいつだけ開けて、Raspiのローカルアドレス(192.168.0.5)に通すことにする。Photo

 ダイナミックDNSのサービスを受けなくても、自分の今のグローバルアドレスで、外から直接ここへアクセスすれば、所定(RasPi)のサーバーが外から見えるかの確認は出来るはずだ。自宅のルーターの設定サイトにログインしてポートマッピングのエントリーを追加する。

 作業そのものは、1分もかからない。あっという間に終わった。本来なら、ネットカフェとか会社とか別のサイトからアクセスしなければわからないのだが、世の中には、色々なサービス(一種のプロキシーサーバー)をしてくれるサイトが結構沢山あってこういうことを、簡単に調べられることがわかった。

 こうしたネットサービスそのものの信頼性を疑う向きもあるが、疑ってばかりいても始まらない。ここのサイトで実際に試してみる。ルーターのポートマッピング(フォワード)を有効にして、テスト。おお、これまで拒否していた、ポート8081の認証に成功した。我家のルーターで閉じると、ちゃんと拒否した。良いぞ。動いている。

 次は、ニューヨークとベルリン、メルボルンの3ヶ所からアクセスしてくれるというこのサイトでテストする。すごい。3ヶ所とも1秒内外でアクセスに成功した(このサイトの説明が真実なら)。ネットワーク的には無事つながっているようだ。

DiCEと同じ機能を持つ別のスクリプト開発(6/6/2013)
 外から8081ポート(motionのストリーム)にアクセスできることが確認されたので、次は、これを名前でアクセスするしかけの準備に入る。グローバルアドレスは固定ではないので、プロバイダーが変更したときは、これに自動的に追従する機能が必要だ。

 ネットを調べると、DiCEというパッケージが一番使われているようだが、驚いたことに、このパッケージは、日本の個人の制作である。もともとはWindows用のパッケージだが、Linux用もある。ただ、サポートはLinux用は余りされていないようだ。

 しかし、前にも書いたように、必ずしもこれを使わなくても、ダイナミックDNSのメンテナンスは自作スクリプトでも出来るような話がWebに出ている。へそ曲がりでは誰にも負けない所長である。自分で作りたくなった。久しぶりのLinuxのプログラミングだ。心がはやる。

 検索を続けているうちに、ちょうどこちらが使おうとしているNiftyのDDNSサービスを自動化するスクリプトのソースを公開しているサイトを見つけた。これは助かった。細かい、プロバイダーとのやりとりはそっくり真似をすることが出来る。ありがたくソースを頂く。

 Perlで書かれている。Perlなら、昔、Linuxに夢中になっていた頃、ウェブのCGIを作るために、本を2冊も買って勉強し、実際に通信ログの統計ソフトを開発したことがある。懐かしい(所長の蔵書は第2版で写真はPerl5のもの)。

Perl_ref_book1

  久しぶりに、Perlをお勉強する。ネット上のソースを、手元の参考書や、ウェブの情報を頼りに解読していった。perlは最近、Pythonとか、日本発のオブジェクト指向スクリプト言語Rubyなどに押されているようだが、とても強力な言語だ。

 ただ、余りにも色々なことができるため(この大量の特殊変数はとても覚えきれない)、人が書いたソースの可読性は余り高くないかもしれない。ただ、件のソースは、凝ったことはしていないのでまあまあ読み取れる。

それにしても、このwgetを使ったサイトの解析にはしびれた。

# @nifty DDNSのIPアドレス更新ページをwgetでアクセスし、現在のIPアドレスを確認 

$wget = `wget --secure-protocol=auto -O - -q $atniftyddns?$conf_ipaddr`;
$wget =~/[0-9]+(\.[0-9]+){3}/; #この正規表現で、nnn.nnn.nnn.nnnの文字列抽出!
$current_ip = $&; #抽出したIPアドレスを変数に収容

 これだけのスクリプトで良くあの大量のHTML文書から、IPアドレスを抜き出しているものだ。たったの1行である。ソースコードをRasPiにとりこみ、シリアル端末にメッセージを出すコマンドを追加してテストを始める。

 現在使っているAUひかりは、一旦つながってしまうと滅多にグローバルアドレスは変わらないようだ。このところ全く変更がない。どうも、それほどあせって自動化を図る必要もなさそうだ。とりあえず手動でコマンドを出して動かしてみる。cronにするのは後でも良い。

 よし、現在のグローバルアドレスが端末に出て、このPerlスクリプトが書いたテキストファイルに収容された。ここはこれくらいで良いだろう。まだ、NiftyからダイナミックDNSのドメイン登録をやっていないのでこちらを先に進めることにした。

DDNSのドメインを登録したが、勤め先からの接続は失敗(6/10/2013)
 NiftyのDDNS(ダイナミックDNS)サービスは、XXX.atnifty.comというサブドメイン(XXXが自分の名前)なら、一ヶ月¥200で、独自のドメイン(YYY.comや、ZZZ.jpなどが選べる)なら¥400で借りることが出来る。

 迷ったが、まあ最初なので、安い方にしておく(登録したドメインネームは、まだ認証機能がついていないのでここでは公開できない)。前にも書いたが、このNiftyのDDNSのサービスのサイトはとてもわかりにくいところにある。

 しかしページが見つかれば設定は至極簡単である。申請して、その名前がまだ使われていなければ、ほんの数分で登録が終わる(もちろんNiftyユーザーとしてログオンする必要あり)。登録がOKになったので、早速テスト。自分のPCでpingを打ってみる。

 だめだ。not reachableになってしまう。中からは名前を引くとグローバルアドレスになるからだめなのだろうか。いや、グローバルアドレスの直打ちならpingは通る。おかしいところはない。頭を抱えた。

 しかし、心配は無用だった。暫くすると、pingが返ってきた。そりゃそうだ。すべてのネームサーバーに瞬時に登録されるわけではない。沢山のサーバーを経由するわけだから少し時間がかかるのは当たり前なのだ(一旦つながれば、キャッシュされるらしく瞬時に帰ってくる)。

 次の日は出勤日だった。朝、出かける前にRasPiの電源を入れ、ウェブカメラを生かしたまま事務所に出た。ひととおりの仕事を片付けて、どきどきしながら、RasPiのストリーミングサーバーにアクセスする。グローバルアドレスが前日と替っていないことは確かめてある。

 残念。つながらない。それならとグローバルアドレスの直か打ちで8081のポートにアクセスしてみた。しかし、これもつながらなかった。ただ、門前払いでなく、ネットはつながるが、向こうのレスポンスがタイムアウトしているような感じだ。それならと、pingを打つ。何と、この事務所、pingが通らない。まあ、IT関連の事務所なので、ICMPパケットのフィルターが掛けられているようだ。

遂に外部からのアクセスに成功(6/12/2013)
 帰宅して、早速つながらない原因を追究した。内部のローカルアドレスでは問題なく動く。ルーターのポートマッピングのエントリーを調べる。今、2台のRasPiがいるので(1台はSAMBA用)、念のため、8081のポートは、2つのローカルアドレスにエントリーしてある(特にエラーにはならない)。

 ふむ、今、ストリーム用に生きているのは、192.168.0.10の2台目のRasPiで、もう一台の192.168.0.5は電源が入っていない。順番は、あーっ、192.168.0.5の方が先頭だ。このエントリーをルーターがどう解釈するかだが、ルーターが親切に2台を調べて動いている方にデータを送るなんてことは殆どありえない。

 これだ、これだ。これに違いない。事務所で動かなかったのは、電源の切れている192.168.0.5の方に8081リクエストを送っていただけに違いないだろう。あわててポートマッピングのエントリーをストリーミングサーバーにしている192.168.0.10の方だけにする。

 不具合(と思われる)箇所はすぐ直したが、その確認は今ここでは出来ない。意気込んだ気持ちの吐け口がわからなくて、ウェブを手当たり次第に検索したときである。自作したWWWサーバーが動いているかどうかテストしてあげるという親切なウェブサイトを発見した。

Www おおー、これなら外に行かなくても、自分のところからウェブサーバーの状況を見ることが出来そうだ。ポート番号が、HTTPの80番でないのが少々心配だが、だめもとである。早速、このサイトの項目に http://XXX.atnifty.com:8081/ と入れてみた(XXXは仮名)。

 やった、やりました。見事に、1Fに設置したライブカメラの映像が、PCに出現した。ヒャッホー、遂に、外部から自宅内のウェブカメラの映像が見えた瞬間である。2年前のBeagleBoardあたりから狙っていた機能が遂に実現したのである。Photo_2

 この数日後、事務所のPCで、実際に映像が映ることを確認した。名前引きでもちゃんと見える。これで間違いなく、ストリーミング映像は外部からアクセスできることがわかった。ライブカメラプロジェクトは、いよいよ次の大物、カメラのパンとチルトのモーター制御の開発に移ることが出来る。あ、DDNSの方もテストしておく必要があるか。

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

2013年4月26日 (金)

STM8Sでグラフィック液晶に漢字をスクロール表示する

ハングアップするSTM32F107の気圧計を修理する(4/13/2013)
 STM8Sでグラフィック液晶に日本語フォントを表示するプロジェクトは一段落したが、実は前から気になっていることがある。一年ほど前、O-Familyさんの掲示板で知ったのがきっかけで作ったグラフィック気圧計がまともに動かなくなってしまった。

 この気圧計のMPUはSTM32F107で気圧センサーは秋月のMPL115A2、Aitendoの2.4インチのカラーTFT液晶(YHY024006A)に2日間の気圧の変化をグラフィックに表示する。気圧データは、毎秒測定した気圧を1分ごとに平均化し、10分に一回、I2CのEEPROMに蓄積する。

 RTC(リアルタイマークロック)を内蔵しているので、実際の年月日を表示したグラフ枠に直近の2日間の気圧遷移が折れ線グラフで表示される。予報ロジックの組み込みや、ケースに実装する工程が残っているが、とりあえずここ数日の気圧の変化が一目で確認できるので、このままで結構重宝していた。

 当初この基板にはソケットの接触不良があって、長時間稼動させると(2~3日以上)、止まってしまう持病があったのだが、直接ピンとピンの間を別配線してしまうことなどで、トラブルは解消していた。ところが、最近になってまた止まるようになった。しかも動いている期間がどんどん短くなり、このところは数時間が限度である。これでは実用にならない。

 止まる要因で疑われるのは、TFT液晶の描画と、気圧センサーMPL115とフラッシュROMの読み書きに使っているI2Cインターフェースである。最初、液晶の描画ルーチンを疑っていたが、詳細にコードを調べて、このプロセスでは、少なくともMPU側にはループする要素が見当たらないことがわかった。

S_p4255844  とすると、残るはI2Cである。このI2Cのドライバーは、例の弁護士さんの書いた「STM32マイコン徹底入門」でも紹介されたSTマイクロの標準I2Cライブラリーを殆どそのまま使っている。久しぶりにEclipseを立ち上げて、ソースを見る。

 他のウェブや、この本にも書かれているとおり、このライブラリの信頼性は余り高くない。しかし、これに換わる適当なコードはないので、とりあえず仔細にソースコードをチェックする。何だ、何だ、ソースコードには、たくさんwhileでイベントが終わるのを待っているところがある。4箇所もある。しかも無限ループだ。これでは沢山のところでハングアップする可能性がある。

無限ループをやめて、エラーexitをつけたのに止まらなくなった(4/14/2013)
 回数を数えて、一定の回数以降はそのループを抜けるようにソースを書き換えた。ところが、MPL115が正しい値を返さないようになって測定値が乱れる。うーむ、1000回程度ではだめなのか。
クロックを計算してみたら数十μsだ。こりゃいかん。MPL115はまだ測定を終えていない。

 60000回以上(1ms近辺)でループを抜けるようにして、様子を見る。これが不思議なことに、何時間経っても、エラーexitもせず、しかも全く止まらなくなってしまった。2日間でも止まらない。???である。

 要するに少しソースに手を入れただけでタイムアウトもせず(エラーメッセージも出ず)、無限ループにも入らず直ってしまったのである。逆に、UARTの切断/接続でハングする。えー、UARTルーチンにイベントを待つプロセスなどはないぞ。これも謎である。暫く様子を見ることにする。

 それにしても最近の物忘れの程度は度を越えていて、自分でも笑ってしまうほどだ。STM32の開発手順を見事に忘れている。この気圧計の開発を盛んにやっていたのは、わずか1年前である。それが統合環境のEclipseでのソースのコンパイルはともかく、ファーム書き込みの具体的な手順が思い出せない。

 さすがに、どういうツールを使うか(中華製のシリアルローダーMCUISPを愛用している。他のプログラマーの出番なし)くらいは覚えているが、どういう手順でプログラムをロードするのかブートモードが0だったか1だったかも忘れている。見事なものだ。

 エラーが起きないので、これ以上のデバッグは出来ない。デバッグというより、I2Cがエラーで帰ってきたときにどうするかを考えておく方が合理的かもしれない。測定は毎秒やっているのでひとつくらい読めなくても大きな差は出ない。EEPROMの書き込みでも2日間のグラフなので、1回や2回データが欠けても大勢には影響がない。

ハードウェアのスクロールは難しい(4/15/2013)
  気圧計のエラー発生待ちで手が空いたので、いよいよSTM8Sの最後の課題、ハードのDisplay Startコマンドを使った漢字のスムーズスクロールを実装する作業に入った。

 問題は、縦64ラインある画面に12X12ドットの漢字を表示し、これをなるべく乱れなくスクロールしていくことである。これまでの検討では漢字フォントを分割して(画面の最下部と最上部に分けて)描画できればスムーズスクロールが出来るはずである。

S_p3285780  つまり、縦(Y軸)0ラインから、12ドットの漢字を5行表示し、余白になっている画面の60ラインから一字の4 ドット分描画し、画面の0ラインに戻って残りの8ドット分を描画する。さらに4ラインの空白を表示し、ここにハードウエアの描画開始アドレスを移動すれば、全体の漢字の位置は全くずれずに、1行分スクロールされることになる。

 このやりかたは、漢字描画の縦の物理スタートポイントが、決まった位置になく少しづつずれて行き(次の行の開始アドレスは12ではなく8。16回廻って一周)、スクロールのスタートアドレスも、それに合わせてずれるので、コーディングには細心の注意が必要だが、今のところ、この方法以上のやり方は見当たらない。複雑だがこれを実装することにする。

 まず、必要なのはフォントの分割表示のための、グラフィックライブラリの中の日本語フォント関数LcdChr_Kanji())への機能追加だ。これまでは画面の最下部にかかる文字の描画は、エラーリターンしていたのを、折り返して最上部に残りのフォントを描画するようにロジックを追加する。

 この改良は、相当厄介だろうと覚悟していたのだが、思いのほか追加するステップが少なく、簡単に完成した。Y方向(縦)のドットのアドレスを画面の最大幅になったときに0に戻すだけである。こんなにうまくいったのは、最初のプログラムの構造が良かったからだと自画自賛する(動いてから自慢するべきだろう)。

 実際にスクロールを制御するところは、ライブラリではなくmain.cの中である。SRAMが残り少なくなっているので、変数を増やすのは気を遣う。手持ちの変数を使いまわして、描画のスタートポイント、スクロール開始位置のシフトを考える。

 やっぱり一筋縄では動かない。擬似コードを何度もやりなおす。なんとかコーディングを終了した。いよいよテストである。苦労が多いほどこの瞬間はわくわくする。最初は連続ではなく、スペースバーを押すたびに、一字づつ表示するようにする。

 順調に画面の最上部から、漢字が出てくる。スクロールしないときの表示は順調だ。まあ、ここは前と変わっていないので表示されて当たり前なのだが、ついに画面の最後まできて、スクロールするところに来た。

 思い切って先へ進む。おお、画面全体が上に上がった。しかし文字は、表示されない。消し残しのようなラインが出るだけである。さらにキーを押して次の文字を出す。おっ、今度は文字が出た。コードを確かめる。出るべき正しい文字だ。スクロールした最初の文字だけが出ないが、分割したフォントは正しく文字になっている。良かった、この部分はうまく行っているようだ。

 さらに文字を出していく。何とかスクロールが動いているようだが、周辺にはゴミが出るし、行換えした直後の文字が出てこない。一字づつを止めて連続表示をしてみると、文字が乱れたりループしたりして不安定だ。しかし、とりあえずスクロールはしている。とはいえ完成にはまだ程遠い。

すこしづつスクロールが出来てくるが連続はまだ無理(4/16/2013)
 最初の文字が出ないのは、画面の更新をするときの領域の設定ミスとわかった。描画領域の定義は、仮想の描画スタートアドレスではなく、物理的なVRAMの範囲なので、分割して表示する時は結局、全部を描画領域にするしかない。

 これを直して、スクロール直後の文字もめでたく画面に表示された。しかし、スクロールの幅がおかしい。思ったように下の余白が止まっていない。表示が4ドット分上がったり下がったりするので、連続して表示するととてもスムーズなスクロールにはならない。それに画面にゴミが残って、それがスクロールに合わせて動く。

メモに図を描いては、画面の動きを確かめ、UARTにドットアドレスを表示したり、デバッグを進める。スクロールの幅は常に12ドット(文字フォントの幅)で良いはずだ。それなのに何故、4ドットの余白が移動するのだ。そのうち思い違いをしているのを発見した。

 ハードスクロールのスタートアドレスを新しく表示する文字のスタートアドレスに合わせている。ああ、これでは駄目だ。スクロールの開始アドレスは、0ラインから12ラインづつ動かしていけば良いのだ。このままでは空白は最上部に行ってしまう。まさしくプログラムは書いたようにしか動かない。

  面のゴミは原因不明だ。スクロールのあと、表示するまえに1行分全体を消去しているのだが、このあたりは並木算の世界である。0オリジンか1オリジンか、最後の部分は含むのか、含まないのか。画面の途中ならそう難しくはないが、折り返すところがどうしても計算が合わない。

ライン0を表示しないのは元の関数の仕様だった(4/17/2013)
 ゴミが出るのは、折り返しのところだけなのは間違いない。しかし、消去する幅や、起点を調整しても、ゴミがとれない。どうも今開発しているプログラムに誤りはなさそうだ。となると下部関数に何か不具合があるのではないかという疑いが出てきた。

 そら。さんから頂いたこのグラフィック液晶(GLCD)ライブラリのオリジナルは、外国でNOKIAの液晶用に開発されたようだ。グラフィックの部分は、このGLCDではコメントアウトされて使われていなかった。こちらが勝手にコメントをはずして動かしているので、このGLCDで動く保証はない。

 グラフィック関数は階層構造になっていて、新規に開発した特定の行を消去する関数、LcdFill()は、LcdLine()で直線を引き、LcdLine()はLcdPixel()という1ドットを描画する関数を使っている。

 LcdLine()から見ていく。特におかしいところはない。次は、LcdPixel()を調べる。あ、あ、あ、画面の0アドレス(Y軸)は何も処理せず帰っている。何だ、何だ。0ラインにはドットが描けないのか。スクロールは0ラインにもドットが描けなければ正しい字にならないのに。

 不具合でも何でもない。元からこういう仕様だったのだ。やれやれ大山鳴動鼠一匹である。もっと早くここを確認すべきだったのだ。0ラインも描画するようにして今まで汚かった画面は一掃された。漢字フォントだけが綺麗に表示される。一字づつ表示していくだけでは問題なく漢字が表示されて行く。よーし、大分進んだ。

 しかし、連続するとまだ途中でループしたり、画面の位置が変わったりする。まだ何かがおかしい。トラブルシューティングは終わらない。

連続してスクロールが出来ないのも大きな勘違いだった(4/19/2013)
  連続スクロールは、入力されたシフトJISの漢字コードに1バイトづつ足し上げ、漢字コードのときのみ(LcdChr_Kanji()は有効な漢字コードでないときはエラーで帰る)画面上に漢字を出すようになっている。

 待ち時間を入れないで連続表示させると、表示が速すぎて、画面全体が白くなり、字そのものが殆ど読めなくなってスクロールの意味がなくなるので、一字あたりに30ms程度の待ちを入れて表示する。

 ところが、連続しているうちにスクロールの位置が変わったり、ある時点でループに入ってしまう。 一字づつでは問題なく、連続してエラーが出るのは、ハードが疑われる。表示位置を変更するコマンドの前後に待ち時間を入れたり、表示そのものの関数にも待ちを入れたり、時間調整してみるが全く改善されない。

 GLCDのSPIインターフェースが早すぎてデータをとりこぼしているのかもしれない。現在のSPIクロックは、2MHzである。データシートを確かめてみる。何とこのGLCDは20MHzくらいまでサポートしており全く問題ない。

 そのうち一字づつ表示を続けているうち、全く同じところで表示が乱れることがわかった。うはあ、これはハードではない。ソフトだ。非漢字領域をスキップしているところで、どうもエラーが起きているようだ。

 漢字コードでないときのエラー処理がおかしい。念入りに調べる。あっあっあー、わかった。非漢字コードのときは、文字をずらすところをスキップしているのだが、肝腎のスクロール処理がこのループからはずれているではないか。これではたまたま表示が左端で非漢字コードが来た時、無意味なスクロールをしてしまう。

 何というお馬鹿なコードだ。非漢字領域のコードの描画が画面左端から始まるときのみ、おかしくなるので発生がランダムに見え、ハードを疑っていたが、何のことはない、単純なソフトのバグだった。今まで疑っていたGLCDさん大変失礼いたしました。悪いのは全部私です。

この解決で、グラフィック画面は、延々と漢字を表示し続ける。いやあ、良かった。良かった。これで動画が公開できる。この画面では、漢字一字に30msの待ちを入れて表示している(スクロールは待ちなし)。これより少ないと、表示が速すぎて液晶の残像で満足に字が見えなくなる。

これでSTM8SとGLCDの当面のテーマはすべて完了した。この日本語表示を何に使うかが今後の課題である。音声合成チップとあわせてネットワークを経由したメッセージボードのようなことが出来ると面白いかもしれない。

ここに例によって上記のソース一式をSTVDのプロジェクトごとzipファイルにしたものを置きます。STM8のライブラリはこれまでどおり同梱されていません。以前の記事を参考に所定のディレクトリに設定してビルドしてください。容量の関係でフルビルドが必要です。

「JCG12864_426.zip」をダウンロード

本格的なFETスイッチの実験(4/22/2013)
 このあいだ秋月から買ってきたMOSFET(FKV575)のスイッチの実験の続きである。ブレッドボードにCRとトランジスターの遅延回路を組み込んで、FETでLEDを1秒ほど遅らせて点灯する実験は成功した。しかし実際のスピーカー切り替え用の2つのFETを組み合わせた本格的なスイッチはまだ組んでいない。

S_p4235837  前回にも書いたように、2つのFETで構成されたスイッチの導通抵抗がどうも寄生ダイオードによってミリΩ台になっていないような気がする。ウェブを見ているとACのスイッチには、何と4つのFETでスイッチを構成しているものもあり、その回路図を探していたが見つからなかった。

 迷っていても仕方がない。現物があるのだから実際に試してみるのが手っ取り早いのではないか。まずは最初組んだFETひとつの回路に、オシロと秋月のファンクションジェネレーター(FG)で導通を調べてみることにした。

 FGの出力は、AC(±1V)なので、FETひとつなら、片側が半波整流のような波形になるはずである。ところが、これがおかしなことに、ACが完全に通るのである。所長のFETの知識は、トランジスターのアナロジーで、ドレイン(コレクタ)からソース(エミッタ)に流れる(N型のとき)電流をゲートが制御し、ソースからドレインには電流がそもそも流れないというものである。

 寄生ダイオードは、この逆電位のときに流れるもので(これはトランジスターにはない)、スイッチに使うときは、これが効かないよう、FETを背中合わせにするのだと思っていた。

 ところが、前回の記事に、久しぶりにkugaさんからコメントがあり、自分が勘違いしていることがわかった。FETはゲート電位が上がって導通状態になれば、たとえドレインがソースより電位が低くなっても(NMOSのとき)、寄生ダイオード以外のところでも電流が流れると言うのだ。

S_p4235830  どうも勘違いをしていたらしい。それなら本番用を実験してみよう。ブレッドボード上に背中合わせにFETをつけた回路を組む。たいした手間ではない。FGの出力を、このスイッチを通してオシロにつなぐ。導通は?うむ、全く問題ない。では、ゲートの電圧を0にする。ありゃあ、切れてないぞ。矩形波はサグの出る波形に、正弦波は殆ど減衰せずにそのまま出ている。

負荷抵抗を入れると切れた。うーむアナログは難しい(4/23/2013)

Fet  えー、どうして切れないのだ。良くわからない。ウェブで同じような実験をされているページの回路図を確認した。あ、そうか。負荷抵抗がいるのだ。微小電流ではFETは遮断できないらしい。

今ひとつ理屈はわからないが、本来はスピーカーという数Ωの負荷を切るスイッチである。この状態で調べるべきだろう。しかし、現在のFGは、内部抵抗が高く、とても数Ωの負荷抵抗をドライブすることは出来ない(出力は0になってしまう)。

S_p4235838  とりあえずFGが何とか出力を出す(0.5V)くらいの負荷抵抗、300Ωを入れてスイッチを調べてみた。よし、わずか脈流は残るが、出力は殆ど0になった。スイッチは機能したようだ。しかし、正弦波は切れたが、矩形波は立ち上がり(下がり)に鋭いパルスが残る。

 これは結局、実際の音で確かめるしかないか。使用を予定しているメインアンプの切り替えは少しおおごとなので、手元にあるカマデンデジタルアンプで試してみることにした。スピーカー端子は幸いこのあいだワンタッチの端子板に換えてあるので接続は簡単だ。

S_p4235826  これはFETが持つ内部寄生容量で一瞬導通するからではないかと思うが、これを解説しているところは見つけられない。この症状は0.01μFくらいのコンデンサーを負荷に並列に入れるとパルスはおさまり、何とかスイッチの役目を果したようだ。

 ブレッドボードからジャンパーを出し、念のためオシロもつないで片チャンネルだけスイッチをつける。問題なく入り切りができた。全くの無音になる。音は変化したか。この程度のスピーカーやアンプで、これを判別するのは無理と言うものだろう。

S_p4235824

 ウエブでも、機械リレー方式との音の違いを追及している人がいるが、まあスペックを信用するしかない。矩形波の残留パルスはMhzの世界で、少なくとも可聴周波数域での違いは全くないと言ってよいのではないか。

 ウェブをさまよった挙句、4つのFETを使ってスイッチする理由がわかったような気がする。FETのオン抵抗(Rds)が入力電圧(ゲートソース電圧)によって大きく違うので、レールツーレールにするため、P型とN型を並列にして特性を相殺しているためではないかと思われる。   http://www.analog.com/jp/content/cu_ad4505jp/fca.html
まあ、ここまで心配ならリレーを使えば良いと思うけれど。

 実験はそろそろ良いだろう。これを実装する工程が待っている。いずれにしても、スピーカーのミュートスイッチは、一般のFETのスイッチング特性とは全く別の世界(スイッチング周波数は全く無関係)なので参考になるウェブサイトは意外に少ない。以下は、スピーカーのFETスイッチに関して参考になったサイトのURLである。ご参考まで(勝手リンクご容赦)。

そもそもフォトボル型カプラーを知ってFETスイッチを作ろうとしたきっかけのサイト。
http://easyaudiokit.hobby-web.net/bekkan/MOSFETrelay/MOSFETRELAY.html

スピーカーのミュートをリレーからFETにしたときの考察。切れていたら()内のホームから。
http://members2.jcom.home.ne.jp/2060bl/21review/18ftrly/01vrfctn/vrfctn1.html
http://members.jcom.home.ne.jp/4120blaudio/index.html

マルツのFETスイッチの基礎的な解説。FETの一覧表もある。わかりやすい。
http://www.marutsu.co.jp/user/fet_3.php#mos-fet3

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

2012年5月29日 (火)

気圧計のバグつぶしと、ステッピングモーターの静音化

EEPROMストリームの一周がうまく行かない(5/18/2012)
 気圧センサーMPL115を使ったSTM32F107のグラフィック気圧計は、順調に気圧の推移を表示して稼動し始めた。嬉しくなってこの制作のきっかけとなったO-Familyさんの掲示板にも報告する。みんなが祝福してくれた。

 人は狩猟生活をしていた原始時代から、一人では生きていけない動物である。本来は孤独な電子工作だが、こういう機会を通じて沢山の同好の人と自宅に居ながらにして交流できる。こんな楽しいことはない。ネット社会の有難みをしみじみ実感する。

 稼動が2日以上になって気が付いた。気圧の表示は直近2日間だけなのに、外付けのI2CのEEPROM(24FC256)の容量は256キロビット(32KB)で1週間以上蓄積される。2日分(8KB少々必要)しか表示しないにしては大きすぎる。S_p5144879

  EEPROMのバッファーそのものは、データが一杯になれば、古いものから消していくしかけ(リングバッファー)になっているが、このままではグラフ表示が無用なデータの読み込みで遅くなってしまう。EEPROMの量を制限して、2日で廻るようにした。

 と、これが2日間のあとバッファーが折り返されるとレコードが目茶目茶な形になってグラフが表示できなくなった。折り返しのテストは、開発の初期にサイズを256バイトに縮めて何度もテストし、問題なく動くことを確認している。それなのに何故だ。

 UARTを付けてEEPROMから読んだデータを調べて、その原因はすぐわかった。 データがバッファーの最後まで書かれてオーバーラップした際、スタートポジションを1バイト余分に進めている。そうか、今までこのバッファーの使い方は、バイトストリームなので1バイト飛ばしても余り大きな問題にはならなかったのだ。データが最初に折り返すときに書き潰されるデータがひとつ増えるだけで、そのあとは問題なく折り返されていく。

 しかし、今度のアプリケーションは、32バイトのレコード単位にデータを蓄積している。このような形で、折り返しのストリームバッファーを使っている時には、この1バイトのずれは致命的である。1レコード分をすべて無効にしてアライメントを合わせてしまえば良いが、これでは解決したことにはならない。 

 しかも、今度のストリームはハードウエアがページ単位に読み書きするEEPROMで、アライメントに厳格だ。まあ、EEPROMのページサイズを考慮しないでもアクセスできる構造になっているので、レコードサイズを合わせる必要はないのだが、何となく気持ちが悪い。

簡単に修正出来ると思ったが意外に難しい(5/20/2012)
 始めは、バグのつもりで気楽に修正に取り掛かった。要するに、データがバッファーの最後まで書かれて、バッファーのトップに折り返すとき、スタートポジションを先に1つずらしてしまうのが、データが乱れる直接の原因である。

 データはまだ書かれていないので、このときにスタートポジションを移動する必要はない。次のデータが書かれるときに始めてスタートポジションを動かせば良いはずだ。これでこの問題は解決とばかり、コードを直してテストしてみた。

 しかし動かない。考えてみたら、データを読むときのEOF(End Of File ファイルの最後)の条件は、読み込むポジションがデータの最後に来た時である。データが書かれる前までスタートポジションを変えないということは、スタートとエンドが同一ポジションにあるということである。 既に読み出す前にEOF条件を満足しており、これでは先に進まない。意外や意外、難しい話になってきた。

 調べるにつれて、これは深刻な問題であることがわかった。スタートとエンドが同じポジションにあるとEOFの条件判定が極めて難しくなる。今まで、折り返しストリームバッファーがうまく動いていたのは、スタートポジションとエンドポジションが1つずれていたためなのだ。無駄なデータが必要だったのである。

 頭を抱える。メモ用紙にバッファーの図を書いて、解決法を探る。整理した結果わかったことは、データのスタートとエンドのポジションが重なると、このバッファーが、データが書かれた状態なのか、全くデータのない初期の状態なのかは、これだけで判別することは出来ないということである。

 それなら、エンドポジションの位置をスタートポジションとずらして、リングバッファーを操作すれば良いのではないか。データが全くない初期のときはデータのエンド位置をバッファーの最後に置くなどすればデータがないときと一周したときの判別が出来るはずだ。

 しかし、これも実際に動かしてみるとデータがあっても0の状態になったり、EOFが判別できなくてループになったりしてうまく動かない。いくらエンドポジションをずらしても、最後に書き込まれたデータ位置は、物理的にスタートポジションと同じなのでEOFの判定をするときは前のスタートとエンドを同一にしているときと変わらないからだ。S_p5284990

 結局、3日近くあれこれ考えた末、スタティックなポインターの位置だけでEOFを判別することは諦めた。やりたくはなかったがフラグを持ち込むことにした。スタートポジションを2回通った時に始めてEOFと判断する(1回のときはフラグを立てるだけ)ようにする。

 フラグ方式なら、beforeEOFとも言えるようなフラグを作っても良い。エンドポジションを最終データの一つ前に設定しておき、ひとつずれる形でEOFを返す。どちらが良いか迷ったが、わかりやすい前者の方式で実装することにする。

 ロジックが固まった(勿論例の擬似コードである)ので、テストに入る。EEPROMの関数を直すだけでは、テスト結果は2日かかることになるので、mainプログラムをいじって早く結果が出る(バッファーを使いきる)ようにし、テストする。

 何度かプログラムを修正して、やっとのことでデータは正しくバッファー上に記録されるようになった。これが最善の策か自信がないので、このブログに擬似コードと図を載せて、読者の方からご批評を待ちたいと思う。もっと良い方法があれば教えて下さい。

上記の修正を加えたEEPROMのライブラリをzipに固めたものを下に置きます。以前公開したコードでは折り返しで1バイトずれます。また、気圧計全体のロジックの参考のため、main.cも入っています。ただしこれだけでは動きませんのでご注意。

「5_28_2012eeprom_lib.zip」をダウンロード

自動巻き機のマイクロステップ制御の勉強を続ける(5/21/2012)
 時計の自動巻き機の工作の話である。ステッピングモーターを静かに回すための方策、マイクロステップ制御の検討を続けている。前回記事にマイクロステップ制御には4つもPWMチャネルが必要だと書いたら、コメントでhiraさんがバイポーラなら2本のPWMで出来ることを教えてくださった。

 ユニポーラモーターでも、バイポーラにして使うことが可能なようだが、モータードライバーには、逆転が必要なため、フルブリッジのドライバーが2つもいる。PWMを2つにしたいのは、Tiny13などの8ピンのAVRがPWMを2つしか持っていないためで、Tiny45も、調べたらPWMを4つ持っているのにPWM出力は不思議なことに3本しか出すことができない。

 とはいえ、8ピンのAVRで実装しなければならない必然性は殆どない。AVRチップ最安値(秋月で¥100)のTiny2313は、余裕で4本のPWMが使える。それに、こちらには、Xbeeラジコンのときに間違えて買ったステッピングモーター用のFETモジュールMP4401が5つもある。早くこいつを消化したい気持ちもある。ここはとりあえず2313で実験を進めることにする。

ただ、2313ではタイマーを全て使い切るので、運転制御のためのタイマーがPWMのタイマーと併用できるか心配である。ウェブを見ていると、バイポーラのマイクロステップ制御のICが数多く売られている。それだけ需要があるということなのだろう。

マイクロステップ制御の仕様を固める(5/23/2012)
 だいぶ煮詰まってきたので、細かい仕様を決めていくことにする。クロックの計算をする。波形は、一番ポピュラーな正弦波にすることにした。これを分割して近似波形の0から255 までのテーブルを作る。PWMサイクルは20kHz(5ms)、分解能は8ビットで十分だろう。回転は恐らく、1分20回転もする必要がない。正弦波は、どの部分を使うのだろう。 

 最初はモーターを動かさずにLEDとオシロで実際に波形が出るかどうかを確かめれば良さそうだ。偉そうなことを言っているが、実は、がた老AVR研究所はまともなPWMは始めての経験である(ゼロクロスのトライアックで真似ごとのPWMはやったが)。

 波形はサインカーブをEXCELで作り、1/2π分を32分割で作る。分割の数は良くわからないで適当に決めた。これをテーブルに入れ、PWMカウンターのオーバーフロー割り込みの度にデータを移していけばPWMが出来るはずである。

 さらに、4相のモータードライブ単位に、PWMを設定していく。モーターの1サイクルは全体を少し大きな(ステップ数の多い)ステートマシンで動かせばよい。まずは1チャンネル分のPWMを作り、LEDとオシロで確認することにする。

 久しぶりのAVRの開発である。この前のステッピングモーターのAVRStudioプロジェクトをコピーして、新しいソースコードを起こす。色んなことを忘れている。何かの手違いか、全く同じソースを持ってきたはずなのにビルド出来ない。エラーで帰ってくる。

 こういう統合開発環境の不具合は厄介だ。先を急いでいるので、深追いせずこのプロジェクトをさっさと諦め、もういちど別のプロジェクトを起こしなおす。よーし、動いた。何が悪かったのか追求しても始まらない。ソフト開発の世界はこういう見切りも結構重要な要素のような気もする。

 PWMといっても難しいところがあるわけではない。やたらにタイマーの定義が複雑なだけだ。でもARMに較べれば、AVRのタイマーの定義など可愛いものだ。8ビット高速PWM、コンペアレジスター2つで、2つのPWM波形がとれる。とりあえずタイマーひとつだけに実装し、LEDが人間の目で蛍のように瞬く時間にプリスケールを定義して、簡単にソースコードが書けた。

LEDで実験に入る(5/24/2012)
 ブレッドボードにLEDを差して、早速実験に入る。LEDが点いた。しかし、変な瞬きである。ギクシャクしているし、完全に消えないところがある。オシロを接続して出力波形を見る。ふむ、何となくPWMっぽい波形だが、あちこちにパルスが出て(これがLEDの消えない理由)、しかも綺麗な波形ではない。

 デバッグに入る。ヒゲが出るわけは判明した。スタックを減らしてプログラムを小さくするため割り込みではフラグを立てるだけで、主な処理はすべてメインルーチンに引き込んでいる。ステートマシンの番号でフェーズを判定し、コンペアマッチレジスターを0にしているが、タイマーはCPUの動きとは無関係に動き続けるので、この差の分だけヒゲになるのだ。

 そういうことなら、これを割り込みルーチンで直接やれば良い。これでヒゲはなくなるはずだ。おやあ、まだ残る。何故だ。そうか、高速PWMではカウンターがオーバーフローすると出力は1にトグルされるが、オーバーフローしてから、このユーザープロセスの割り込みルーチンに来る時間は0ではなく必ず少し遅れる。

 CPUクロックとのプリスケールが8程度では、8ステップ以内にコンペアレジスターを0にしなければならず、割り込みでうかうかレジスターの退避などしていては間に合わない。このグリッチはクロックを上げてプリスケールを増やせばなくなるのだろうが、何となく対症療法的でしゃくである。

 データシートを眺めているうち気がついた。意味が良くわからないが「位相基準」PWMというのは、コンペアマッチする場所とオーバーフローするところが違うようだ。PWM周波数は1/2になってしまうが、これならグリッチは出ないのではないか。

 早速、確かめる。タイマーのレジスター設定で「位相基準」PWMに替えて動かしてみる。ビンゴ!だった。全くグリッチはなくなり、LEDも完全に消えるところが出来てホタルらしく点滅する。よーし良いぞ。ただPWMで調整している光の動きがどうもギクシャクしているような気がする。S_p5264894

 出力ピンに4KΩと、1μF程度のLPFをかませてオシロで見てみた。思ったより綺麗なサインカーブが現れた。おやあ、カーブが最大になったあと、少し欠けて次の下降カーブになっている。ちょうど、LPCMプレーヤーでバッファーアンダーランを見つけたときのようなカーブだ。綺麗なサインカーブが一部欠けているところが見つかったのである。

 ソースコードを調べる。すると、カウンターの増やし方を間違えているところが発見された。これを直して動かしてみる。やった、やった。完全なサインカーブがオシロの上で観測できた。いやあ、オシロを買っておいて良かった。これはロジアナではなかなか発見できなかっただろう。

モーターは完全に静かになった。大成功(5/26/2012)
 マイクロステッピング制御でモーターを動かせる環境が少しづつ整って、完成の期待が段々高まってきた。1つだけのPWMチャネルを4つに拡張する。ブレッドボード上にあり合わせのLEDを差して、それぞれホタルのように次々に点滅する様子を暫く楽しんでから、いよいよモータードライバーを接続する。

 さきほどの簡易LPFをさらに3組増やす。ブレッドボードは林のように部品が乱立するがそれにかまっている場合ではない。配線が済んだ。さあ、どうだ。コンパイルはARMと違ってフラッシュが2KBもないのであっという間に終わる。さあ実行である。緊張の一瞬。「ゆけー」という掛け声とともに電源ON。

 しかし、モーターは、「ンゴゴゴ...」と言ったまま、廻る気配はない。ふーむ、配線を間違えたか。試しに一部を反転させてみる。廻り始めた。おおお、全く音がしない。手に持っているとわずかな振動が感じられるが、導電スポンジの上に置くと、余程耳を近づけないとモーター音が聞こえない。

 大成功だ。LPFの部分を少しいじってみる。意外なことに、コンデンサーをはずすとモーター音は更に小さくなった。手で持っていても、この状態だと殆ど振動を感じない。ただし、モーターを机の上に直に置くと、PWM周波数(およそ2Khz)の「ピルルル」という音がはっきり聞こえる。ひところの電車のモーター音のようで面白い。

S_p5284991

 コンデンサーをつけるとこの高周波音は小さくなるが、モーターの振動は明らかに増える。抵抗は入れてあるほうが静かになる。エッジがなまるからであろうか。パルス制御で言えば一相制御にあたるのでトルクの低下を懸念したが、手で止めることが出来ないくらい力は十分で、時計を回すくらいなら全く問題がない。

 いやあ嬉しい。あれだけゴーゴーとうるさかったステッピングモーターが、全く無音になったのである。同じモーターとは思えないほどだ。PCの横で動かせば、PCのファンの音で、モーターが廻っている音は完全に消える。ただ、長時間動かすとモーターは2相パルス駆動のときより明らかに発熱する。

 2時間連続で動かしても、少し暖かいなという程度なので、これからのアプリケーションには全く問題がないが、やっぱりモーターには少し負担がかかっているのかもしれない。一方、MP4401は全く変化がない。この程度のPWM制御は全く問題がないようだ。

 これで自動巻き機のソフト開発は峠を越えた。これだけ音が静かになったのだ。大威張りで巻き機だと自慢できる。残るは、マイクロステップ駆動の逆転である。これ結構面倒くさそうである。

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

2012年5月15日 (火)

グラフィック気圧計の完成と、腕時計自動巻き機の制作

 今年始めから手がけてきたSTM32F107と2.4インチTFT液晶を使ったグラフィック気圧計(天気予報計になる予定)が、やっと想定した気圧の推移を画面に描き始めた。いやいや、完成までえらい時間がかかった。これから最後のソフト開発について報告するのだが、実はこのプロジェクトと並行して全く別の工作を続けていた。この話を先にご紹介することにする。

S_p5154893

 その工作とは、以前、動作確認だけやって放置していたステッピングモーターの応用で、機械式自動巻き腕時計の自動巻き機(ややこしい)を作る工作である。

自動巻き腕時計は、使わないときの管理の方が面倒である(5/6/2012)
 所長は、いわゆる時計マニアではない。しかし、そこは機械好きのこと、随分昔になるが有名ブランドの自動巻きの腕時計をボーナスをはたいて手に入れている。以来これを愛用している。

S_p5134874

 自動巻き時計は、正確さということではクオーツの足元にも及ばないが、電池切れの心配を全くしないで良いし、機械だけでこれだけの精度(日差数秒)を保つ堅固な精密品を持っているという満足感が心を豊かにしてくれる。

 ところが、最近は腕時計でありながら電波時計で、しかもソーラー電池で電池交換不要という正確で全くメンテナンスフリーの時計が、ずいぶん安くなってきた。GPSを受信して世界中で時差の調整不要な最新式の時計にも食指は動くが、スポーツ用の安物のクォーツ腕時計が壊れたのを機に、物欲を押さえることができなくなり、セイコーの電波ソーラー腕時計を衝動買いしてしまった。

 買ってみて軽くて具合が良いので、仕事にもつけて歩こうとしたが、心配なのは自動巻きの腕時計の方である。機械式の自動巻き腕時計は、毎日、腕に巻いていないと、2日ほどで止まってしまう。長時間時計を止めておくことは、時計にとって良いことではないし、使うときには、竜頭を起こして時刻合わせをしなければならず、これを続ければ防水性も損なう。

 世間にはこういうときのために、はずした腕時計をぐるぐる機械でまわして自動的にネジを巻いてくれる自動巻き機というのが用意されている。時計マニアの中には、ここに3つも4つも腕時計を入れて管理しているのをみかける。一方向だけ廻るのでなく、休みをとりながら回転方向を変える。こった機械になると、手の動きのようにスイングして巻くものもある。

 値段も中華製なら¥3000くらいからあり、そう高いものではない。でもカタログをウェブで見ているうちに思いついた。そうだ、何も買うことはない。当研究所には、モーターがごろごろしているではないか。これを利用しない手はない。

 腕時計をぐるぐるまわすだけの機械である。こんなものは電子工作ではないと叱られそうだ。確かに、ただ回すだけなら面白みがないが、一定期間まわしたあと休みをとりまた動かすという操作は、マイコンにとっておあつらえ向きの仕事である。既製品と違ってどんな回し方にもできる。自作の強みだ。

S_p5114871

 当研究所にとっては、マイコンのソフトやモータードライバーの部分はともかく(あとでいくらでも変えられる)、機械部分をどう作るかが一番の課題である。色々考えた末、千石のロボット部品館で、ステッピングモーターのシャフトに部品をつけるジョイント(継ぎ手とでも呼ぶのか)を買ってきた。

 手持ちのステッピングモーターの速さとトルクから、減速する必要はなく直結で十分だという判断である。ただ、このジョイント、先が6ミリネジで、もう一方がシャフトを入れるハウジングがあるだけのものだが¥500もする。モーターの半分の価格である。ロボット用部品はどうも高すぎる。

 シャフトの太さをあらかじめ測って、内径6.0ミリのジョイントを買って帰ったきたのだが微妙に入らない。スペックを見ると、このモーター(ST-42BYG0506H)のシャフト径は、なんと6.2ミリであった。

 どちらかを削らなければ入らない。シャフトを削るのはモーターを傷めそうなので、ジョイントの内側を削ることにする。しかし、めくら穴をやすりで削るのは容易ではない。そのうちルーターの小さい丸砥石で削ることを思いついた。早速やってみる。うむ、手でやっているよりはかどる。少しづつ削って、何とか全部入るようになった。

 時計を入れるケースは、このあいだハンズから買ってある。腕時計をまいた形でクッションをかませて入る大きさのアクリル円筒、要するにコップである。円筒の真ん中に穴を開ける。3ミリの下穴から慎重に開けたつもりだが、やっぱり、ヒビが入ってしまう。まあ¥190の部品だ、試作ということで許してもらおう。

 ブレッドボードに残してあったステッピングモーターのFETドライバーで早速まわしてみる。うむ、回転を遅くすると、モーターはうなりが大きくなるが、予想通り、この程度の負荷は全く問題なく力強く廻る。あとは、この組み立てである。ただ、音がゴーゴーと騒がしい。

アクリル曲げ器の最初の実用品(5/10/2012)

 すんさん掲示板のばんとさんの記事に刺激されて自作したアクリル曲げ器で始めて実用品を作る機会が訪れた。自動巻き機のフレームをアクリル板を曲げて作る。手持ちの厚さ2ミリと3 ミリのアクリル板を検討して、3ミリの方を選ぶ。2ミリの方が工作しやすいが、振動が心配だ。

S_p5114868_2

 形は単純で、50度ほどの角度で板を曲げるだけである。斜め方向にモーターをセットし、円筒を傾けながら回す。ただ、3ミリのアクリル板がうまく綺麗に曲がるかが問題だ。板を曲げる前にモーターの取り付け穴を定規で測ってアクリル板の養生紙の上に描く。

この前買ったドリルスタンドで、直径22ミリのステッピングモーターの出っ張り部を3ミリドリルを連続的にあけて切り出す。アクリル板でも厚さ3ミリ程度になると、ちょっと緊張するが順調に22ミリ径の内側に失敗もなく連続穴が開いた。切り取った後をやすりで整形する。

 4隅の取り付け孔は、ひび割れを心配してセンターポンチを使うのをさぼったため、正確に開けられなかった。丸やすりで調整する。まあ、ここはネジで隠れるので、あまり神経質になる必要はない。とりあえず組み立ててみる。よーし、全部ネジ穴が揃った。

S_p5114867

 モーターの取り付け孔の工作はうまくいった。モーターをアクリル板から取り外し、いよいよアクリルを曲げる工程に入る。久しぶりにアクリル曲げ器に電源を入れ、温度を230℃に設定する。順調に7セグLEDの温度が230℃に上がり、±10℃で安定する。外部はこれで150℃近辺になるはずだ。

 慎重にアクリル板の目印に引いた線に曲げ器のパイプを当てる。アクリル板が3ミリと相当厚いので本当はいけないのかもしれないが(曲げたところが一直線にならない)、不安なので両側をあてて加熱した。暫くするとユリゲラーのスプーン曲げのように、アクリル板は、突然、柔らかく曲がり始める。

 アクリル板はあっけなく90度以上簡単に曲がり、予定したフレームが完成した。早速モーターを取り付けなおし、円筒をシャフトにつけて試運転する。モーター音が大きく、振動するのでアクリル板の底部には何かの滑り止めが必要かもしれない。マイコン基板は、台の上にセットすれば良いだろう。

 暫く、ブレッドボードのモータードライバーで時計を回してテストする。このモータードライバーはUARTで正転・逆転や速度の制御が出来るので、PCキーボードで指示しながら曲げ器の運転をシミュレートする。30分も回せば、一日、時計は止まらないことがわかった。ただ、音がうるさい。ステッピングモーターには、色々な制御方法があるが、音が静かになるというマイクロステップ制御を試したくなってきた。

マイクロステップ制御はお手本が少ない(5/12/2012)

 正転、逆転、休止などのモーターの運転制御は、マイコンなので、どんな複雑な動きにも対応できる。運転プログラムをどういう形で作るか、あれこれ考える。EEPROMに基本スケジュールをあらかじめ作ってしまっておき、UARTでその修正をするというのが、一番素直なようだ。

S_p5134875 それより、マイクロステップ制御である。今ブレッドボードにあるマイコンは、ATTiny2313だが、8ピンAVRを使ってみたい気もする。ただ、マイクロステップ制御はPWMなので8ピンAVRがどれくらいPWMチャネルを持っているか調べてみた。

 マイクロステップ制御は、4チャンネルのPWMが必要だ。残念ながら、手持ちの最安価のTiny13は、PWM出力を2つしか取り出せず、Tiny45以上が必要のようである。Tiny85ならDigiKeyで買ってある。

  ウェブを漁るが、ステッピングモーターを静音で動かせるマイクロステップ制御については意外にも資料が少ない。前のPID制御のときと同じだ。理論的な話や基礎的な話は、いくらでもあるが、では実際にどういうクロックで、どんな波形でやるのが良いのか参考になるサンプルが極めて少ない。

 特許のページがいやに目に付く。このへんの工夫やしかけはソフトと違って特許で守れるので、それで具体的な話が少ないのだろうか。大体この秋月で買った¥1000のモーター(ST-42BYG0506H)でPWMのマイクロステップができるかどうかもわからない。

 最初、3角波で良いかと思ったが、正弦波が良さそうだという話もあり、別のサイトでは台形波を勧めている。 ハードは揃ったが、ソフトの準備が思いのほか手間取りそうだ。まあ、このあたりは電子工作でも、一番楽しいところだ。存分に悩んでみよう。

グラフィック気圧計の完成近づく(5/11/2012)

 STM32のソフト開発の方である。このあいだTFT液晶で枠線を引くことが出来て、最後の仕上げ、グラフ描画のソフト開発の段階まで来た。

S_p5104866

 日付線や、時刻の表示など補助的なグラフィックは、ダイナミック表示(グラフが時間とともに移動していく)のため、とても面倒だったが、これは擬似コードをかなり周到にやって見通しがついた。あとはこれをC言語ソースに替えれば良いだけになっている。

 擬似コーディングから実際のCコードに落とす作業は、擬似コードのレベルにもよるが、単純作業に近くなるので進捗は早い。オリジナルのプログラムを大幅に変えて本来のグラフ描画に絞った関数を残し、FatFS関係を削除する。こちらのほうが大変である。

 FatFS関係だけ削れば良いと思っていたら、グラフィックのファイラー部分は、FatFSの関数を呼ぶところが各所に散在し、いたるところをコメントアウトしていかねばならない。画面描画の部分も残っているので、全部なくすわけにもいかないのだ。

 それに、あまりフラッシュが小さくならない。どうしてだろう。フォントファイルが大きいためなのか。日本語フォントは今のところ使うつもりがないが全部消してしまうとあとから復活させるのが大変なので残しておきたい。それにこの部分だけの削除はもっと大ごとだ。

 なんとか整形して、テストを始める。うーむ、動かなくなった。グラフは一部出ているので、どこか途中で暴走している。テストステートメントを挟んで、慎重に暴走地点を探す。ふむふむ、EEPROMから気圧データを読み出すところでハングしている。

 EEPROMに蓄積する日付と気圧データは、視認性を高めるためと、今後のデータの編集を考慮して、キャラクターになっている。グラフ描画のときは、このキャラクターデータをバイナリーに戻す作業にChaNさんのxatoiを使わせてもらっている。これがどうもうまく動かず暴走しているようだ。

 この関数は強力だが、アドレス、ポインターを多用しているためちょっとでも間違えると、一瞬にしてハングアップしたりリセットしたりする気難しい関数だ。いつもは威力を発揮するprintfデバッグだが、STM32のUART出力はバッファーを使っているらしく、こういうポインター間違いで一気に暴走するバグには無力である。結果をUARTに出す前にハングアップしてしまう。

 いくら調べても原因を究明できない。そのうちじれてきて早く結果が見たいので、xatoiを使わず、自前のルーチンでキャラクタからバイナリに戻すステップを急遽追加する。20桁近い文字の変換だが、この際きれいごとは言ってはいられない。

S_p5134873

気圧計が動いた。やっぱり文字が小さすぎるな(5/14/2012)
 この改修で、やっと、プログラムは正常に気圧を出すところまで進んだ(10分間隔)。画面の下に、赤い気圧点が見える。うーむ、このTFTの赤は暗いのでこれでは見難い。1ピクセルではなく、2X2のレクタングルにしてやる。うはあ、画面が赤線だらけになった。画面関数の引数を間違えたようだ。

 利用させてもらって文句を言うのは気まずいのだが、この描画関数群は、引数の座標の順番が微妙に少しづつ違っているので用心しないといけない。XとYが逆になっている関数もある。今度の関数の引数は、XYの順番にはなっているが、X1,Y1  X2,Y2ではなく、X1,X2 Y1,Y2だった。

 指定どおりに引数を直して、無事、少し濃い赤点がでた。暫く放置してグラフになっていることを確かめる。よーし、これでグラフィック気圧計は正常に動き始めた。いやあ、それにしても時間がかかったな。ほぼ4ヶ月かかった。グラフ全体が時間とともに動くという仕掛けが、ソフト開発では特に手間どった。

 半日ほど動かして、グラフの横軸(気圧)のスケーリングが大きすぎて、殆ど気圧の変化が見えないことがわかった。大幅にスケーリングを見直す。最初は、950hPaから、1150hPaという、MPL115気圧センサーの測定可能範囲にしていたが、これを980から1030という狭い範囲にする。

S_p5144889

 これで、やっと気圧の変化がはっきりするようになった。すんさんの気圧計のグラフの範囲も、970と1030になっていた。何だ、始めからこれを参考にすれば良かったのだ。へそ曲がりで人のものを参考にしたがらない性格がこういうときに損をする。

 水色で枠をつけてグラフが引き締まり、気圧計らしくなった。下側に、細かく目盛りをつけたりして悦にいる。ただ、時刻と気圧を表示する文字がやっぱり小さすぎる。それに天気予報の機能はまだ何も考えていない。

 今後の計画は、まだ具体的には決めていない。天気の予報をしなくても、グラフの気圧変化を見ているだけで、この先の天気が雨模様になるのか、回復するのかは大体のことがわかる。あらためて数値解析をして予報を出す必要があるか悩ましいところだ。ま、これも暫く悩んでみることにしよう。

 ソースコードの公開は、このブログの容量制限(1MB)を越えるため、今のところ出来ません。いずれ、別のサイトからでも引けるようにしようと考えております。もし、ロジックだけでも知りたいという方がおられれば、このサイトに部分的に置くことにします。コメントをお寄せください。

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

2012年5月 3日 (木)

グラフィック気圧計ソフト開発の合間に道草

 STM32によるグラフィック気圧計は、いよいよ画面に気圧の遷移を折れ線グラフで表示するメインロジックの開発に移った。今年の1月から始まったこのプロジェクトは、まずAitendoの生基板にSTM32F107を実装することから始まり、2.4インチTFT液晶の組み込み、気圧センサーMPL115A2の実装とデータ取り込み、さらに気圧の時系列データを保存するEEPROM(24FC256)の組み込みとそのドライバーの開発まで進んだ。

 最近は電子工作のモチベーションが、夢中になってやっていた頃に較べると明らかに下がっている。いわゆるスランプである。体の奥底から突き上げるような、「作りたい!」という衝動が生まれない。ただ全く興味を失ったわけでもない。考え出すと、あれもやりたい、これもやりたいと迷うことが多くて実際に手が動く(ハンダ付けや、コーディング)ところまでなかなか行かないだけである。

 亀のような歩みだが、それでも、やっと全体を動かすメインプログラムの開発が始められる段階まできた。さあ、一気呵成にと思った途端、別のやりたい工作が入ったりして相変わらず、がた老AVR研究所は道草の連続である。見通しの悪い話の展開で読みにくいとは思うが、まあ、アマチュアの気ままな開発日誌ということで我慢してお読みいただきたい。

TFT液晶でDOS端末のような文字スクロール画面を作る(4/17/2012)

 これまでテストベンチにしていた、ねむいさんのFatFSファイラーのソースコードを基本にEclipseの新しいプロジェクトを起こし、いよいよ気圧計本体のソフト開発に着手する。 残っていたThomas氏のルーチンは削除して構造をすっきりさせる。サイズは200KBに減ったが(10KBばかり節約)、びっくりするほどは減らない。

 もっと減らすには、気圧計では使わないFatFSとファイラーを消せば良いのだが、これからグラフのコードを作るときに、グラフィック機能の確認のために残しておきたい。コンパイルに時間がかかってしまうが、あえて残したままにする。

ソフトの仕様を詰め始めた。例の擬似コーディングである。測定途中でパラメーターを変えたりしないで良いのなら制御構造は、とても単純だ。10分に一回、EEPROMにデータを蓄積して、2日分のグラフを描き直すことをひたすら続けるだけである。予報は、このときに過去のデータをもとに更新する。

 ただ、グラフを現在時刻を起点に過去2日分をダイナミックに表示していくしかけは、結構厄介である。 オブジェクト指向的に実現すべき機能とデータ構造をまとめてソフトを構造的に分割できるようにする。だいぶん骨格ができてきた。

S_p4144825 文字の大きさが問題だ。この間大きくしたファイラーの10ポイントの文字は、グラフの中の目盛り数字には良いが、現在の気圧値や時刻を遠くから見えるようにするには、まだ小さすぎる。といって、12ポイント以上はフラッシュが小さすぎて(実装したSTM32F107は256KB)、入らないだろう。まあ、漢字を使わないで英数字だけでも入れたほうが良いかもしれない。

 そんなこともあって、グラフィック機能の勉強のため、今動いているファイラーで、DOS画面のようにテキストが表示されるよう、ソースに手を加えてみた。しかし、思ったようにうまく動かない。ソースの一文字出力関数にはスクロールの機能が組み込まれているのに、文字の表示が最終行まで来ると重複して表示されるだけである。画面全体が上にスクロールしていかない。

 調べたところでは、スクロール関数の縦横の指定がどうも逆さまになっているような感じだ。ねむいさんは、最近、このファイラーに、ファイルのテキストを表示するブラウズ機能を追加された。ソースも公開されている。恐らく、ここの部分は直っているのだろうけれど、少し意地になってそれを見ないで修正することにする。自分の推理が正しいことは自分の手で確かめたい。

 X軸とY軸を逆さまにすると画面は見事スクロールするようになった。自分の推測があたって気分が良い。ただ、2バイト文字の漢字は、スクロールした時両端が残ってしまう、それに最終行にはゴミが残る。ただ、スクロールは今度の気圧計では使わないので急いで直す必要は無い。

 でも、気になるのでもう少し調べてみた。要するに、全角文字の表示のために画面の両端は、半角サイズあけて文字を表示しているのだが、スクロールの際に両端の全角のフォントの半分が次の半角文字表示では更新されないので、そこが残ってゴミになる(次の行も全角なら塗りつぶされOK)。

 2バイト文字が使っていたエリアをスクロールしたあと、空白の全角文字1字を書き込めば、良いはずなのだがこれがうまくいかない。このあとの行全体の文字すべてが化けてしまう。こうなると意地になるのがいつもの癖である。別の画面関数(Display_FillRect_If)を使って、この部分をレクタングルで消してしまうようにした。

S_p4144826 これで、ゴミは消えて漢字も出た。しかし、半角英数字は問題なくても、一部の漢字がスクロールで化ける(すべてではないのが不思議)。 黒の1文字分のレクタングルを両端に描いているだけなのだが、どうも漢字コードの表示ルーチンと何らかの関連があるらしい。

 奥が深そうなのでこれ以上の深追いはやめた。今回のグラフではスクロールは使わない。ただでさえ遅れているプロジェクトをこれ以上迷走させるのはやめよう。潔く諦めて先に進めることにする。

直線を引くことに成功(4/19/2012)
 グラフ表示に必要な機能をさらに詳しく調べる。画面操作関数(ファイラーts.cの下部関数群のソースファイルdisplay_if_support.c)を調べて行って、実際のグラフ表示に必要な機能(点、直線、領域の描画)は、すべて関数が既に開発済みでそれを利用すれば良いだけであることがわかった。これは楽だ。ただ、スクロールがうまく行かなかったように、文字関数との関連が、いまひとつわからないので不安は残る。まあ、しかしこれはやってみるしかない。S_p4274855

 試しに、画面に直線を描く関数(Display_DrawLine_If)を使って、縦、横の直線を引いてみる。これは、あっけなく引けた。今回は使わないが斜め線もOKである。これは有難い。難しいことを考えない限り、気圧のグラフは思ったより簡単に引けそうである。

 調子に乗って、JPEGを横位置に表示するテストもやってみた。オリジナルはTFTの画面を縦位置で使っているので、スケールファクターが大きくなり、折角の画像が小さくしか見えない。これを横位置にすれば、画像が大きくなるはずだ。

 ChaNさんのTinyJPEGが使われている。描画はIJGと同じように、1ラインづつ24ビットRGBデータを出力し、これを繰り返している。この細いレクタングルの座標を変えるだけで画の方向が変わるはずだ。

 ソースの解析を進めて1ライン表示のレクタングルに出力しているところを突き止め、この縦横を逆にしてみた。おおお、倍のサイズのJPEG画像が出た。しかし、画像を良く見ると1ラインずつわずかだが画像がずれており元の画像になっていない。

S_p5034856 これも今回のプロジェクトとは関係ない。もうこのあたりで止めよう。どうも今回は、余計なところに目が移ってなかなか先に進まない。詳細な画面仕様を作り始める。作ってみると枠線とか目盛り線など本来のグラフと関係ないところの描画が結構面倒なことがわかる。特に日付線が動いていくところをどうスマートに描画していくか頭を悩ませる。小道具の方が手間がかかる。

激安テスターの通信機能追加に道草(4/20/2012)
 そうこうするうちに、すんさんの掲示板で耳寄りな話を聞いて、プロジェクトは大きく脱線してしまった。shuji009さんが上げたテスターのトピックで、きぃたんさんが秋月の激安¥1000テスター、P-10にRS232C通信機能がついていることを教えてくれたのである。

 ウェブで探してみると、あったあった。少なくとも2つのサイト(ここここ)で、それを実際に試して動かしている。しかも、PCのテスターのロガー(フリーソフトのTs Digital MultiMeter Viewer)にも接続できるらしいのだ。あろうことか、現在、愛用中の秋月のP16(6000カウント)のマルチメーターにも、このRS232C機能がついているらしい。

 くわしくは、これらのページを見てもらえばわかるが、要するに、ICチップが元々持っていてコストの関係で省略されたデータ送信機能がちょっとした工作で、使えるようになるということである。

 以前から、測定結果のログをとりたくて、シリアルでデータを取り出せるテスターを物色していた。電池の充放電や、DC-DCコンバーターの長期テストなど、電圧などの長期間の推移は、これまで方眼紙に、手でプロットしていたが、そろそろ効率的に行いたい。

 ロガーそのものの自作も考えたが、アナログ部の制作と較正が面倒で、今ひとつ、作るところまでは行かなかった。既存のテスターからデータが取り出せれば、ロガーの部分だけ自作すれば良いので、都合が良い。

 しかし、通信機能のあるテスターは秋月にもたくさんあるが、値段はともかく、みな大きくて取り回しが面倒である。秋月もの以外の国産や著名な欧米製品(Flukeなど)も調べてみたが、通信機能のあるクラスは、みな結構な値段のうえ、ごつくて自分の好みに合わなかった。

 そこへ、この情報である。電子工作をするための測定器を電子工作してどうするのだという声もあるが、なにしろ¥1000の値段には勝てない。もし、不幸にして壊しても精神的打撃はわずかである。しかもPCにはフリーソフトのロガーまで用意されている。ロガーを作る必要も無い。掲示板でこれを知った翌日、仕事の帰りに、早速手に入れてきた。

フォトカプラーに簡単にデータが出力された(4/21/2012)

 ウェブには写真つきの改造手法が出ているので、作業に迷いがない。問題は、ピンから引き出したワイヤーをどう始末してRS232Cまでつなぐかである。ウェブには直結してRS232Cを引き出している改造例もあるがS_p4194827、ここは測定器なので絶縁して引き出したいところだ。

 しかもデータシートの参照回路は、フォトカプラー出しの形が用意されている。これを利用しない手はない。フォトカプラーは手持ちが沢山ある。2400bpsということなので、汎用品(PC817Cなど)で十分なはずだ。在庫整理にもなる。

S_p4204837 ただ、基板とケースを介して、どう実装するかが問題だ。考えた結果が、前にもやった、基板にピンヘッダーを瞬間接着剤で固定し、そのあと、普通の撚り線で配線する方法である。これなら保守性も高いし、見栄えも良い。

 カプトンテープで基板表面を保護してから(SparkFunのときのようなリークの心配をしたくない)、接着剤で3ピンのヘッダーを固定する。よーし、少々力をいれても取れないくらいの強度になった。

 グランドをどこから出すか、ウェブサイトの方法はまちまちで迷った。ピエゾスピーカーがグランドだというが、テスターでどれだけ調べてもつながっていない。参照回路はグランドだが、このP-10ではそうなってはいないようだ。

 しかたがないので、手当たり次第にグランドと導通するポイントをテスターで探し回り、基板の近くに適当なところを見つけて配線した。チップのピン(0.65ミリピッチ)へのハンダ付けは、これまでの経験がものをいって、あっけなく上手くいった。経験はつむものである。

S_p4264852  ケースの工作も進める。まず、前のP16でもやった、直付けになっている測定プローブのコネクター付けから始める。この工作は、数年前やって、とあるサイトに紹介され、当ブログのアクセス数の増加に寄与している。

 久しぶりにミニルーターをドリルスタンドにつけて穴あけ工作をする。穴は簡単にあいたが、ピンを止める段になって、ネジ止めポストと干渉することがわかり、周辺を削るのに手間取る。ピンの外だしは、ケースの一部を削って窓を作る。コッピングソー(糸鋸)が欲しいところだ。

 フォトカプラーの部分を、ブレッドボードに仮組みし、いよいよ、テスト。いくら¥1000の投資とはいえ、電源ONはいつものように緊張する。スイッチを入れる。あれえ、RS232Cの表示が出ない。ちゃんとグランドに落としたのになぜだ。

S_p4204832 配線図をたしかめる。うーむ、このテスターには2種類グランドがあって、使い分けている。何々?さっき見つけたグランドはAGNDだ。いかん、AGNDは、Vccの1/2の電圧のでている中間値のグランドだ。

 これをデジタルグランド(電池マイナス側)にして、めでたくLCDのRS232表示が出た。フォトカプラー代わりにしたブレッドボードのLEDが点滅し始めた。よーし良いぞ。とるものもとりあえずオシロに電源を入れて波形を観測する。出た出た。ちゃんとしたUART波形だ。

 フォトカプラーの配線で、また悩む。参照回路は、単にグランドと送信ライン(TXD)の間にフォトカプラーの出力S_p4204829を抵抗をはさんでつないでいるだけである。しかも回路図は、出力側もダイオードの形をした部品で、どうもフォトカプラーではないみたいだ。

 いろいろウェブを探し回る。こんな接続は見たことがない。フォトカプラーの出力はたいていがオープンコレクターで、これを動かすには電源がいる(フォトカプラーそのものが電源を要求するのもある)。

 この電源を本体のテスターからとることは出来ない。何のための絶縁かということになる。USBにするとVBUSが来るが、この程度の出力に、USBアダプターをつけるのも何か抵抗がある。

 しつこく、「RS232C フォトカプラ-」でウェブを探し回った。あるページで、出力側をTxだけでなく別のピンに配線している回路を見つけた。あっ、そうだ、RS232Cにはホスト側から色々な制御信号が来る。これを電源に使うんだ。これは頭が良い。感心した。

 早速、これを真似る。DTRを使う。これはホスト(PC)から端末(モデムなど)に、装置が使用可能になったことを教える制御線で、OKが+15V、NGが-15Vである。念のため、今のPCのCOM1で確かめる。確かに、電源を入れると、-15Vに下がり、ターミナルプログラムを立ち上げると見事+15Vに上がった。

P10_logiana 逆の-15Vが心配なので、ダイオードをかませ、ブレッドボードで実験する。出た出た、TeraTermから、次々に送信データが表示される。ロジアナをつないで中のデータを確認する。よーし、データシートどおりの14バイトの測定データが順調にUART出力されている。

データフォーマットが違うので、PCのロガーに出せない(4/24/2012)
 ここまでは順調だった。しかし、このIC(FS9711_LP3)のRS232Cは、フリーソフトのTs Digital MultimeterViewerがサポートするテスターに入っていないことがわかった。 ウェブでWENS20Tと互換というのは、最近のP10のバージョンでは、変わっているようだ。動かしてみると、一番それらしい挙動はするが、正しくは動かない。

 14バイトコードのフォーマットはデータシートに完全に出ているので、あとは単なる力仕事だ。ただ、ややこしい。数値データはすべて7セグLEDのエレメントなので、翻訳してやる必要がある。これは、WENS20Tも同じなのだが、測定レンジや、V、Aなどの表示単位コードが、かなり違う。mAとかkΩなどは、合成しないといけない。そんなことでPCのロガーはうまく動かない。

P10_data 選択肢としては、Tiny2313あたりで変換して、もういちどUARTでPCに流すか、いっそのことマイコンの方でLCDとSDカードでロガーを自作してしまうかである。とにかく、すぐ出来る話ではない、とりあえずはブレッドボード上の回路を、P-10に組み込んでけりをつけることにした。

 RS232Cコネクターをつけるには、P-10は小さすぎる。そのうちBeagleBoardのとき作ったRS232Cケーブルを思い出した。10ピンのコネクターでBeagleBoardにつながっている。
これだ、これだ。小さな基板を切り出し、そこへフォトカプラーと10ピンソケットを実装することにする。S_p4264841

 P-10へは接続コードを収容する空間を使ってアクリル小片で押し込むようにする。うまくできた。これで一応ハードの工作はおしまい。コードの解析は一時おあずけである。

 気になっていることがある。フォトカプラーのRS232出力は、本来のRS232C仕様(±15V)ではない。TeraTermは、問題なく文字を出力し、Ts_ Digital MultimeterViewerも、データ入力まではしているようなので動いていることは動いているが、信号Lがマイナスになっていない。これをマイナスにするには、フォトカプラーのオープンコレクターの部分のグランドをマイナスにしS_p4264843てやる必要がある。

 これは、ChaNさんのサイトであっさり解決した。最近のRS232CのLowとHighの閾値(スレッシュホールド)は、マイナスではなく大抵の機器は、+1~+1.5Vなのだそうだ。そういえば以前、ChaNさんの簡易RS232Cを作ったときも、マイナス電圧は使っていなかった。

擬似コーディングに恰好の課題をみつけた(4/26/2012)
当ブログのホーム、ココログは、何処からブログに飛んできたかを調べることができる。このあいだ見ていたら、嬉しいことにこのリストから当ブログを紹介してくださる擬似コーディングのページが見つかった。

「擬似コーディング」でGoogleしても、このページは上位に登場する。ソフトウエアを職業とする方のようだ。自分の考えに共感してくれる人が少しでもいるということは生きている喜びのひとつである。素直に喜ぶことにする。ご紹介ありがとうございました。

 ただ、ウェブを見ていると、色々誤解があるようだ。「どうやって書くの?文法は?」というのが多い。何のために擬似コーディングするのかを考えれば、こういう発想にならないと思うのだが、どうも日本人は形式にこだわりすぎる。

 擬似コーディングはあくまでも論理思考(ロジック)をまとめるものであって、コードそのものに意味があるわけではない。どんな書き方でも良いわけである。書いたことによって頭の中が整理され見通しの良いソースコードを完成させることが本来の目的である。

 そういうわけでもないが、もう少し擬似コーディングにこだわってみた。このあいだは擬似コーディングの講釈ばかりで、実例は失敗例という恥ずかしい結果に終わったので、汚名返上の題材を探していたが、恰好の例をみつけた。気圧計のグラフをEEPROMのデータから描画するルーチン(オブジェクト)である。

 要求される機能は、EEPROMに入っている気圧と時刻データを最初から読んで、現在より2日前に遡って気圧推移をグラフに描くことである。入力は、現在時刻と気圧のEEPROMストリームデータ、出力はTFT液晶の気圧値プロットを打つXY座標である。

 描画するべき時間帯のレコードがおあつらえ向きに連続してきれいに並んでいるわけではない。電源を切ったり、過去のデータが残っていたりして歯抜けになっていることも予想される。読んでみたらデータがないということも有りうる。

 どんなときにでも、グラフが(歯抜けでも)所定の範囲(現在時刻から2日間)に描くにはどうしたらよいか。EEPROMに全くデータがないときでも暴走しない頑丈(Robustness)な構造が望ましい。

 EEPROMのデータは可読性を高めるため、実際の年月日、時分秒で保存されている。実際の処理は、すべて、ある時刻からの総経過分で計算する。

 何回も、擬似コードをメモ上に書き散らし、ロジックを検討した。最初は、描画の順番を重視して、複雑な処理を考えていたが、ある時突然、気圧値のプロットはランダムに打っても問題ないことに気付き、一気にプログラムは単純になった。S_p5034859

 定石どおりEEPROMのデータを最初から読み始め、レコードに入っている総経過分に応じて所定のY座標を計算し、2日間の範囲の時だけ、プロットすることでEEPROMを最後まで読みきれば、それで良いのだ。

 擬似コードは、文法にこだわらず、自由な発想でロジックを考えることが出来るため、ロジックの整理に大きな力を発揮する。これが実際の計算機言語でロジックを作っていると、それに縛られてなかなか飛躍した発想ができない。擬似コーディングのおかげで、すっきりした形のロジックになった。

グラフを描くのにこんなに手間がかかるとは(4/30/2012)
 描画ロジックに見通しがついたので、すぐ完成すると思っていたが、そうは問屋が卸さなかった。年月日時分から、ある時刻を起点とした、総経過分(プロットは10分単位)を出したり、ある年月日から何日か前の日付を求めたりすることが、こんなに大変とはやってみるまでわからなかった。

 自力で考えることはすぐ諦め、ウェブを探索する。いやありがたい。色々な方法で日付を求めるサンプルコーディングを即座にたくさんみつけることが出来た。そう、最初にとりいれたこの方法などは、テーブルを使わずに特定の年月日を、経過日数に見事に変換してくれる。

 ところが、グラフに日付線などの補助線を引く段になって、この方法では、ある年月日から1日前、2日前の日付を求めることができないことがわかった。結局、月の日数テーブルを使った普通のやり方に戻った。

 気圧の推移をEEPROMから1レコードづつ読み出して、2日間のデータをプロットさせることは、先ほどの擬似コードの通りそう難しくない。それより、グラフを見やすくするための補助的な日付線や日付の表示を描画するロジックの方が難しいというのも皮肉なものである。

 擬似コードのロジックがだいぶ溜まり、グラフの詳細な仕様もメモに書きとめて、これでグラフを描く準備が整った。あとはこれをCソースに書き直す作業が待っている。このあたりでブログに報告しておこう。

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

より以前の記事一覧