« 2014年11月 | トップページ | 2015年1月 »

2014年12月の2件の記事

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年11月 | トップページ | 2015年1月 »