« 2013年1月13日 - 2013年1月19日 | トップページ | 2013年2月10日 - 2013年2月16日 »

2013年1月27日 - 2013年2月2日の1件の記事

2013年2月 1日 (金)

STM8Sにフォントデータを入れる外部フラッシュメモリをつける

 販促基板のUSBローダー部ばかりが注目されて本体は不遇な8ビットマイコンSTM8Sに同情して始めたプロジェクトは、次はこれに外部メモリをつけてSPIで動かそうというところまで進んだ。

 前回の記事では、モノクログラフィックLCD(以降GLCD)をAVRで動かしたが、本来はこのSTM8Sで動かすためのものである。今度の外部メモリをつけるというのも、風が吹けば桶屋が儲かるという諺に近い話で少し説明がいる。

 GLCDに文字を出したいが、STM8SはGNUコンパイラーがないのでフォントファイルをフラッシュに埋め込めない。それなら外部メモリにフォントデータを入れればよい。どうせなら、いっそのこと日本語まで出ると面白いだろう、という脱線に近いプロジェクト進行である。

 しかけはSTM8SのSPIインターフェースに外部メモリをつなぐだけである。コーディング例は、例の平坂氏のSTM8SサイトにSDカード(SPI接続)を直か読みするサンプルソースにある。簡単に動くだろうと気楽に始めた。

  ところがこれがはまったのである。このブログは、ときどき「波乱万丈」と褒めていただくが、今回も、実はここに書くのも恥ずかしい思い違いをいくつかやって、見方によってはドラマチックな展開になってしまった。

 はたから見れば、何でまた、こんなくだらないことに血道をあげるのだろうと思われることばかりだが、負けず嫌いの当人にとっては、大げさに言えば自分の存在を賭けるくらいの入れ込みようになる。うまくいかないときは、率直に言って人生が暗い。生きていることがつらくて、来し方行く末をあれこれ考えるくらい落ち込む。

S_p1315669 しかし、問題が解決したとなると、暗い気持ちが一挙に吹き飛んで、まるで天下をとったような気分になる。山の頂上を極めたり、マラソンを完走したときと同じような快感だ。こういう快楽のときに分泌されるというドーパミン中毒に間違いなくかかっている。

M25P40という4メガビットメモリーをSTM8S-discovery基板につける(1/21/2013)
  このM25P40という8ピン外付けメモリーは、以前LatticeのFPGA XP2に載せるつもりで買ってあったが、XP2本体のメモリで用が足りたので使わずに置いてあったものである。SPIインターフェースで、サイズは512KBもあるから、12ドットの日本語フォントファイル(240KB)でも余裕で入る。書き込みは遅いが、読み出し速度は速い(この石は25Mbit)。

 ただ、SPIはGLCDで使う予定だ。SPIはCS(チップセレクト)で複数のディバイスを一本のSPIでつなげるとはいえ、プログラムは複雑になる。最初は、独立したI2CのEEPROMにするつもりだった。しかしI2C EEPROMの手持ちは最大が1Mビットで128KBしか入らない。それに速度がせいぜい1Mbitなのでちょっとかったるい。

 少し迷ったが、結局、M25P40を外付けメモリに使うことにした。STM8S-Discoveryの試作スペースにM25P40を実装することにした。久しぶりの基板の半田付けである。STM8S-Discoveryには、基板の一部にユニバーサル基板的な蛇の目パターンがあって、真ん中には表面実装の8ピンPSOCパターンまで用意されている。

 最初、このパターンに吸い寄せられるように、嬉々として、M25P40(PSOC 8ピン)をパターンにハンダ付けして、はたと気づいた。M25P40へのデータ移動は、SDカードをつけたマシンを経由しようと考えている。ソケットで着脱できるようにしておかねばならない。お馬鹿な話である。

S_p1305662 例の低温ハンダ(ストロベリーリナックスの低温ハンダが安い。¥1575)で取り外し、DIP用の変換基板(秋月の8ピン用¥11)に載せ換える。このM25P40の1番ピンがわかりにくい。データシートにはチップの文字が表記されていないが、正順に置かれているとして左下を1番としたが不安である。電源とグランドが、たすきがけの配置なので間違えれば一発でお陀仏になる。

 ソケットをつけたあと、UEW線で本体との配線をすませる。SPIなので3本をつなぐだけだ。電源とグランドを合わせて5本のハンダ付けである。ハードの準備はあっけなく終わった。さあ、次はソフト開発である。

STM8SのSPIはSDカードアクセスのサンプルソースを利用する(1/23/2013)
 平坂氏のサイトのSDカードのプログラムは、STマイクロ社のSDカードのサンプルコードが大元になっているようだ。 SDカードのアクセスは、ChaNさんのFatFSを移植する予定なので、SPIをドライブする基本関数部分だけを利用させて貰う。

 同時にM25P40のデータシートを読んでアクセス手順を勉強する。EEPROMは、STM32で気圧計に実装したり、AVRでも使っているので理解が早い。読み込みはページ区切り(256バイト)を無視して連続して読めるようだ。ただし、書き込みは、どこからでも書き込めるが、256バイトのページ単位で折り返される。

S_p1305656

 読み出しを止めるのは、チップセレクトだ。書き込みは送信をやめるだけで止まる。擬似コーディングを始めて、ドライバーの構成がかたまってきた。いつものように、ソースコードは3階層に分ける。

 最初のSPIのところは、GLCDと共用になることを意識して変数名を考える。ここでやることは、SPIの初期化と、1バイトの送受信関数だけである。2段目は、EEPROMのアクセスルーチンで、データ書き込み/読み込みシーケンスの基本(共通)部分をここで作る。3段目がアプリケーションレベルで、ここが実際のデータの書き込み/読み込み関数となる。

 当初、フォントデータの書き込みは、SDカードを持った別のマイコンに、このEEPROMをつないで、そこからオブジェクトファイルをEEPROMに流すつもりだった。そのために、STM8Sの基板に最初ハンダ付けでつけたEEPROMをわざわざ剥がして、ソケット付きにとりかえている。

 しかし、開発を進めていくうち、STM8SのUARTでファイル転送を使えば、そんな手間は要らないことに気づいた。データはバイナリーデータだし、送受信とも1バイトも取りこぼしが許されないので、UARTにはダブルバッファーを設定するなど、少し難しいロジックになるが、これはこれで挑戦しがいのあるプログラムだ。楽しみになってきた。

RaisonanceのCコンパイラーのエラーメッセージに惑わされる(1/25/2013)
  ソースコードはそれほど苦労せずに出来たのだが、わけのわからないコンパイルエラーが連続して、なかなか先に進まない。このRaisonanceのCコンパイラーは、無償だからあまり文句は言えないが、このコンパイラーのエラーメッセージが奇怪で、その対応に一日つぶれてしまった。

 何でもない関数のところで、わけのわからないコンパイルエラーが出る。しかも容易に解決しない。キャストが裸になっているのを括弧で閉じたり、ifの中の演算の括弧を増やしたりするといつのまにか直ってしまう。だいたいエラーメッセージが、実体を反映していない。

 エラーの大元は、
 void M25_Write_Page( uint32_t adr, uint8_t *buf, uint16_t leng)
という、adrで示されるEEPROMアドレスに、lengの長さの、bufにあるデータを書き込む関数である。全く同じ形式のM25_Read_Str(略)は、エラーにならないのに、こいつだけが通らない。全く不審である。

 しかも、出てくるエラーコードが Invalid parameter declarationになったり、syntax errorだったり不定で、funcdef requires ANSI-parameter listというわけのわからないものや、なかには、警告だが、'?' decleared. but not used.などという全く身に覚えのないメッセージが出たりする。

 そのうえ、プロトタイプ宣言をヘッダーファイルですると Invalid parameter declarationというエラーになるのに、プロトタイプ宣言をソースに持ち込むとエラーでなくなる(警告)。全くもって何のことかさっぱり見当が付かない。

 ソースをだましだまし調整して、コンパイルはやっとNO ERRORになった。大したステップ数でもないのに、およそ一日かかってしまった。先が思いやられる。

コンパイラーのご機嫌が悪い。いんちきな引数渡しをしている(1/26/2013)
 コンパイルが通った(少し警告が残るが)ので、いよいよテストに入る。テストのやり方は、UARTモニターから文字列を適当なEEPROMアドレスに送り込み、それを読み出しコマンドでUARTにデータを戻して確かめる方法である。いつもの定番のテスト方法である。

 ただ、この方法では、うまく動かなかったときのデバッグは不可能である。送信が悪いのか、受信がまずいのか、それともEEPROMがおかしいのかを簡単に特定することが出来ないからである。心配なので、最初からロジックアナライザーをプローブさせて送受信の様子をみながらテストすることとした。

S_p1305655 テストを始める。懸念したとおりいきなりハングするだけで全く動かない。ロジアナで見ると送信から動いていないことがわかる。やれやれ。今度は、UARTの出力関数を入れて最初からチェックして行く。いわゆるprintfデバッグである。あれえ、SPIの送信関数の引数がでたらめな数字になっている。なぜだ。

 関数を呼ぶ前と、関数内の引数の値が明らかに違うことを確認した。どうも警告を無視してコンパイルした結果がまずいようだ。プロトタイプ宣言をヘッダーファイルに定義すると、エラーになって、main.cに持ち込むと警告になった例の関数である。

 正しく引数が渡されていないのは明らかだ。同じような引数構成の他の関数は通っているのに、こいつだけがおかしくなる。コンパイラーの不具合の疑いが濃厚だけど、こればかりに時間をかけているわけにはいかない。

 対症療法を考える。ヘッダーファイルがらみでエラーが起きているようなので、この関数をmain.cの中に入れてしまって、1ファイルとしてコンパイルしてみた。なんだ。警告もなくなった。やっぱり関数の表記が悪いのではなかった。

 テストしてみる。うむ、パラメーターは正しく関数に送られている。ロジアナの波形も、とりあえずもっともらしい送信シーケンスになったようだ。しかし、まだ正しいデータは戻ってこない。

SPIのマスター受信って送信しないと動かないのね(1/27/2013)
 ロジアナで見る限り、正しい命令、正しいアドレスでEEPROMにデータを送っていることが確認された。しかし、受信をしても全くデータは受信できない。SPIに対する読み込み命令は正しくEEPROMに送信されている。しかしクロックパルスが出てこない。

 正しく送られているといっても、これは単にSTM8SからEEPROMに送ったというだけで、EEPROMがこれを正しく受け取ったかどうかの確認はできない。送信シーケンスのあとデータが書かれたことを確認するRead Status Registerという命令を送ってもStatus Registerが帰ってこない。もしかするとEEPROMを逆差して、壊してしまったのかもしれない。

 もういちどルーペを取り出して何度もチェックする。刻印はないが、印刷の方向はデータシートと同じで問題なさそうだ。電圧も正しくかかっている。調べるところがなくなった。状況は暗い。気分が落ち込む。しかし、こんなことくらいで引き下がるわけにはいかない。

 基本的なところから確認していくしかない。受信のとき、クロックパルスが出ないのはなぜだろうと考えていて最も基本的なことに気づいた。クロックパルスはスレーブ側のEEPROMが出すのではないのだ。あくまでもマスターのSTM8S側が出すものだ。うはあ、わかったぞ。このあいだサンプルソースの受信関数から不審な送信コマンドをコメントアウトしたことを思い出した。

 このサンプルソースは送信するときも、受信バッファーに入ったデータを受け取って呼んだルーチンに返している。てっきり全二重通信のために、受信のときも送信しているのだと思い、今度のような半二重通信には不要と考えて削除してしまっていた。

 そう言えば、これまで開発したSPIインターフェースはすべてマスター送信だけで、SPIのマスター受信というのはやったことがない。受信関数のサンプルソースに送信コマンドが入っているのは、受信クロックパルスを作るためだったのだ!何というお馬鹿な勘違い。

 I2Cのように、スレーブ側も何らかのパルスを出して交信しているのだとばっかり思っていた。SPIのスレーブというのは、クロックパルスを受けてデータを送ることしかやっていないのである。いやいや思い込みというのは恐ろしいものである。

 あわてて、受信関数にもダミーバイトを送信するコマンドを入れて、テストする。無事、ロジアナには受信パルスが復活した。ReadStatusRegsterコマンドのあとにもStatusRegisterのデータが出るようになった。

 しかし、受信したデータは意味のあるデータではなかった。StatusRegisterの値も、ロジアナではちゃんとしたデータがでているのに、受信関数を通した値は、全く違う値だ。書き込み完了が終わらず延々とループする。先はまだ遠い。

Ws000000 しかし、ロジアナのお陰で、全体の動きが完全に把握できている。もし、これがなかったらここでのデバッグは全くお手上げだっただろう。測定器の有難さをつくづく感じる。トラブルシューティングを続ける。

M25P40はEEPROMでなくフラッシュメモリーだった(1/29/2013)
 最後のオチが、ここに書くのもためらわれるお恥ずかしい思い込みだった。SPIの受信コマンドがまともに動いて、ロジアナで見る限り、受信シーケンスはちゃんと想定どおりのデータストリームとなった。しかし、送り込んだデータと似ても似つかぬデタラメなデータしか出てこない。

 データが送り込まれているらしいことは、受信するデータが少しづつ変化しているので、全く動いていないわけではなさそうだ。送ったデータより先のエリアは、0xFFで埋められているので、何らかのデータが書き込まれ、それを読んでいることは確かだ。

 ただ、データはでたらめである。もうデバッグすることがなくなった。解決を求めウェブをさ迷う。しかし検索するにも適当なキーワードが見つからないので有力な情報に行き当たらない。STM8Sのエラータ情報にSPIに関連するのが1件あるが、どうみてもそれとは関係ない。

 万策が尽きて、印刷したM25P40のデータシートを最初から少し丁寧に読み返し始めたときである。書き込みコマンドのところで妙な記述に目が止まった。

Page Program instruction allows bytes to be programmed in the memory(changing bits from 1 to 0).
 「ページ書き込み命令は、メモリのビットを1から0に変えてプログラムします。」

 なんで、わざわざ、1から0と断っているのだろう。ここで明かりが点った。あ、あ、あ、もしかして、このメモリーはこれまでのEEPROMと違って、フラッシュメモリーなのか。てっきりEEPROMだとばかり思っていたが、違うようだ。

 何のことはない。M25P40のデータシートにもちゃんとSerial Flash Memoryと書いてあり、EEPROMとは書いていない。大慌てで、改めてウェブで、EEPROM、フラッシュメモリ、NANDメモリ、NORメモリなどの外付けメモリの違いについて調べ直す(ここが詳しい)。

 大きな誤解をしていた。フラッシュメモリは、EEPROMといわれるメモリと違ってデータの書き込みでは、0から1には出来ないのだ。書き込むときは一旦、eraseで全体を0xFFにしてからでないと正しいデータにならない。

 そうか、だんだん書かれた内容が0になっていくのはそういうことだったのだ。間違いない。謎が解けた。あわてて、データシートのセクターイレーズ(Sector Erase)のコマンドを使って、メモリーを消去する手順を加える。

 テストする。はい、おめでとうございます。やっと思うようなデータが入り、それが出てきた。少し長い2バイトコードの漢字も入れてみる。問題なく日本語が戻ってきた。いやあ嬉しい。暗かった気分がすっかり晴れる。心が充実感で満たされる。周りを余裕を持って眺められるようになった。

Ws000001

 しかし、それにしても今度は長かったな。解決に少なくとも4日はかかっている。外付けメモリについて、いい加減な覚え方をしていてひどい目にあった。

 さあ、次は、UARTを使ったファイル転送だ。まだソースコードはデバッグのためのテストステートメントが山盛りになっており、機能的にはまだテストプログラムにすぎないが、とりあえずは一山を越した。ソースコードの公開は次のファイル転送を実現してからまとめてやることとしたい。今度はドジを踏まないぞ。

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

« 2013年1月13日 - 2013年1月19日 | トップページ | 2013年2月10日 - 2013年2月16日 »