« 2012年1月15日 - 2012年1月21日 | トップページ | 2012年2月19日 - 2012年2月25日 »

2012年1月29日 - 2012年2月4日の1件の記事

2012年2月 4日 (土)

STM32F107でやっとUSB仮想端末が動いた

 前回の記事以来、もう20日近くが経ってしまった。何故か2012年の電子工作は遅々として進まない。特に他の事で忙しいというわけでもない。ただ、どういうわけか意欲が湧いてこないのだ。とりとめもないことばかりに時間が過ぎて気分が乗らない。いわゆるスランプというやつだ。

 まあ、こういうときもある。人生にはまだまだ時間がある(そうゆっくりもしていられないが)、たいした成果も上がっていないけれど備忘録を兼ねてこの間の経過報告をしておくことにする。

S_p1314614

やっとDFUが動いてプログラムが書けた(1/16/2012)
 生基板からのSTM32プロセッサー基板がやっとのことで動いて、プロジェクトは次のステップ、ファームの開発に移った。統合環境Eclipseを立ち上げる。EclipseでのSTM32のソフト開発は、フォトフレーム以来ほぼ1年ぶりだ。

 半年前にはFreeRTOSをやっていたが、同じARMでも石はNXPのLPC2388で微妙に環境が違う。情けないことにEclipseはともかく、STM32のプログラミング環境などは見事にみーんな忘れていた。

 リハビリのつもりで、少しづつ以前のプロジェクトのソースコードを見ながら、ブートローダーから先の手順をゆるゆると進める。CPUは、前の騒ぎでSTM32F103に戻ってしまっている。103と107はピンコンパチで、こんどのグラフィック気圧計は、特に107でなくてもかまわない。何しろ100ピンのCPUの換装はおおごとだ。とりあえずは103のままプロジェクトを進めることにする。

 まずはCQ-STARM基板の状態にもどそうと、ブートローダーからDFUを焼くことにする。ファーム書き込みの手段は増やしておきたい。中華シリアルプログラマー、MCUISPは好調だが、いつ何時動かなくなるかわからない。STマイクロ純正のライターFlushLoaderは、103に戻したら動かなくなっている。用心に越したことはない。

Ws000000

 もう4年も前になる付録の雑誌号を引っ張り出して全体を復習する。DFUそのものは、以前ねむいさんのところから頂いたソースを使う。MCUISPは快調にプログラムを書き込んでくれるが、一向にUSBが動かない。PC側のプログラマーDFUseが基板を認めない。

 そのうち、DFUモードというのがあって、I/Oピンのひとつをグランドに落とさなければDFUにならないことに気づいた。基本的なところをすっかり忘れている。お馬鹿な話である。早速、PB9を1kΩでプルダウンする。ただ、このソースがこのピンで良いのか確認するのにえらい時間がかかった。考えてみれば、このDFUはCQ-STARM基板用なので確認する必要もなかったのだが、何しろ昔のことで周りがすっかり見えなくなっている。

 最初、動かなかったが、何度かUSBを抜き差ししたり、リセットを押しているうちに、PCのディバイスマネージャーのところにDFUのアイコンが出た。 コネクターに抵抗を差し込んでいたのが接触不良だったらしい。DFUseを立ち上げると、ちゃんとボードを認識した。

 しかし、このあとも難儀が続いた。DFUで適当なプログラム(仮想UARTモニター)をファームに書き込んだのは良いのだが、このプログラムが動かない。さっきのピンをはずしてもプログラムモードに行かないのである。

 これも、このピンをプルアップしなければならないことを忘れていた。Vccから1kΩをつないで無事、USBを通した仮想UARTモニターが動いた。やれやれ、これで一段落である。¥450のCPUボードがやっと日の目を見た。

103から107へまた換装しなければならない(1/19/2012)
 勢い込んで、ねむいさんが最近、集大成してくれた、STM32ファミリーでこのTFT液晶が動くソースコード一式をネットからダウンロードした。当初はスクラッチからTFT液晶のコマンドレベルのドライバーを書こうと意気込んでいたのだが、ウェブで上記のソースを見つけた途端、意欲が一気に失せた。

 へそ曲がりではあるが、意気地のないへたれである。折角、先人が苦労して作ったものを使わない手はない。何も無理をすることはないと勝手な理屈をつけて、ありがたくソースを頂戴する。このソースは、ChaNさんのFatFSが入っており、ファイラーにもなる。

 ハードはまだ未配線だがビルドだけでも通してみようとEclipseにソースチェーンを展開して、コンパイルの準備をする。このソースは、107用のソースなので103向けに換えてやらなければならない。MakeFileで103の環境変数を設定する。しかしmakeは何故か最初のところで門前払いである。

 ファイルではなくコマンドがないと怒っている。暫く悩んでいたが、MakeFileに新しく追加されていたシェルの置換ステートメントを訳わからずにコメントアウトしていたことがわかり、これをはずしてやっとコンパイルが進み始めた。

 いくつかのライブラリ定義漏れを修正して、これは通りそうだと思っていたら、見かけないエラーでビルドが止まった。エラーメッセージを読む。あっちゃー、フラッシュサイズオーバーだ。このTFT液晶+FatFSモデルは、要求メモリとSRAMが大きく、フラッシュ128KB、SRAMが20KBのSTM32F103VBT6では動かないことがわかった。「振り出しに戻る」というやつである。

 仕方がない。折角つけて正常に動いていた103をはずすしかない。107に移し変えなければ先に進めない。3回目のLQFPのハンダ付けはさすがにきつい。一度外した面実装のICチップは、ピンをいくら目視で揃えても、あちこちが微妙に歪んでいるので、ハンダ付けをルーペで見直すと、冷や冷やするところが続出している。

 下手にやり直すのは危険だ。前やったようにパターンごとはずす恐れがある。この基板は安いだけあって、パターンが弱い。気楽にはいじれない。それでも、どうしようか迷うところが数箇所ある。ハンダ付けは問題ないようだが、ピンと隣のパッドが近接して危ない。

 何度もルーペを換えてチェックしたが、結局そのままにすることにした。テスターでショートだけはしていないことを確認する。思い切って通電する。よーし、ブートローダーまでは通った。各ピンが本当につながっているかどうかの確認は実際にそのピンを使ってみないとわからない。とりあえずは、これで行こう。

STマイクロのUSBライブラリが大きく変わってしまった。(1/20/2012)

 103のときと同じ手順で先に進む。まずDFUのソースをSTM32F107で動くようにMakeFileを調整する。何とかビルドが通った。テストする。順調にMCUISPと、フラッシュローダーが107を認め、DFUの書き込みに成功した。DFUSeが107で動いた。ねむいさんが以前ブログで指摘していた107のブートローダーのERRATAは幸い発生しなかった。まあ、まだ何もペリフェラルをつないでいないからだろう。

 次はDFUそのものの動作確認である。103で動いたUSB仮想端末モニターのファームをロードしてみた。何の問題もなく書けた。しかし、モニターは動かない。PCでは不明なディバイスと表示されるところまで動くが、仮想UART端末としては認めないのである。

 動かない理由はすぐわかった。USBライブラリが古すぎて107では動かないのだ。2年前に開発したUSB仮想UARTモニターは、雑誌についていたSTマイクロのUSBライブラリV1を使っている。107はV1では動かない。

 それなら仮想UARTモニターのUSBライブラリを107が動くV3に換えれば良さそうなのものだが、これが難しい。STマイクロのUSBライブラリーはV1からV3で、大きく変わっている。というより、103と107では、USBそのもののハードが変わっていて(107はUSBのOTG機能が追加されている)、ユーザープログラムで使っていた関数や変数が殆ど変更されている。ライブラリを単にV3にしただけでは、次から次に未定義エラーが出る。

 こうなると意地になるのがいつもの癖である。冷静に考えれば、元々は気圧計のためにSTM32F107を動かそうとしている。そこでUSBが動こうが、動くまいが本筋とは関係ない。さっさとやめて本来の開発に戻れば良さそうなものだが、これが出来ない。

 103で快調に動いていたダブルバッファーを使った仮想UART端末が新しいチップで動かない(動かせない)というのが、しゃくなのである。変なこだわりがある。このまま放置して先に進めないのだ。まあ、このへんがアマチュアの特権である。やりたいようにやる幸せ(?)をかみしめて、こだわることにする。

 暫くEclipse上で苦闘する。未定義変数を検索して必要なドライバーを探す。Eclipseのサーチ機能は強力なので、どこで定義しているかはすぐわかる。あれえ、ちゃんと定義されているのにエラーになる。おかしいな。そのうち気がついた。ソースコードにあっても、107を選んだ時に#ifdefなどのプリプロセッサーでなくなってしまう。ひとつひとつのソースレベルまで見ないとわからない。

 半日近く、ソースをいじりまわして納得した。これはやっぱりあきらめるしかない。107には、103と違うハード(USBのOTGなど)がついているので、ライブラリの構造が大きく変わっている。今までのやり方の手直しぐらいでは動きそうもない。USB仮想UARTは道半ばだが、諦めることにする。ロードが大きすぎる。それにこれが目的ではない。

 ようやく、あきらめた頃である。何とウェブでまたも、ねむいさんの記事がヒットした。STM32F107でVCOM(USB仮想UART端末)を動かしたデモプロジェクトである。なんだ、なんだ、ちゃんと動いているソースがあるじゃないか。またまたねむいさんである。ありがたくソースをいただいた。

STM32F107の仮想UARTのソースでも泥沼(1/23/2012)

 ねむいさんのソースは、STマイクロのV3ライブラリのVCOMのデモがベースになっているようである。実はこれを探していたのだが、自分では見つけられなかった。みんなが言っているようにSTマイクロのサイトは欲しい情報が実に探しにくい構造になっている。誰のためのサイトなのだろう。

 ビルドそのものは、前に一回通しているので、Makefileの修正は楽で、順調にビルドは進んだ。MCUISPでファームを焼く。このSTマイクロのVCOMデモソースは、標準のUART1とUSB仮想UARTをつなぐブリッジ機能のデモである。USBケーブルを差し込んで電源を入れる。良いぞ、PCが107のUSB仮想UARTを認めた。これで一歩前進だ。

 次に、PCのシリアル端末ソフト(Teraterm)で、通常のCOM1のシリアルコンソールも立ち上げる。2枚のシリアル端末を前にしてキーボードを叩く。しかし、どちらから打ってもデータは行き来しない。

 うーむ、ビットレートが合っていないのか。ソースコードの通りUSB-UARTを11520bpsパリティ無し、ストップビット1、COM1を9600bps、奇数パリティ、などとするが、うんともすんとも言わない。

 こちらの目的はCOM1とつなぐためではなく、前やったように単にUSBの仮想UARTを動かしたいだけである。不確定要素のあるハードのCOM1のUARTの方は余計だ。コードを削って、前にやったような仮想UARTモニターにしようとソースをいじり始めた。

 しかし、このVCOMのソースコードは何かおかしい。特に、USBのエンドポイント周りのコーディングは、同じような処理が複数あって混乱する。新しく加わった新機種(STM32F107クラス)のために#ifのプリプロセッサーで分けて機種ごとにコードを追加しているので余計読みにくい。ソースコードが年を経て劣化するというやつである。安易な#ifの使用は、あとが大変で、こんなコードを書いていると、書いた本人でもこの先メンテナンス不能になるのではないかと心配になる。

 それにしても、UARTとUSBのバッファーの間のデータ移動ロジックは稚拙としか言いようがない。受信したUARTデータのサイズとUSBのパケットサイズを比較しながら無理やりデータを移している。まるで素人が書いたようなプログラムである。

 要するに目の前のデータの形に気を取られて、本質がわかっていない。こういうときは、ストリームの概念を持てばプログラムは非常に簡単になるはずで、少し大きめのリングバッファーかFIFOに一旦データを移して、そこからUSBのエンドポイントのパケットサイズ分を採っていけば良い。

 それにしても、ひどいコーディングだなあと思っていたら、違う視点でこのコードの不安について書いているサイトを見つけた。

全く同感である。USBの割り込みが2箇所あって、排他処理しているのは良いが、全く同じような処理が重複している。バッファーの終端処理が考えられていない。このページの通り、バッファーを使っているのに、リングバッファーとして使わず、2048バイトという大量の容量にして、その管理をサボっている。

 そもそも、オリジナルのソースでは、UARTの速度が9600bps、USBが115200bpsなのに、USBからのデータは受け取るばかりで、ソースには何らかのフロー制御をしている形跡がない。フロー制御をしなければバッファーをどんなに大きく(2KB以上)とっていても、持続して送受信を続けることは出来ない。

 こんなソースを書いてはいけないという見本のようなものだが、悪態をついたところで正しい修正が行えるわけではない。黙々と、少しづつ直していくしかない。しかし、スランプなので、集中してデバッグする気力がなかなか生まれない。

やっとのことでVCOMが動いた。しかし不安定(1/28/2011)
 やれやれ、やっとSTM32F107の仮想UARTが動いた。しっかし、えらい時間がかかった。やっぱり、ヤキが廻ったとしか言いようがない。モチベーションが低い時に作業を無理に進めると、こういうものである。

 USB仮想端末は、実行のたびにUSBケーブルを抜き差ししないと動かないことを思い出し、動き始めた(最初から動いていた)のは良いが、どうしても文字化けが解決しない。1文字のエコーバック程度なら問題ないが、複数データの送信では正しく送られない。

 ねむいさんのブログにも、このソースについての不安が同じように出ていたが、わかってしまえば、いつものように自分のお馬鹿な基本的ミスで、とりあえず問題は解決した。USBのエンドポイントバッファーに書き込む配列の番号がオリジナルのままになっていた。これでは、常にデータを送り終わったところが始点で、いつもゴミを送ることになる。字化けするはずだ。

 これをバッファーの最初、&EP_Buffer[0]にすることで字化けしていた複数データは一応正常に表示された。やれやれ。しかし謎が残る。何故1文字の時、正しく出たのだろう。1文字のときでも化けるはずなのだが、1文字の時は正常に送出される。謎である。

 とにかく、前のV1のライブラリを使った103の仮想UARTと同じような動きはするようになった。ただ、まだsystickを使ったタイマーは動かないし、ちょっと多量に送ると半分以上欠落するし、頻繁にハングする。まだボロボロでとても完成と言える状態ではない。

V3から導入されたハードのエンドポイントバッファーに書き込む関数SIL_WRITE()が不調である。パケットサイズ一杯に送ると、データを半分以上落としてしまう。パケットサイズの半分にすると、大体動くが、それでも4 KB以上を一気に送ると、ハングしたり、データの欠落があり安定しない。それにしても、このVCOMのコードはV3になっても色々なところでたたかれているようだ。

 でも、まあ、とにかく、USB仮想UARTは動いた。これでやっと、VCOMの縛りから逃れられた。そろそろ本筋のTFT液晶の工作に移らなければいけない。

脱線ついでにSTM32でタイマーを実装(1/31/2012)
 と、意気込んでは見たものの、一向に工作の意欲が湧かない。CPU基板の上にのせる液晶、SDカードソケットなどを載せるサブ基板のレイアウトがなかなか気に入った構成にならない。モジュラージャックは、べたアースの基板を使いたいが、そうすると基板が三重になってみっともないしと、あれこれ迷っているだけである。

 で、相変わらず、また脱線してしまった。タイマーの実装である。経過時間を示す1ms単位のTickタイマーは、USBの新バージョンでsystickを使われてしまって動かなくなっている。ちょうど良い機会だ。今まで面倒なのでやってこなかったSTM32のタイマー実装に挑戦してみた。予想通りこれがどうして、手ごわかった。

Stm32

 弁護士さんの書いた参考書「STM32マイコン徹底入門」は、このあたりが100ページ近くにわたって詳細に紹介されていて、なかなか役に立つが、それにしても設定パラメーターが恐ろしく多い。とても最初からやってられない。結局、自分でいちから書くのをやめ、ひとさまのソースを拝借して、0.5秒のタイマーを作った。

 ソースの丸写しである。LEDチカチカで成功を確認する。単純なオーバーフロー割り込みのタイマーだけで16行の定義である。いやあ、これは大変だ。まあそれだけ機能が多いということなのだが、どうみても入門者には無理だ。

 しかし動かしてみると、USB仮想UARTがタイマーで字化けする。本来あってはならない状態なのだが、理由がわからない。このあたりでその日の気力を使い果たした。
何かの参考になるかと思い、コード例をお示しする。

void TIM2_start(void)
{
NVIC_InitTypeDef NVIC_InitStructure;    //割り込みベクタのインスタンス定義
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //タイマー定義構造体
TIM_OCInitTypeDef TIM_OCInitStructure;  //コンペアマッチ構造体(今回不使用)

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //クロックを起動

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;      //TIM2割り込み定義
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);         //割り込みベクターの初期化

TIM_TimeBaseStructure.TIM_Period = 14280-1;    // カウンターの上限値
TIM_TimeBaseStructure.TIM_Prescaler =360-1; //プリスケーラー値
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //キャプチャークロック分周
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //増加カウント

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //上記定数でタイマーを設定

TIM_PrescalerConfig(TIM2, 4,TIM_PSCReloadMode_Immediate);//プリスケール再設定

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  //上限値で割り込み許可;

これは設定だけで、このほかに割り込みハンドラーのコーディングがある(略)。
オリジナルは、ここのページである。
(TIM_PrescalerConfig()は不要でした。12/2/2014 修正)

S_p1314617


ダブルバッファーにしてSTM32F107の仮想UART端末完動(2/4/2012)

 V3の仮想COMデモをベースにしたUART仮想モニターは動いたとはいえ、データは欠落するし、たまにハングし、まだ使い物にはならない。もともとソースがひどく読みにくかったので、リングバッファーを使った処理に殆どの部分を書き換え、見通しが良くなったのだが、どうにも安定しない。Sof_

 タイマーを入れて文字化けする問題は、タイマー割り込みが計算違いでマイクロ秒単位で起きていたことがわかり、1ms単位になるようにして解決したが、不安定なことは変わらない。

 こうなると意地である。ロジアナを持ち出して、本格的なデバッグ体制に入った。基板についているLED、2 ヶをロジアナのプローブ点にして、各ルーチンの動きを探る。USBの資料も読み直して、ロジックを勉強しなおす。

 STM32のUSBライブラリは、V3でUSBホストにもなるOTG機能がついた。このためにUSB制御の階層がさらに増え、エンドポイントのバッファー操作が直接出来なくなっている。そのため、このV3のVCOMでは、データ送信のキックは、送信エンドポイント(USBにとってはIN方向)の書き込み後の割り込み(EP1_IN_Callback)ではなく、USBの定期的な割り込み、SOF割り込みで行われるようになっている。

 このため、マイコンの中での送信要求は、このSOF割り込みがms単位と長いので、実際にUSBを通してPC側に送られるデータが多量に溜め込まれて待たされることになる。片側がUARTならそう問題ないが、マイコンの中の送信要求は、べらぼうに早いので、これがハングやデータ欠落の原因になっているようだ。

 未送信のデータでバッファーが一杯になれば、マイコン側の送り込みを待たせ、そこからエンドポイントバッファーに書き込んでいくロジックになってはいるが、この多重処理をしているうちに、ハングアップしてしまうようだ。

 だいたい、この新しいSTマイクロのエンドポイント書き込み関数SIL_WRITE()は、パケットサイズの64バイトまでフルにデータを入れて、エンドポイントに立て続けに書き込むと、それだけで確実にフリーズする(半分くらいだと大体大丈夫)。どうも下位ルーチンがバグを抱えているようだ。恐らくエンドポイントの処理中に入るハード割り込みを止めていないのでレジスターが壊されているのだろう。

 思い切って、このV3のやりかたを捨て、前に成功しているダブルバッファー方式に換えることにした。この方式は、ユーザーの送信要求をパケットサイズ単位で待たせることになるので、USB側に多くの負担をかけることがない。SOF割り込みは使わない。最初のキックは、前と同じように、片側のバッファーでダミーデータの空打ちをする。

Photo

 V1のコードを丸々、こちらに引き込む。大した作業量ではない。ビルドする。おお、フラッシュサイズも4KB以上小さくなった。ファームを書き込む。さあ、どうだ。動くか。よーし、オープニングメッセージが出た。エコーバックも大丈夫なようだ。次は問題の大量メッセージ送信である。

 まずは、1000バイト。問題ない。次は、2000バイト。オリジナルのVCOMでは滅多に成功しない量だ。問題ない。いいぞ、いいぞ、送信量を増やして行く。遂に13KB(リターンキーだけだとx0Dで13)でも全くハングもデータ欠落もなく画面に出力が表示された。速度は前と同じ2Mbps(前のV3オリジナルでは、とりあえずすべて受け入れるので4Mbps以上だったが、動かないことには意味がない)。

 なーんだ。最初から、このダブルバッファー方式にして置けば良かったのだ。久しぶりに解決したときの興奮を味わう。やっぱりこれが味わえないと電子工作らしくないな。気分が良くなったところでブログに報告することにする。

Vcom

 以下に、Eclipseのプロジェクトフォルダーとして入ったソースコード一式のzipファイルを置きます。STマイクロV3のペリフェラルとUSBライブラリは、5MB近くあって、このブログの容量制限で載せられないので、正規サイトなどで落とし、フォルダー名を上記プロジェクトフォルダー直下のlibとして下さい(um0424のSTM32_USB-FS-Device_Lib_V3.3.0内にあります) 

詳しくは、同梱のmakefile参照。ねむいさんのソースから変更したのは、main.c usb_endp.c hwconfig.cの3本だけです。

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

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

« 2012年1月15日 - 2012年1月21日 | トップページ | 2012年2月19日 - 2012年2月25日 »