2008年6月22日日曜日

ゴミ SD カード活用

-------- initialize --------
CMD0:1 CMD1:7 CMD1:7 CMD1:3 CMD1:3 CMD1:3 CMD1:3 CMD1:3 CMD1:3 CMD1:3 CMD1:3
-------- CSD --------
CMD9:0,FE
0000:CSD structure
0000:System specification version
002D:Data read access-time 1
0000:Data read access-time 2 in CLK cycles
0032:Max. bus clock frequency
0135:Card command classes
0009:Max. read data block length
0001:Partial blocks for read allowed
0000:Write block misalignment
0000:Read block misalignment
0000:DSR implemented
019E:Device Size
0006:Max. read current @ VDD min
0006:Max. read current @ VDD max
0006:Max. write current @ VDD min
0006:Max. write current @ VDD max
0003:Device size multiplier
0013:Erase group size
001F:Erase group size multiplier
001F:Write protect group size
0000:Write protect group enable
0000:Manufacturer default ECC
0005:Write speed factor
0009:Max. write data block length
0000:Partial blocks for write allowed
0000:Content protection application
0000:File format group
0000:Copy flag (OTP)
0000:Permanent write protection
0000:Temporary write protection
0000:File Format
0000:ECC code
0074:CRC
f_mount:0
CMD17:0,FE CMD17:0,FE CMD17:0,FE
f_open:0
CMD17:0,FE
f_read:0: read=512
f_close:0
-------- dump --------
0000:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0010:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0020:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

01F0:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

MassStrage.dfu で 8MB のゴミ SD カードのアクセスが失敗していたので,どこでコケているのか調べてみた.
最初は初期化シーケンスが正しくないのかと思ったが,SD の仕様書と見比べてもそんなにおかしなところはない.お次は AC タイミング的なエラーを疑ってみたが,こればっかりはオシロスコープ持ってないのでわかんね.ただほとんどのコマンド (CMD0 とか 9 とかはぜんぜん正常であることが分かってきた.てことは AC タイミング的な問題ではない?

唯一おかしいのは CMD1.こいつのレスポンスが 0x7 とか 0x3 とかしか返ってこないので,MassStrage.dfu では MSD_GoIdleState() で死んでいたようだ.でもレスポンスが 0x7 とか 0x3 とかって,ここ見る限りそもそもなんかおかしいんですが… (illegal command とかありえねー) もしかして SPI の 8bit アライメントがずれてんのか?
本来
11111111 00000001 11111111
と受け取りたいところを,2bit ずれて
11111100 00000111 111111?
と受け取ってしまってるとか.これならばレスポンスが 7→3 に変化してるのも筋が通るが,何でズレてんのかまではわかんね.ああ,こういうときオシロとかロジアナとかほしいなぁ…

で本来 CMD1 のレスポンスが 0 になるまで wait するのだが,レスポンスがおかしいまま次に進んでも CMD17 (セクタリード) とかは全然正常 (これのレスポンスとかリードデータが bit ズレ起こさないのも,上の仮定と違ってて謎).というわけでゴミ 8MB SD カードが無事活用できるようになった(?)

他の使えなかった SD カード (2GB) の解析はやってないけど,たぶんセクタサイズが 512B 以外になっててその設定 (CMD16) をやってないからじゃなかろうか?

-----
追記:
 CMD1 が Illegal Command になっていた件,どうやら SD カードの厳密な仕様的には CMD1 は受け付けなくて,CMD41 で初期化しなければならないらしい.CMD41 で初期化すると,ゴミ 8MB カードも無事使用できた.
 MMC と SD は SPI 通信を使う限り,完全互換性があるという思い込みをしてしまっていた.

2008年6月20日金曜日

FLASH 上のルーチンにリンク成功

デザインウェーブマガジン付録 ARM ボードをいぢくる続き.

FLASH に焼かれたルーチンを SRAM 実行プログラムから呼び出す方法を確立してみた.
SRAM は 20KB しかないので,printf 等の大き目のルーチンを SRAM 実行プログラムにリンクしてしまうと,当然残りの SRAM 容量が減ってしまうので開発に支障が出る.そこで FLASH 上にある printf ルーチンをリンクしてしまおうというのが今回の趣旨.

まず,FLASH 上の printf のアドレスを知るためには,
メニューの Project → Options...
Linker → List タブ → Generate linker map file
で FLASH 実行プログラムの .map ファイルを生成すればよい.たとえば printf のアドレスが 0x080063ed だったとすると,SRAM プログラムのソースで

#define printf (*( int (*)( const char *fmt, ... ))0x080063ed)

と書けば OK.

だが,これだと printf を使ってる全ファイルの修正が必要だし,いちいちプロトタイプ宣言を調べて #define を書き並べるのが面倒なので,別の方法を考えてみる.

rom_entry.s なるファイルを以下の内容

    RSEG ROM_CODE:CODE(2)
EXPORT printf
printf = 0x080063ed
END

で作成し SRAM プログラムのプロジェクトに追加してコンパイル・リンクすることで,FLASH 上の printf にリンクできた.この方法だと .c の修正はいらないし,.map ファイルから perl スクリプトなんかで機械的に rom_entry.s を生成できるので楽.

いろいろ FLASH 上のルーチンにリンクしたら,もともと 18KB のプログラムが 5.5KB になったよ(笑)

2008年6月18日水曜日

SD カード FAT アクセス成功

デザインウェーブマガジン付録 ARM ボードをいぢくる続き.


昨日と今日にかけて,フリーの FAT ファイルシステムドライバであるFatFsを組み込んで,SD カードのファイルを読み出せるようにしてみた.

具体的には,ff.c を組み込んで,diskio.c をインプリしていくのだが,disk_read/write() はほとんど SD カードセクタリード・ライトそのまんまだが,disk_ioctl() は何書いていいのか分からん… 幸いここにサンプルがあった.

デバッグ用にシリアル出力を大量にしているとなぜかリードデータが化ける問題があってちょっとハマッたが,最終的に無事ファイルリード完了ヽ(´ー`)ノ

あと,putchar() 関数を定義して,こいつでシリアル出力するようにしておくと,printf() で普通にシリアルにメッセージが出せるので便利ヽ(´ー`)ノ

以下,ToDo リスト
・FLASH のルーチンを SRAM プログラムからコールする仕組みを確立
・SRAM ルーチンを割込みハンドラに設定
・割り込みを使用したシリアル入出力
・ここら辺が FIX したら FLASH に焼いて,「SD カード上のファームを SRAM にロード」を運用開始

2008年6月16日月曜日

SD カードセクタダンプ成功(?)

データロガー 2号機計画を ゆっくり と進行中.


今回は,MassStrage を参考に,SD カードの 1セクタをリードしてシリアル (USB を介した仮想 com ポート) 出力にダンプさせてみた.まぁ MassStrage の msd.c あたりをそのまま組み込んだだけだが.コンパイル通すのに多少苦労しつつ,とりあえずダンプできるまでこぎつけた.

が,シリアル出力が明らかにおかしい.シリアル出力はカエルがぴょんのやつを参考にしていて,USB の送信データバッファ(?) に送信したい文字列を直接コピーしているのだが,おそらく前のやつが送信されきらないうちに次の文字列を上書きしているのだろう.

普通は,アプリ側でリングバッファを用意して,送信したいデータはリングバッファに書く→USB 送信データバッファに空きができたら割込み発生→割込みルーチンで,リングバッファから送信データバッファにコピー,なんて流れになると思うのだが…
もうちっと Cortex の割り込みを勉強せにゃならんね.とにかくシリアル出力をまともにしないと,まともなデバッグができねぇ.

とりあえず,断片的に見えているダンプデータを見る限り,SD カードセクタリードはできているようだ.

----
6/16追記:
とりあえず割り込みを使用しないでお茶を濁しモード.送信データをバッファにカキコ前に

while( GetEPTxStatus( ENDP1 ) == EP_TX_VALID );

で前回のデータが送信されきるまで待つことで,シリアル出力は正常になったヽ(´ー`)ノ

2008年6月9日月曜日

シリアル経由 FW ローダ完成

前回の記事どおり,SD カードの FW を SRAM にロードする仕組みを作っていくが,その前に,シリアル経由で FW を SRAM にロードする仕組みを作る.いくら既存のライブラリが充実しているからって,一発で SD カードアクセスプログラムが動くわけが無いのでw


というわけで,
1. 起動されたらデータを 0x4800 バイト分,シリアル (USB経由) から読み込んで 0x20000000~ へ書き込む
2. 0x20000004 に格納されているエントリポイントにジャンプ
という恐ろしく単純なプログラムを FLASH に焼きこんだ.これすらも,デザインウェーブマガジンに載っていたカエルがぴょんプログラムをちょこっと書き換えただけ.

ちなみに,マガジン付属 CD に入っていたサンプルプログラムの多くは,IAR Embedded Workbench でコンパイルしようとすると「__program_start」シンボルが無い,などと怒られてしまうが,その対処法はここに載っているようだ.

そしてマガジンに載っていた LED を点滅させるプログラムを SRAM 実行用に書き換え→.s19 を 0x20000000 からのバイナリイメージに変換するプログラムを作って変換→TeraTerm の send file で基盤に送信,で無事 LED が点滅したヽ(´ー`)ノ

これで内蔵 FLASH を書き換えることなく開発・デバッグができる.しかし,早いことベース基盤を作らないと,リセットボタンすらないのでやりにくぅ.

ちなみにメモリマップは前回からさらに変わっている↓

20000000ベクタテーブル
200000ECSRAM プログラム用 .text
・・・SRAM プログラム用 .data .bss 等
・・・空き
・・・スタック
(SRAM後端)FLASH プログラム用 .data .bss 等
20005000

SRAM 実行用プログラムのコード・ベクタテーブルを SRAM の前端で固定したかったので,FLASH 実行用 SRAM 領域を SRAM の最後尾にやって,そこからスタック領域とした.

2008年6月8日日曜日

データロガー2号計画発動

デザインウェーブの Cortex-M (AAM ARM) 基盤を使ったデータロガー 2号機作成をぼちぼち開始.

とりあえずの目標としては,SD カード上のファームウェアを SRAM 上にロードする仕組みを作る.で開発途上は SD カードにファームを書き込むことで Cortex 内部 FLASH の書き込み回数を減らす.これだとコード + データが 20KB 以内しか作れないが,デバッグの終わったルーチンをまとめて内部 FLASH に追い出して,SRAM 上のプログラムから FLASH 上のルーチンを呼び出す.なんてことを H8 の時はしてた.(H8 は SD カードアクセスはできなかったので,シリアル経由の .mot ロードだったが)

で,SD カードアクセスのライブラリは MassStrage デモのライブラリがそのまま使えそうだ.FAT アクセスライブラリも使われてるかと思ったら,FAT の管理をやってるのは Windows 側なのね.なのでフリーの FAT ライブラリを探してみたら,ここのが使えそうだ.

で,いろいろ make してると,メモリマップがちょとヘンなことが発覚.常識的には SP の初期値は RAM 領域最後尾の 0x20005000 だと思うのだが,標準だと 0x20000000 + プログラムで使う分 + 0x200 くらい.RAM あまりまくってるのにもったいない.

これは gcc でいうところのリンカスクリプトがおかしいのだろうと思っていろいろいじってみた.俺がインストしたのは「IAR Embedded Workbench」なので,リンカスクリプトに相当するのは「STM32F10x_FLASH.icf」になる.で以下のように書き換えた.

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08003000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x080030ec;
define symbol __ICFEDIT_region_ROM_end__ = 0x0801FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20004FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x0;
define symbol __ICFEDIT_size_heap__ = 0x200;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];

define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
place at address mem:( __ICFEDIT_region_RAM_end__ + 1 ) { block CSTACK };

define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };

initialize by copy { readwrite };
do not initialize { section .noinit };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

define block RAM_Block with fixed order { rw, block HEAP };

place in ROM_region { readonly };
place in RAM_region { block RAM_Block };

要は,もともとの .icf ではデータ・ヒープ・スタックを連続領域にとっていたのだが,STACK を独立させて 0x20005000 から サイズ 0 で(笑) 固定的に取っただけ.
てか,gcc のリンカスクリプトはドキュメントが充実してるし高機能だし楽なんだけど,ツール独自のリンカスクリプトはわけが分からん…