PICを使ってSDカードを操作

PICはRAMが比較的大きく試作のしやすいDIPパッケージの、PIC18F2550を使います。このPICはUSBポートもありますが、USBは使いません。
PIC18F2550基板と、RS232Cコネクタ
割り込み処理でソフトウエアUSARTを実現する
簡単なモニタ機能でSDカードの操作をしてみる
SDカードへのコマンドとレスポンスのタイミング
SDHCにも対応できるSDカードの初期化
CCSを使って、C言語で開発 ( CCS PCH C Compiler, Version 4.076 ) 2012.3.19 更新
PICを正規の5Vで動作させるため、新たに基板を作成 2012.3.24 更新
新たに作成した基板で、ニッケル水素電池の充電中の電圧をSDカードに記録2012.4.8 更新
押しボタンスイッチによる操作で、スタンドアロンで動作させる 2012.4.8 更新
PIC24FJxxを、無償版のCコンパイラ、C30で開発、SDカードの基本操作機能追加 2012.4.28 更新
PIC24FJxxで、64GBのSDカード、SDXCを操作してみた 2012.5.20 更
PIC32MX vs LPC11U35(Coretex-M0), etc. PIC32MXを使ってみる。 ドライストーンで評価。2016.5.8 追加 

フラッシュメモリでのみ動作するPICは、たいていROMデバッグ
PICのプログラムを開発する場合、その処理がI/O操作を伴わない内部メモリの操作部分は、開発環境のMPLABにある、シミュレーションでたいていのデバッグが可能ですが、I/O操作を含み、そのI/Oに接続されている外部の回路の振る舞いがよく判らない場合は、フラッシュにプログラムを書いて確認する、いわゆる”ROMデバッグ”となり、動くか否かは、一発勝負になってしまいます。そこで、外部I/Oの操作を、PICとターミナルで通信しながら、任意のポートを読んだり、書いたりできると、かなりデバッグ効率が上がります。

PIC18F2550のモニタを作る

PIC18F2550には、USARTポートは1個しかありません。このため、パソコンをターミナルにしたモニタの操作用にこのUSARTを使ってしまうと、シリアルポートを使ったアプリケーションのテストができなくなります。そこで、プログラムで直接ポートを操作して、パソコンと通信できるようにし、空いたUSARTを、他の用途に使えるようにして、簡単なデバッグができるようにします。特に、USARTのSPIを使ってSDカードの操作をする場合は、このデバッグ機能が役に立ちます。モニタを使ったSDカードの操作はこちら モニタでSDカードの操作をしてみる
とは言うものの、PICのプログラムは、内臓RAMにロードしてそこでテストランすることができないので、モニタの機能としては、ポートの読み書き、RAMの表示や変更という機能に限定されます。モニタの操作による任意番地からの実行もできません。
ソフトウエアでシリアルの送受信をするには、ボーレートに合わせて1ビット単位でシフトしながらポートに出すのと、ボーレート時間単位にポートを読んでMSBに書いて右シフトして受信データを作るのが必要です。ここで、送信の場合は比較的簡単ですが、受信はスタートビットがいつ来るかわからないので、常にポートを読んでいないといけません。そこで、受信ポートの立下りで割り込みを発生してスタートビットを知るという方法にすると、CPUは他のことができますが、シリアルデータの立下りでも割り込みが発生するので、1文字の受信が完了するまで、立下りでの割り込みは禁止しないといけません。

以下は、適当なI/Oポートにデジトラ(ベース、エミッタの抵抗は10kΩのもの。RN1102、DTC114EKA、FA1A4M など)と抵抗を接続して擬似RS232C信号に変換して、十分実用になるRS232C変換回路です。この回路では、3V以下の電源電圧でもパソコン側で受信できるように、送信の電圧を上げるため、RS232Cのホストからの信号の、RTSに相当するピン(約10Vになっているはず)から電源をいただき、抵抗でプルアップしてPIC側の送信データラインとしています。57600ボーぐらいまで問題ありません。


ポートのソフト操作による完全非同期のシリアル送受信は可能か?
もうひとつ、送信中に受信が始まったらどうするかという問題は、そう簡単に解決できそうもありません。送信と受信は、完全に非同期に動作するので、送信タイミングの時に1ビット受信のサンプリングと言うわけにいきません。ボーレートが低いならタイミングを計算するのに余裕が出てきて、双方向の同時操作もできそうですが、PIC18Fで16MHz前後で動かす場合、300ボーとか、600ボーぐらいが限度ではないかと思います。

そこで、比較的短い間隔で、(理想的にはボーレートの16倍の周波数)一定時間の割り込みを常に発生させ、これで送受信タイミングを制御するという方法にすると、この非同期問題をスマートに解決できます。ボーレートの16倍はちょっと早すぎるので、8倍とか、4倍に落として高いボーレートでも動作できるようにします。ここで、インターバル割り込みを、ボーレートの4倍にした場合、どれくらいの誤差になるか、図で示します。

この図から判るように、ボーレートの4倍の周波数でサンプリングすると、最良でほぼデータビットの中央となり、最悪では、中央より25%早い位置となって、双方のボーレートが正確なら、実用上問題なく動作します。

PIC18F2550で、一定間隔の割り込みを発生させる

一定間隔の割り込みには、タイマー1を使い、コンペアマッチで割り込みが発生するようにします。このモードは、CCP1M3--CCP1M0 の4ビットを、1011に設定します。コンペアマッチの対象となるカウント値は、CCPR1H と CCPR1L に、16ビットで設定し、ボーレートの4倍の周波数 −1となるような数値にします。この例では、9600ボーの4倍、38400Hzで、4MHzを割った値 −1で、103を設定しています。
;	1秒間に約38400回のインターバル割り込みを発生させる設定
	clrf	T1CON		; タイマー1停止
 	movlw	0x67		; 0xCF=19200/4 ==> 4800bps, 0x67=38400/4 ==> 9600bps
	movwf	CCPR1L		; タイマー1コンペアマッチの値
 	movlw	0x00
	movwf	CCPR1H		; 上位ビットは0
	clrf	CCP1CON		; 最初にクリア
	bsf	CCP1CON,CCP1M3	; タイマー1コンペアマッチ
	bsf	CCP1CON,CCP1M1	; タイマー1コンペアマッチ
	bsf	CCP1CON,CCP1M0	; タイマー1コンペアマッチ
	bsf	RCON,IPEN	; 優先割り込みを設定
	bsf	IPR1,CCP1IP	; Timer1 を優先割り込みに設定
	bcf	PIR1,CCP1IF	; Timer1 の割り込みフラグをクリア
	bsf	PIE1,CCP1IE	; Timer1 の割り込み許可
	bsf	INTCON,GIEH	; グローバル割り込み許可
	bsf	INTCON,GIEL	; グローバル割り込み許可
	clrf	TMR1H		; Timer1 クリア
	clrf	TMR1L		; Timer1 クリア
	bsf	T1CON,TMR1ON	; Timer1 カウントスタート、以後約26μ秒間隔で割り込みが発生。

割り込み処理でソフトウエアUSARTを実現する

割り込み処理の仕様を以下のようにします。割り込み処理は、言わばマルチタスクの基本型ですから、このタスクに対してコマンドとステータスフラグを設けて、メインプログラムからはフラグのON、OFF、ステータスの判定で操作します。割り込みタスクは、メインからのフラグ操作に応答する形でシリアル送受信を受け持ちます。
  1. 送信コマンドは、送信データの設定と、スタートフラグへの1の設定とします。
  2. 割り込み側では、スタートフラグが1だと、送信要求があると判断し、スタートビット送信後、送信中フラグを立てます。
  3. 割り込み側で、送信中なら、データを順に1ビット単位にシフトして、LSBからポートに出します。
  4. 8ビットの送信が終わると、ストップビットを送信します。
  5. ストップビットの送信が終わると、スタートフラグ、送信中フラグ共にクリアします。このクリアで、メイン側は送信終了を判断します。
  6. 受信は、割り込みタイミングでスタートビットの立下りを検出して、スタートビット検出フラグを立てます。
  7. スタートビットが終わると、受信中フラグを立て、以後4回の割り込み毎に、受信ポートを読んで、シフトレジスタをシフトしてMSBに書きます。
  8. 8ビット受信すると、とりあえずシフトレジスタを、受信データバッファーにコピーし、ストップビットの判定をして、受信完了フラグを立てます。
  9. ストップビットがLowの場合は、フレーミングエラーフラグを立てますが、この場合でも受信完了フラグを立てておきます。エラーの場合、厳密にどうすべきかは、メイン側の処理にゆだねます。
  10. 受信完了フラグをメイン側で検出して、1文字受信したことを知り、受信データを読んだ後、受信完了フラグをクリアします。
以上のような仕様だと、メイン側はあたかもUSARTが存在するかのような使い方で、タイミングを気にすることなくシリアル送受信ができます。この仕様は、ごく基本の送受信タスクなので、特に受信の場合は、次の1文字の受信の時間内に受信データを読んで受信完了フラグをクリアしないといけません。PICでは、間接アドレスレジスタが少ししかないので、受信データをリングバッファーに貯めるという手法は安易には使えません。割り込みで直接使ってしまうと、他で使えないからです。無論、間接アドレスレジスタ、FSRxH、FSRxLを割り込み内で退避、復帰で使えますが、テスト用のモニタではそこまで必要ないでしょう。

以下は、割り込み処理の全体です。メイン側での使い方の例として、1文字送信、受信、受信チェックが、終わりの方にあります。


上記の getcon putcon を使うと、パソコンから何か文字を送ると、そのまま返信するエコーバックで、動作確認ができます。
さて、パソコンとRS232Cで接続できると、パソコンからの操作で、PICのI/Oや、メモリを操作するモニタの機能を入れます。モニタは簡単なものなら、メモリ(I/Oを含む)の読み書きだけでいいのですが、PIC18F2550のフラッシュメモリは32kBもあるので、メモリ間のコピーとか比較、コマンド入力中の1文字修正機能などを入れます。これだけ入れても、プログラムは1.2kBぐらいです。

モニタの仕様とコマンド書式

コマンドの内容 書式 引数の説明
メモリの表示 d コマンド dx,y x は表示したいメモリの先頭アドレス、y は終わりのアドレス
メモリの変更 s コマンド sx(,y) x は変更したいメモリの先頭アドレス、y を追加すると、x のアドレスに y を書いて終わり
メモリのコピー m コマンド mx,y,z x は元の先頭アドレス、y はコピー先のアドレス、z はバイト数
m コマンドのオプション mx,y,z,u 引数 u = 0x1 でコピー元だけアドレスを更新、u = 0x10 でコピー先だけアドレスを更新
メモリの比較 v コマンド vx,y,z x は元の先頭アドレス、y は比較先のアドレス、z はバイト数
コマンド入力中の修正 バックスペース 入力中の1ラインで1文字戻す
s コマンド実行中のオプション1 'n' 1文字入力 n コマンドでアドレスだけ次に進める
s コマンド実行中のオプション2 'r' 1文字入力 r コマンドでアドレスだけ前に戻す
d コマンド実行中のオプション 任意1文字入力 メモリダンプを止めてその場で待機。何か入力で再開。ctrl C では中断、終了
v コマンド実行中のオプション 任意1文字入力 メモリ比較を止めてその場で待機。何か入力で再開。ctrl C では中断、終了

以上の機能を入れたモニタプログラムのアセンブラソースです。
上記のバイナリーコード(HEX)
このプログラムでは、水晶は、OSCタイプを使っており、16MHzが出力されていますので、コンフィグレーションは、ECに設定しています。

簡単なモニタ機能でSDカードの操作をしてみる
いきなりSDカードの操作プログラムを作ってデバッグをする・・・という開発アプローチは、PICでは感心しません。モニタを使うと、I/Oポートの入出力、内部レジスタの設定ができるので、これらを組み合わせてSDカードを操作することができます。PIC18F2550と、SDカードとの接続は以下のようになります。また、PICの電源は、3V付近にします。
PIC18F2550ポート PICピン番号 SDカードピン番号 SDカードの信号の意味 プルアップ
GND 19 3と6 GND -
VDD 20 VDD -
SDO 出力(RC7) 18 CMD(DI)入力 22kでプルアップ
SDI 入力(RB0) 21 DAT0(DO)出力 22kでプルアップ
SCK 出力(RB1) 22 CLK 入力 -
RB2 出力(RB2) 23 CS 入力 -

PIC18F2550基板と、SDカードソケット。サンハヤト SK-29
PIC基板上部はPICkit2用6ピンコネクタ

PICでSPIを使うには、ポートが決められており、上記のようになります。モニタを使ってこれらのポートの入出力を設定し、SPIモードの設定すると、あとはSPIの送受信レジスタ、SSPBUF(0xFC9番地)に書くことで、SDカードにコマンドを送れます。

ポートの初期設定

ポートCの、RC2,RC1,RC0は、すでにシリアルで使っているので、同じ設定にします(ビット列で、001)
PIC18F2550ポート レジスタ名 アドレス 設定データ
ポートC、RC7 出力 TRISC 0xF94 0x79
ポートB、RB0 入力 TRISB 0xF93 0xF9
ポートB、RB1 出力 TRISB 0xF93 0xF9
ポートB、RB2 出力 TRISB 0xF93 0xF9
PICの内臓周辺回路、MSSPを、SPIに設定します。
レジスタ名 アドレス 設定データ 設定の意味
SSPSTAT 0xFC7 0x00 送信データは、クロックの立下りで更新
SSPCON1 0xFC6 0x32 SPIをマスターモードに設定。クロックは、Foscの1/64
SSPSTATの、Bit7=0で、Input data sampled at middle of data output time になるので、これらの設定では、クロックの立ち上がりで受信データがサンプルされます。また、Bit6=0で、クロックのアイドル状態はHighになります。
これらの設定をモニタのコマンドで操作すると、以下のようになります。
PIC-Mon>sf94,79 (enter)
PIC-Mon>sf93,f9 (enter)
PIC-Mon>sfc7,0 (enter)
PIC-Mon>sfc6,32 (enter)
これで、SPIモードの初期化が完了

SDカードへのコマンドとレスポンスのタイミング

SPIモードを使って、SDカードの初期化で行う最初のコマンド、CMD0の送信と、そのレスポンスのイメージです。CMD0のコマンドビットはLSB6ビットで、MSB2ビットが01となって、ホストからのコマンドであることをカードに知らせます。コマンドの最初の2ビットは必ず01となっています。それに続く32ビットの引数、0x00000000は、SPIモードでは4バイトの0x00の送信となります。これらに続いてCRC7が7ビット送られ、最後の1STOPビットで、0x95となります。SPIモードでも、最初のCMD0のCRC7は正しくないといけません。7ビットで 1001010 ですが、STOPビットを追加して 10010101 となり、SPIの送信データとしては、0x95になります。
CMD0を送った後、データを0xFFにして送信し、1バイトあたり8クロックを送ると、2〜3バイト目に、レスポンスが返ります。CMD0の場合、レスポンスは0x01となります。SPIモードの最初は、400kHz以下でクロックを送るので、たいてい2バイト目にレスポンスが返ります。
ここで、CRC7の計算ですが、暗算ではとても無理なので、コマンドラインのプログラムとして作ったソースがこちらです。使い方は、C:¥>calccrc 7 40 0 0 0 0 (enter) で、CRC7 = 95 という答えを出します。
SDカードのレスポンスですが、R1と呼ばれる1バイトのレスポンスの意味は以下のようになっています。詳しい資料は、SDカードアソシエーションのSimplified Version of PHYSICAL LAYER SPEC に書かれています。
CMD0のレスポンスは、正常なら0x01になります。

SDカードの初期化で、一番簡単な方法は、CMD0、CMD1を使うもので、次の手順になります。

  1. CSをHighにして、クロックを74個以上出します。これは、SPIに0xFFを10回出すことで行えます。
  2. CSをLowにして、CMD0を出します。(SPIに、0x40、0、0、0、0、0x95を出します。)
  3. SPIで0xFFを出して、受信データを読み、0x01の返答があるまで0xFFを出し、あれば次に進みます。
  4. CSをHighにして、SPIに0xFFを出します。これはダミークロックを出す方法です。
  5. CSをLowにして、CMD1を出します。(SPIに、0x41、0、0、0、0、0x1を出します。)
  6. SPIで0xFFを出して、受信データを読み、0x00の返答を待ちます。
  7. 返答が0x00でないなら、4に戻って返答が0x00になるまで繰り返します。
  8. 0x00の返答があると、SDカードの初期化は終了し、次からセクタのリード、ライトが行えます。
さて、これだけ操作が増えるとモニタのコマンドを手動で行うのはかなり時間がかかるので、パソコンのターミナルソフトに付属する、マクロ機能を使って操作すると、タイプミスによる操作間違いもなくなります。ターミナルソフトのマクロとしては、組み込みでは定番と思われるテラタームのマクロ機能を使います。
SDカードの初期化のマクロはこちら。 sdctl.ttl
初期化の後、先頭セクタ0を読み出し、ヘキサでファイルに残すのがこちら sdctlread.ttl
初期化の後、セクタ番号1に、ヘキサで書かれたファイルをバイナリーで書くのがこちら。 writedata.ttl

4GB以上のSDHC規格のSDカードの場合、CMD0 と CMD1では初期化できません。CMD8、CMD58、CMD55、ACMD41、CMD9などを使います。
SDHCにも対応できるSDカードの初期化は、次の手順になります。
  1. CSをHighにして、クロックを74個以上出します。これは、SPIに0xFFを10回出すことで行えます。
  2. CSをLowにして、CMD0を出します。(SPIに、0x40、0、0、0、0、0x95を出します。)
  3. SPIで0xFFを出して、受信データを読み、0x01の返答があるまで0xFFを出し、あれば次に進みます。
  4. CSをHighにして、SPIに0xFFを出します。これはダミークロックを出す方法です。
  5. CSをLowにして、CMD8を出します。(SPIに、0x48、0、0、0x1、0xAA、0x87を出します。)
  6. SPIで0xFFを出して、受信データを読み、0x01か、0x05の返答を待ちます。
  7. 返答が0x01か0x05でないなら、このカードは使えないか、他になんらかの問題があります。
  8. CMD8にたいして、0x01か0x05の返答がある場合。
  9. CSをHighにして0xFFを送ります。
  10. CSをLowにして、CMD58(0x7A、0、0、0、0、0xFD)を出します。
  11. 0x01の返答が無ければ、9に戻って繰り返します。
  12. 0x01の返答があると、続く4バイトを受信します。4バイトは、0x00、0xFF、0x80、0x00 のはずです。
  13. CSをHighにして0xFFを送ります。
  14. ここから、CMD55、ACMD41のコマンドペアを開始します。
  15. CSをLowにして、CMD55を出します。(0x77、0x0、0x0、0x0、0x0、0x65)
  16. 0x01の返答があると、次に進みます。必ずあるはずです。
  17. ACMD41を送ります。(0x69、0x40、0xFF、0x80、0x0、0x17)
  18. 0x01か0x00の返答があり、0x01なら、CSをHighにして0xFFを送り、14から繰り返します。
  19. 0x00の返答の場合、初期化はほぼ成功ですが、CSをHighにして0xFFを送ります。
  20. CSをLowにして、CMD58(0x7A、0、0、0、0、0xFD)を出します。
  21. 0x00の返答があるはずで、続いて4バイト受信します。
  22. SDHCの場合、4バイトは、0xC0、0xFF、0x80、0x00となるはずです。そうでない場合は、0x80、0xFF、0x80、0x00です。
以上で、SDHCにも対応した初期化が終了します。これら一連の操作を、テラタームのマクロで操作するのがこちらです。sdhcinit.ttl
このマクロを使って操作したテラタームのスクリーンショットです。SDカードはSDHCの8GBのものを初期化しています。こちらは、操作の全体のログです。sdhcinitlog.txt

モニタにSDカードの操作プログラムを追加
簡単なモニタの機能と、ターミナルのマクロ機能を使って、SDカードの基本的な操作ができることが判ったので、これらの結果を元に、モニタにSDカードの操作コマンドを追加します。SDカードの振る舞いが判明しているので、デバッグは主にPICのソフトになります。
SDカードの操作コマンドとして、以下の基本的なものとしておきます。
  1. CMDを指定するコマンド、c
  2. SPIで0xFFを出力して、レスポンスを得るコマンド、r 1回だけの場合と、連続複数回の場合の区別。複数回ではRAMに読む。
  3. SPIで、データを送るコマンド、w 1回だけと、複数回。データは、PICの内部RAMにあらかじめ用意しておく。
  4. カード挿入直後に、CSをHighにして、74(80)回のクロックを出すコマンド、i
  5. CMD送信と、レスポンス受信後にCSをHighにして0xFFをSPIで送信、u
それぞれのコマンドの使い方は、
PIC-Mon>c40,0,95 (enter) で、CMD0を、パラメータ0x00000000で、CRC7が0x95で出す。
PIC-Mon>r (enter) で、0xFFをSPIに出し、受信データをヘキサで表示する。
PIC-Mon>r200 (enter) で、0xFFを0x200回出し、受信データを、RAMの0x200番地以後に書く
PIC-Mon>w4d (enter) で、SPIで、0x4Dを出す。
PIC-Mon>w200 (enter) で、RAMの0x400番地のデータを、順番に0x200バイトSPIに出力する。
PIC-Mon>i (enter) で、CSをHighにして、0xFFを10回SPIで出力する。
PIC-Mon>u (enter) で、CSをHighにして、0xFFを1回SPIで出力する。

以上の機能を追加したアセンブラのソースは こちらです。 pic18fsdt1.asm
約1.8kBほどのコードサイズです。pic18fsdt1.hex

2GBのSDカードを、WindowsXPでFAT16でフォーマットし、その先頭セクタを読み出してみます。
使うコマンドは、初期化が完了しているとして、次のようになります。
  1. c51,0,1 (enter) で、先頭セクタを読み出すコマンドを出します。
  2. r (enter) を数回実行して、レスポンスが0xFEになると、次に進みます。
  3. r200 (enter) で、データを512バイト、RAMの0x200番地以降に読み出します。
  4. r (enter) を2回実行して、CRC16を読んでおきます。
  5. u (enter) コマンドでダミークロックを出しておきます
  6. d200,3ff (enter) で、読み出したデータを表示します。
以下が表示された先頭セクタの内容です。

読み出した先頭セクタの、
M03C0 3B 00 06 3C FC DC F7 00 00 00 09 D7 3C 00 00 00
に注目し、中央近くに F7 00 00 00 という数値がありますが、これは、FAT16のDPB(ディスクパラメータブロック)が存在するセクタ番号を示しています。0xF7セクタは、0x1EE00番地になりますから、このSDカードのこのアドレスを読み出します。この数値の右に、09 D7 3C 00 という並びがありますが、これは右からMSBとして読んで、0x003CD709 という値になり、このSDカードの容量を、セクタ数で表しています。0x3CD709 = 3,987,209 セクタで、約2GBとなります。
  1. c51,1ee00,1 (enter) で、0x1EE00 番地を読み出すコマンドを出します。
  2. r (enter) を数回実行して、レスポンスが0xFEになると、次に進みます。
  3. r200 (enter) で、データを512バイト、RAMの0x200番地以降に読み出します。
  4. r (enter) を2回実行して、CRC16を読んでおきます。
  5. u (enter) コマンドでダミークロックを出しておきます
  6. d200,3ff (enter) で、読み出したデータを表示します。
以下が表示された0xF7セクタの内容です。

このデータには、FAT16で管理する基本情報が含まれていますが、詳しい内容は、ブートの仕組み に解説されているので、ここでは省略します。

パソコンから送信したデータをRAMに書く機能をモニタに入れる
SDカードのデータをRAMに読み出し、メモリダンプで内容を見ることができても、パソコン側にあるデータをSDカードに書くには、w コマンドで書くときのバッファーRAM(0x400番地から0x200バイト)に、そのデータを書いておく必要があります。これはマクロを使って可能かも知れませんが、時間がかかります。そこで、メモリダンプでヘキサ表示したものをターミナル操作で保存しておき、それを逆にPICに送信することで、RAMに書き戻せるような機能を追加します。メモリダンプのフォーマットは、
M0400 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
などとなっていますから、これを受信して、0x400番地から、0x01、0x02、0x03・・・・を書くと、パソコン内のヘキサダンプファイルをRAMに書き戻せます。そこで、次のような仕様で、受信できるようにします。
  1. 受信単位は、1行で0x10バイトのみ。
  2. M のあと、4桁のアドレスが続き、スペースで区切られながら0x10バイトのデータが続くものとする。
  3. データ部分は、例として、”8F ”と、2桁のヘキサ + 1スペース で表現されているものとする。
  4. 0x10バイトのデータの後、”−7D”などと、0x10バイトデータのチェックサムを付けられるようにする。
    例:M0260 11 04 90 10 22 24 C8 80 9D 47 E1 12 98 40 02 21 -15
  5. M で始まるアドレス値は、受信後0x1FFでマスクして、常に0x400〜0x5FF以内に収まるように制限する。
  6. 総受信単位は、512バイトまでとする。0x20行まで。
  7. 受信機能追加に合わせて、メモリダンプにチェックサムを付加して表示できるようにする。
  8. 受信時、チェックサムを無視する場合も設け、またチェックサムが1行でも間違ってると、結果をフラグに残す。
  9. チェックサムは行の最後に行うだけで、途中受信したデータが誤っていたとしても、そのままRAMに書く。
  10. コマンドは、l (enter) または lv (enter) で、コントロールCでいつでも中断できる。lv では、チェックサムを確認する。
  11. 受信コマンドの終了は、パソコンがデータの送信を終わったのを確認して、コントロールCで終了する。
以上のような仕様をモニタに追加したものがこちらです。pic18fsdt2.asm

以下は、機能追加したモニタで、RAMの0x200〜0x400のメモリダンプを行い、そのデータをファイルにして、RAMの0x400番地からロードする操作です。lv でロードして、メモリの比較がOKになった後、ファイルの一部を変更して、再び lv でロードし、メモリの比較で違ってる箇所を表示した例です。

CMD17に対して、0x00の後、いつまでも0xFEを返さないカードがある??
さて、SPIモードでのSDカードの制御ですが、読み出しコマンド、CMD17に対して、0x00のレスポンスはあるものの、データの始まりを示す0xFEのレスポンスが無く、いつまで待ってもデータが出てこないカードがあります。このような場合、もう一度CMD17を出すと、0x00のレスポンスは無いですが、0xFFが数回有った後、0xFEがあり、続いてデータが始まるものがあります。無論これはSPIモードのプロトコルに違反していますが、1回目のCMD17に対して0xFEが無いSDカードでは共通した現象のようです。

このような現象が起こるSDカードの、CSDと、CIDを調べると、CIDの、Manufacturer ID が一致しており、同じメーカーか、あるいはOEM元が同じということが判りました。 また、いづれのカードも、CSDのTAAC(asynchronous part of the data access time.)が0x7Fで、NASCが、0xFFとなっていました。これらはリード時のアクセスタイムを示す値で、NASCが0xFFだと、最悪25.5kクロックかかるという意味のようですが、25.5kクロック与えても0xFEのレスポンスがありませんでした。今のところ、このようなSDカードは2枚まで見つけていますが、同じメーカーの同じ容量のカードでも起こらないものばかりでした。同じメーカーの同じ容量のSDカードで正常に読めるCSDのTAACは、0x7Fではなく、NASCも0xFFではありませんでした。

CCSを使って、C言語で開発 ( CCS PCH C Compiler, Version 4.076 )

 CCS のPIC用Cコンパイラの開発環境が使えるようになったので、これでSDカードを操作するプログラムを作ってみました。PIC18Fシリーズではメモリも多く、リニアアドレスのものは、さらに使いやすくなって、Cコンパイラでの開発も現実味を帯びてきます。ここで使ってるPIC18F2550では、16kワード(32kB)のフラッシュがあるので、かなりのプログラムを書けます。FatFsの移植は、いささか無理っぽいですが、CCSの driver に、fat.c というのが同梱されていて、FAT16 or FAT32 を使えるみたいです。(両方同時使用は不可)

 そこで、fat.c (FAT Filesystem)で操作する解説となると、CCSのライセンスに引っかかるので、ここでは、もっと簡易なものを目指します。つまり、SDカードにあらかじめファイル領域を確保しておき、長さも変更せず、ファイルの中身だけを書き換えるという方法です。こうすると、FAT管理部分や、ディレクトリの書き換えとかが、一切関係なくなるので、かなり小さくできます。その代わり、ファイルの中身で、どこまでどこに書いたか、その情報を自前で管理する必要があります。無論、パソコンで読むときも、特別なソフトが必要になる場合があります。さらにこの方法だと、SDカードに書く回数が激減し、途中で突然電源OFFになっても、FATの管理部分が壊れることはありません。最後のデータが書けないぐらいです。
 また、ファイル情報はあるが、ファイルには何も書いてない状態を作っておく必要があります。ディレクトリと、FAT情報だけをあらかじめ書いておき、ファイルの実体部分は、SDカードのセクタの並びが連続するようにしておきます。このようなファイルシステムの状態のSDカードを作り出すには、Windowsでも特別なソフトが必要になります。物理セクタ番号を直接指定してデータを書くので、ドライブ番号を間違えると、Windowsでは致命傷的に危険なソフトになってしまう為、PICでできるようにします。

CCSで開発するにあたって、いままで説明してきた回路では使いにくいので、
  1. SDカードの操作を、PIC内臓のSPIポートを使うのではなく、ソフト制御のSPIに変更します。
  2. UARTを、ソフト制御ではなく、PIC内臓のESUARTを使えるように変更します。
SDカードとの接続 桃色は、変更したところ。
PIC18F2550ポート PICピン番号 SDカードピン番号 SDカードの信号の意味 プルアップ
GND 19 3と6 GND -
VDD 20 VDD -
出力(RC0) 11 CMD(DI)入力 22kでプルアップ
入力(RB0) 21 DAT0(DO)出力 22kでプルアップ
SCK 出力(RB1) 22 CLK 入力 -
RB2 出力(RB2) 23 CS 入力 -

UARTの接続 桃色は、変更したところ。
PIC18F2550ポート PICピン番号 FA1A4M FA1A4M DSUB9、クロス
PC6 TXD 17 → ベース コレクタ、プルアップ1k 3番ピン、RXD
PC7 RXD 18 ← コレクタ、プルアップ4.7k ベース 2番ピン、TXD


CCSを使って、C言語でSDカード操作モニタをまず作ってみる Version 4.076

CCSは、PIC専用のCコンパイラで、そこそこの機能があり、int1, int8, int16, int32 など、専用のインテジャーで指定します。long は、32ビットではなく、16ビットの int16 とみなされるので、注意が必要です。また、複雑な演算付きの引数だと、コンパイルできないことがあります。( 最新の、Version 4.130 では、かなり修正されているようです )

以下は、モニタのコマンドと、使用例
SDカードの初期化コマンド
PIC18F_MON>Si ここで Enter キーを押します
PIC18F_MON>Si
CMD0: 01
CMD8: 01
CMD58: 00FF8000
ACMD41: 0500
CMD58: C0FF8000
PIC18F_MON>

SDカードのファイルシステム情報を表示する
PIC18F_MON>Sm ここで Enter キーを押します
PIC18F_MON>Sm
MBR_start = 0x00002000, MBR_volsects = 0x00F05800
MBR partiton type = 0x0B
FAT0_start = 0x00002022, FAT_size = 0x00000783 sectors
DIR_start  = 0x00002F28, Sectors per cluster = 0x00000040
file start = 0x00002F68, FAT type   = FAT32   

ここで、MBR_volsects は、このSDカードで使えるセクタ数、
DIR_start は、このSDカードのファイルシステムの、ルートディレクトリの
物理セクタ番号を示しています。この値のセクタを読むと、次の表になります。
その他、FAT32の情報を表示しています。

SDカードの指定セクタを1セクタ読む
PIC18F_MON>Sr2f28,0 ここで Enter キーを押すと、0x2F28 セクタ
をバッファー0に読みます。バッファーの先頭の物理アドレスは0x22です。
PIC18F_MON> と表示した後、
PIC18F_MON>d0,80 ここで Enter キーを押します
これは、バッファーの論理アドレス(物理は0x22)から、0x80バイトのメモリの表示です。
0022 44 30 30 30 30 20 20 20 54 58 54 20 00 00 0A 4C [D0000   TXT ...L]
0032 6A 40 00 00 00 00 0A 4C 6A 40 03 00 00 00 00 02 [j@.....Lj@......]
0042 44 30 30 30 31 20 20 20 54 58 54 20 00 00 0A 4C [D0001   TXT ...L]
0052 6A 40 00 00 00 00 0A 4C 6A 40 03 04 00 00 00 02 [j@.....Lj@......]
0062 44 30 30 30 32 20 20 20 54 58 54 20 00 00 0A 4C [D0002   TXT ...L]
0072 6A 40 00 00 00 00 0A 4C 6A 40 03 08 00 00 00 02 [j@.....Lj@......]
0082 44 30 30 30 33 20 20 20 54 58 54 20 00 00 0A 4C [D0003   TXT ...L]
0092 6A 40 00 00 00 00 0A 4C 6A 40 03 0C 00 00 00 02 [j@.....Lj@......]

PIC18F_MON>

これはちょうど、このSDカードのルートディレクトリのセクタを読んだことになります。
コマンドとして、 d0,80 と、0番地から指定しているにもかかわらず、0x0022 番地から
表示されているのは、d0 では、メモリの0番地からではなく、SDカード用のバッファーの
先頭番地の指定になっているからです。
RAMの0番地から表示したい場合は、dm0,80 と、'm' を付加すると、RAMの絶対番地になります。

SDカードのディレクトリを表示する
PIC18F_MON>Sd ここで Enter キーを押します
PIC18F_MON>Sd
0033554432 00002F68 D0000.TXT
0033554432 00012F68 D0001.TXT
0033554432 00022F68 D0002.TXT
0033554432 00032F68 D0003.TXT
0033554432 00042F68 D0004.TXT
0033554432 00052F68 D0005.TXT
0033554432 00062F68 D0006.TXT
0033554432 00072F68 D0007.TXT
0033554432 00082F68 D0008.TXT
0033554432 00092F68 D0009.TXT
0033554432 000A2F68 D0010.TXT
0033554432 000B2F68 D0011.TXT
0033554432 000C2F68 D0012.TXT
0033554432 000D2F68 D0013.TXT
0033554432 000E2F68 D0014.TXT
0033554432 000F2F68 D0015.TXT

PIC18F_MON>

ここで、左から、ファイルのサイズ(10進)、
ファイルの先頭の物理セクタ番号、ファイル名となっています。
表示できるのは、ルートディレクトリのみです。
この例では、すべて32MBのファイルで、中身は不定です。
つまり、何も書いていないのです。
PIC18F_MON>F10 ( enter ) で作成したものです。
約2分ほどかかります。

このSDカードを、パソコンのコンソールで表示すると、以下のようになります。

その他、モニタの機能として、RAMの表示、変更ができます。( バイト、ワード単位 ) PIC18F2550では、内部レジスタがRAMの後ろの方にマッピングされているので、レジスタの表示、変更も可能です。

上記のCCS用ソース f25mon_120317.cと、ヘッダファイルです。CCSは、Version 4.076
コンパイル済みの PIC18F2550 用のHEXファイル。f25mon_120317.hex
これらいづれもバグが見つかれば修正し、旧バージョンと置き換えています。最初のもの( 2012.3.11 ) では、Sundisk の8GBの初期化ができませんでした。
旧バージョンf25mon_120314.c f25mon_120314.hex ←こちらでは、BUFFALO の32GBでリードエラーとなりました。また、Sundisk の8GBで時々エラーとなりました。いづれも、リードコマンド、CMD17 の後の返答( 0x00 と、0xFE ) 待ち回数が不足していたようです。


ファイル情報だけ書いておいた、中身を書いてないSDカードのファイルに、データを書く

これを行うには、ディレクトリを読んで先頭クラスタから物理セクタ番号を計算し・・・・、という手順は、実は必要がありません。というのは、PICでファイル情報を書くコマンド、PIC18F_MON>F10 ( enter ) は、32MB単位にファイル名を付けて、先頭クラスタ番号をディレクトリに書いていますが、複数のファイルは実際は連続した領域に並んでおり、file start = 0x00002F68 で表示されたセクタ番号から始まっているからです。ですから、ファイルにデータを書くには、0x2F68セクタから順に書いていけばいいことになります。ディレクトリにファイル名を書いたのは、パソコンからファイル名を指定して、読めるようにするためだけです。

小型の装置でSDカードにデータを書き、あとでパソコンで読み出すとき、たいてい専用ソフトを用意するので、ここでもそのような使い方ができるようにデータを書きます。もし、もっと長い名前のファイル名にしたい場合は、ファイルの先頭にその領域を決めておいて、そこに書いておけばいいことです。もちろんパソコンのエクスプローラでは読めませんが、先頭から名前を書けば、テキストエディタで簡単に確認することができます。

さてここで、今までSDカードの操作で使ってきた、1セクタのライトコマンド ( CMD24 ) では、SDカードへの書き込み回数が、FatFs での操作よりは減るものの、SDカード自体にとってはあまり関心しない書き方です。と言うのは、SDカード内部では、16kB〜128kBぐらいの単位で消去とライトをセットにして書き換えているので、書き換えと関係ない部分が、何回も同じデータで上書きされるからです。SDHCタイプでは、同じ場所を書き換えられる回数は、1万回程度とされています。ここで同じ場所というのは、SDカードへのコマンドで指定する物理セクタのことではなく、SDカード内部のマイコンが管理している同じフラッシュメモリの場所のことで、外部からは知る方法がありません。SDカード内部のマイコンは、できるだけライト回数がフラッシュメモリ全体にまんべんなく行われるように管理しています。SSDでは、このことを、ウエアレベリングといって、その方法はSSDの性能を左右するので機密情報のようです。SDカードでも、内部の管理にときどき時間がかかることがあり、ライト後にビジーが解除されるのに200〜300msほどかかります。( SDカードのメーカー、スピード、容量によってかなり差が有ります )

CMD25 連続ライトコマンド
ライトだけを連続で行う場合、CMD25でまとめて行うと、内部で定めたサイズになったときに書き換えが発生し、SDカード内部での書き換え回数も減り、総合的に消費電力も少なくなります。ボタン電池で運用する場合など、電池寿命をのばせます。 ←実際に消費電流を測定してみると、CMD25では、CMD24には無かった振る舞いをして、総合的には、消費電流の時間積は増加しました。CMD25では、0xFCで開始するライトデータの転送が済んだあと、CSをHighにしても、消費電流が減らず、12mAほど流れ続けてしまう結果になり、電池駆動で使う方法としては不向きだと判明しました。2012.4.8
CMD25では、SDカードは以下のような応答をするようです。
  1. CMD25の送信の後、レスポンス0x00を返すと次のコマンドへ。レスポンスを返すまで、内部でイレーズが発生することがあり、時間がかかることがあります。
  2. 0xFC を送信した後、ライトする512バイトを送信します。
  3. 0xFFを送信して、受信したデータのLSBを0x1FでANDした値が0x05なら次へ
  4. 0xFFを送信してレスポンスを読み、0xFFになれば次へ。これは内部での処理が済むと次のデータを送ってもよいという意味です。ここで、内部で、書くべき領域のイレーズが行われることがあります。実際にライトが行われることがあります。
  5. 次に書くべきデータが用意されていない場合、次に進みますが、まだまだデータがある場合は、今まで送ったライトデータが16kb〜128kbになっていれば、次に進み、そうでない場合は、データが用意できた段階で、2に戻ります。この間、このまま放置してもいいようですが、ライト終了の0xFDを送らない限り、ここで電源を切ると、今まで送ったデータは見ることができない領域に書かれているので、破棄されたのと同じです。ですから、ときどき0xFDで終了する必要があります。
  6. 0xFDを送信し、レスポンスが、0xFFになると、ライト完了です。次のライトデータがあれば、1に戻ります。この0xFDを送ると、16kb〜128kb(SDカードによって異なります。)に達していない場合でも、ここで内部でライトを行うようです。
SDカードのコマンドの、ACMD13( CMD55+CMD13)で、内部でイレーズされるブロックサイズ(AUs、アロケーションユニットサイズ)を確認できますが、8GBのSDでは、4MBを示す値が(コードは0x9)書かれており、4MB単位で書き換えが起こると期待しましたが、それには4MBのRAMが必要になり、現実的ではないので、もっと小さい単位のようです。


PICを正規の5Vで動作させるため、基板を新しく作成。 ↑ ここまでの解説では、PICも3.3Vで動作させていた

このために、以下のような変更をしています。SDカードへのPICの出力は、オープンドレインとして、信号線は4.7kで3.3Vでプルアップしています。また、LCDで文字を表示させるため、16文字2行のLCDモジュールを追加しています。( Strawberry Linux 製 )LCDとは、IIC 接続で、PICからの出力はオープンドレインとし、5Vにならないようにしています。LCDのインターフェイスも3.3Vとなっているからです。

SDカードとの接続 桃色は、変更したところ。
PIC18F2550ポート PICピン番号 SDカードピン番号 SDカードの信号の意味 プルアップ
GND 19 3と6 GND -
VDD 5V 20 VDD 3.3V -
出力(RC0) 11 CMD(DI)入力 4.7kでプルアップ
入力(RB0) 21 DAT0(DO)出力 4.7kでプルアップ
SCK 出力(RB1) 22 CLK 入力 4.7kでプルアップ
RB2 出力(RB2) 23 CS 入力 4.7kでプルアップ

全体の回路図は以下です。A/Dコンバーターに接続するコネクタも追加しています。これで、充電中のニッケル水素電池、eneloop の電圧を10ms毎にサンプルして記録を取ろうという計画です。こちらは 2012.4.1 まで表示していた誤りがあった回路図


LCDに文字を表示し、SDカードを右に接続したところ。


新たに作成した基板で、ニッケル水素電池の充電中の電圧をSDカードに記録

記録を取ったニッケル水素電池の充電器は、SANYO製の、NC−MDR02という充電器です。3年ほど前に買ったものですが、現在でもほとんど同じものが売られています。eneloop を使い出すと、他のニッケル水素電池はほとんど使わなくなりました。自己放電が少ないので、たまにしか使わないデジカメでも、しっかりと電池が残ってるので、頼もしい限りです。100Vのプラグのところの特殊ねじ(HDDなどで使われているもの)を外すと、比較的簡単に開けられました。


この充電器は、マイコン制御になっていて、中には小さなスイッチング電源が入ってました。充電器の内部の電極の部分を引っ張り出します。

リード線で引っ張りだして、PICのA/Dコンバーターのコネクタ、1番(計測電圧側 AN0)と6番(GND)に接続します。充電器を100Vに入れて、なくなった電池を装着します。すぐに、PICに接続したターミナルからコマンドを送ります。SDカードは、あらかじめPIC18F_MON>F10 コマンドでファイル情報を初期化しておき、16個のファイル情報を作っておきます。
SDカードの初期化コマンド
PIC18F_MON>Si ここで Enter キーを押します
PIC18F_MON>Si
CMD0: 01
CMD8: 01
CMD58: 00FF8000
ACMD41: 0500
CMD58: C0FF8000
PIC18F_MON>

SDの初期化をした後、FAT32のファイルシステム情報を読みます。
SDカードのファイルシステム情報を表示する
PIC18F_MON>Sm ここで Enter キーを押します
PIC18F_MON>Sm
MBR_start = 0x00002000, MBR_volsects = 0x00F05800
MBR partiton type = 0x0B
FAT0_start = 0x00002022, FAT_size = 0x00000783 sectors
DIR_start  = 0x00002F28, Sectors per cluster = 0x00000040
file start = 0x00002F68, FAT type   = FAT32   

ここまで操作して、電圧記録タスクを起動します。
電圧記録タスクを起動します
PIC18F_MON>l3,1 ここで Enter キーを押します
PIC18F_MON>l3,1

PIC18F_MON>
ここで、
l3.1 は、ロガーを3モード(A/D読み取り、且つSDカードに記録)で開始し、
D0001.TXT ファイルの先頭から記録するという指示です。
タスクを起動するという呼び方は、タイマー割り込みでA/Dを読み取り、バッファーに記録し、
モニタのキー入力待ちの空き時間で、512バイト溜まったか否かをチェックして、
モニタ機能は残したまま、SDカードに記録するからです。
もっとも、モニタで操作できるのは、その処理はメモリ操作のみが対象で、1秒以内に終わる
ものだけです。A/Dコンバーター、SDカードなどの操作はできません。

ログの終了は、
PIC18F_MON>l0 ( enter ) で、モード0を指示するだけです。この指示で、
マルチライト中のCMD25を終了させ、書き残しデータをSDカードにフラッシュします。
突然電源を切ると、書き込み中の最大0x20セクタ(16kB)が書けないことになります。


以下の写真は、充電器が充電完了になった時点を少し過ぎてから、PIC18F_MON>l0 ( enter ) でログを停止したときのもの。最終セクタが、0x130AD 最終電圧が、1494mV で止めています。sect 05 の05は、CMD25コマンドで、5セクタのデータをSDカードに送ったという意味で、CMD25の終了コード、0xFDで締めくくっています。

これらのCCS用ソース f25mon_120325.cと、ヘッダファイルです。CCSは、Version 4.076
コンパイル済みの PIC18F2550 用のHEXファイル。f25mon_120325.hex

実際にデータを記録すると、次のようになりました。生データではわかりにくいので、パソコンでデータ部分を実電圧に換算して、CSVに変換したものを Excel のグラフで表示させたものです。sanyocharger.pdf


押しボタンスイッチによる操作で、スタンドアロンで動作させる
RS232C経由でパソコンで操作できたところで、次は、パソコン無しでロガーの機能を操作できるようにします。記録したデータの解析はパソコンが無いとできませんが、記録そのものは、パソコン無し、且つ電池(単3、4個を想定)で動くと何かと便利です。電池駆動にするには、もう少し改造が必要ですが、(ニッケル水素4個で、4.8Vから4.2Vを作る回路が必要)そのまえにタクトスイッチで操作できるようにします。また、SDカードの消費電流測定のため、2Ωの抵抗をGND側に追加して、精度は低いですが、2Ω両端の電圧を測って、記録を取ってみます。SDカードは、どの操作のとき電流が増えるのかを調べます。2GまでのSDカードでは、CSDのビットを見ると、最大200mAらしいのですが、SDHCでは、CSDを読んでもその規定がありません。SDカードの消費電流は、電池で運用するには見逃せないほど大きいので、実際のところを調査してみます。
以下は、タクトスイッチ4個と、1Ωの抵抗2個を付けた状態です。

データロガーでは、時間の管理精度が要求されるので、「だいたい10ms」というこれまでの制御から、水晶の精度にまで高めるため、タイマーの扱いを変更します。タイマーのプリスケーラは、2のn乗倍しかできないので、次のような設定に変えます。
  1. プリスケーラを64分周にして、16000000/4/64 --> 62500 Hz でカウンタを駆動。
  2. カウンタを125カウントでオーバーフローさせるため、プリセットを、256 - 125 = 131 にします。
  3. 62500/125 --> 500 Hz となって、2msで割り込みが発生します。
  4. 2msの割り込みインターバルから、最短2msから、4ms、10ms、20ms、50ms、100ms、・・・・などの選択を可能にします。
    SDカードにライトするインターバルの制約を、1秒以上にするため、2msの場合は、8ビットデータになります。SDカードの電流測定の場合、2Ωの抵抗の両端電圧が低いので、LSB8ビットの記録でフルスケール0xFFを超えることはありません。
とりあえず、2msのサンプリングで、SDカードの電流記録を6時間ほど取ってみると、KINGMAX製8GBのSDカードでは、以下のようになりました。2msで1バイトの記録で、6時間ですから、3600*6*500−−>10.8Mバイトになりました。

記録に使ったソース。インターバルは2ms固定、8ビット記録 f25mon_120407.c  押しボタン操作は途中
ヘッダファイル HEXファイル。f25mon_120407.hex
2msでSDカードの消費電流を記録
測定の項目 測定結果
最大ピーク電流 87mA
通常ライト中の電流。約2m秒間 約50mA
最大ライトビジー時間/1セクタ 170msec
データ転送中の電流 SPI 転送 約12mA
データ転送中の時間 SPI 転送 約32 m秒/1セクタ(1秒に1回)
6時間の総合mAh 3.1mAh (11256mA*秒)

記録を見ると、1セクタ書くのにSPIで転送しますが、170kHzのソフトクロック転送で、これに約32m秒かかり、このとき12mAほど流れ、転送後に約50mA(2m秒間)流れています。その後、CSがHighで、電流はほとんど0になります。ログでは0で詳細はわかりませんが、デジボルで測定すると約300μVになります。初期化後のSDカードのスタンバイ電流はわずかで、この例で150μAです。
転送後、ライトビジーが発生しますが、この時間はほとんどが短く2m〜4m秒ですが、ごくたまに170m秒かかる場合があり、このとき電流も大きくなり、平均で60mA、最大で87mAとなります。このようなライトは、10Mバイト中で、約60回ほどありました。
以上のような結果になりましたが、SDカードのメーカーによってかなりばらつきがあります。このSDカードでは、最大87mAでしたが、200mA近くながれるものもあり、ボタン電池駆動の装置では対策が必要です(PIC18Fでは無理か)。それにしても、この程度のデータレート(500バイト/秒)なら、6時間で3.1mAhぐらいだと判明しました。16MHzで動作させるPIC18F2550の消費電流よりかなり低いです。

3種類のSDカードで、電流を測定して、電流が増加する部分を抜き出したもの。




工事中


PIC24FJxxを、無償版のCコンパイラ、C30で開発

PIC24Fは、マイクロチップのMPLABで使えるC30( オプティマイズレベルが低い、無償版のCコンパイラでも )で開発すると「 同等のマイコンの中でコード効率が良い 」というWebのサイトを見つけ、さっそく試してみることにしました。
以前買っておいた PIC24FJ64GB002 を使い、とりあえず簡単な基板を作成しました。 PIC24FJ64GB002 はUSBのホスト機能があるのですが、とりあえずUSBは使わないので、水晶は、7.3728MHzの発信器にしています。その他、簡易RS232Cポートを付けています。これでC30を使って、簡単なプログラムのテストをしてみようと思います。なぜ7.3728MHzなのかは、次の説明する、MicroChipの評価基板と合わせるためです。それと、たまたま7.3728MHzの水晶発信器があったからです。この周波数だと、ボーレートがきっちり合い、タイマー割り込みもおよそではなく、きっちり合います。

マイクロチップから、28ピンの PIC24F の スターターキットのデモソフト から、 (16-bit 28-pin Starter development Board Software ) 16-bit 28-pin Starter Board Software v2.zip をダウンロードしてきます。これを解凍すると、この中に、24F Project.zip があって、これをさらに解凍すると、Eg1_BlinkLED.c というLED点滅と、RS232Cのテストができるソースがあります。これを改造します。

使っているのが、PIC24FJ64GB002 なので、PICの機種をインクルードするところを変更してコンパイルするまではエラーなしでしたが、フラッシュに書こうとして、pickit2 の選択がグレーになっていて選択できない状態になっていました。サポートデバイスを確認すると、PIC24FJ64GA002 はありましたが、PIC24FJ64GB002 がありません (;´Д`)
そこで、pickit3 に変更し、プロジェクトファイルも 変更すると、書き込みはできるようになしましたが、どうも様子がおかしいのです。動作周波数が指定通りにならず、ボーレートが合っていないのです。いろいろ試したところ、コンフィギュレーションの指定で、次の行を追加すると、やっとボーレートが合い、LEDの点滅スピードも合いました。
_CONFIG2(IESO_OFF & FNOSC_PRI & FCKSM_CSDCMD & OSCIOFNC_OFF & IOL1WAY_OFF & I2C1SEL_SEC & POSCMOD_XT);
この CONFIG2 で、FNOSC_PRI は、PLLを使わない指定です。以下は Eg1_BlinkLED.c を改造した、LED点滅と、UARTのテストができるソースです。水晶は7.3728MHzとなっています。


基板は、以下のようにACアダプタの5Vから3.3Vを供給できるようにしています。4Hzで割り込みが入り、LEDが点滅しています。UARTは、[a] をPICに送ると、["a" ] を送り返します。UARTの送信は、17ピン(RP8)、受信は、18ピン(RP9)で、評価基板に合わせています。クロックだけ、水晶振動子ではなく、発信器になっています。9ピンに入力しています。20ピンには、10μFのコンデンサの+を接続し、20ピンをGNDとしています。

この写真では、3.3V7.3728MHzの水晶発信器にしていますが、全体で、約9mAほどです。この水晶発信器が約4.5mA(かなり古いIC)は流れているので、CPUとしては、4.5mAほどになります。4.9152MHzの振動子に変えると、約3.2mA。2.4576MHzで約1.7mAほどの消費電流になりました。ボタン電池駆動も可能なレベルです。2V以上で動作するので、LR44を2個か、空気電池2個で運用できそうです。

この基板に、SDカード操作と、モニタを移植して操作したものが以下です。水晶は2.4576MHzとしています。ソースはこちら→ p24gbmon.c

最初に電源ONの起動メッセージ、次が、SDカード初期化 "Si" コマンド、2000セクタを、メモリ0x1000番地にリード "Sr2000,1000,1"、メモリの0x1000番地から128バイトの表示 "d1000" と続きます。この操作例では KINGMAX の microSD 8GB を使っています。0x2000セクタは、FAT32の情報を記録した場所になっています。


上記SDカードモニタを走らせる回路図です。




64GBのSDカード、SDXCを操作してみた

以前から、SDXC規格のSDカードが店頭にならべられているのを見かけましたが、何万円もするので手が出ませんでした。今日( 2012.5.20 ) KINGMAX の64GBのSDXCを見つけ、8千円台だったので、思わず衝動買いをしてしまいました。SDXCのカードリーダーはすでにあったので、何か書けば読めるだろうと試しましたが、まず、開発に使用しているパソコンが、WindowsXP、且つSP2と、骨董品みたいなので、EXFAT でフォーマットされたカードが読めず、「フォーマットしますか?」とたずねられてしまいました。写真参照。


そこで早速 MicroSoft から、EXFAT に対応したBIOSにアップグレードして、アクセスできるようになりました。PIC24Fでも試しましたが、初期化はできているようなのに、以下のように、CSDが正しく読めていない様子です。サイズがとんでもない大きさになっています。CSD情報の、FE の右8バイト目から、01 E2 BD という数値がありますが、これがSDカードのサイズを示しており、0x1E2BD x 512kB がサイズのはずです。計算すると、61GBほどになります


PIC24Fのモニタを調べると、SDXCのサイズになると、正しく計算されていないことがわかりました。修正後のモニタのソースはこちらです→ p24gbmon_sdxc.c
修正後のモニタで、操作した例が以下です。0セクタ、0x8000セクタを読んで表示させ、その後、0x78A7800 セクタの先頭から0,1,2,3と書いて、読めるかを確認しています。




工事中


RX62N こちらは随時追加→RX62NのSPIでSDカードを制御
ホーム に戻る
inserted by FC2 system