今回はSPIです。SPI通信する周辺機器にSDカードが有ります。今回はSDカードへのデータの読み書きを目標にします。
まずはハードから
以下は今回使用したSDカードリーダーです。アマゾンで買いました。
回路と実際は以下の通り。

- 追加部分は青い四角で囲まれた部分です。
- 今回使用するのはSDカードリーダーとLED部です。その他は無くても動きます。
- SDカードリーダーとPICは下記の4本と GND 2本、 3.3V 1本の計7本をケーブルでつないでいます。
| リーダー側 | PIC側 | 
|---|---|
| CS | RB10 | 
| MISO | RB13 | 
| SCK | RB12 | 
| MOSI | RB11 | 
次はソフト
いつも通り、PIC24FJ64GA002 用プロジェクト名 ”SPI” で空のプロジェクトを作成して下さい。作成後MCCを起動して下さい。

- Device Resourcesの欄で SPIをクリック。その中の SPI1 を選択すると
- Project ResourcesにSPI1が追加されます。
- 今回はSystem Moduleを変更します。データの読み書きを想定しているのでMAXクロックに設定します。
- FRC Postscalerにチェック。
- Postscalerを1:1
- PLL Enableをチェック。これでMAXクロック Fosc=32MHzになります。
この画面でPIN Managerタブをクリックしてピンの割付を行います。
- RB10はCS GPIO 出力
- RB11はSPI MOSI 出力
- RB12はSPI SCK 出力
- RB13はSPI MISO 入力
- RB15はLED点滅用 GPIO 出力
続いてSPIの詳細を設定して行きます。

- Project ResouecesのSPI1をクリック。右側に設定画面が表示されます。
- Enable SPIをチャック
- 8ビットを選択
- Primary Prescalerを1:1を選択
- Secondary Prescaler を1:1を選択 これで、SPIの周波数は16MHzになります。
- ここで、Pin Moduleを選択してピンの状態を再確認します。
- 右側にピンの状態が表示されます。PR10,11,12,15が出力になっている事を確認
- 最後に、Generate ボタンを押して終了です。
コードはいつも通り、MCC Generated Filesフォルダーに保存されます。そこに SPI1.c というファイルが有ります。これが今回作成されたSPI用のファイルです。

- 170行: uint8_t SPI1_Exchange8bit( uint8_t data )
- SPI通信用関数。1バイト送信用
- 相手からのデータを返す
 
- 179行: uint16_t SPI1_Exchange8bitBuffer(uint8_t *dataTransmitted, uint16_t byteCount, uint8_t *dataReceived)
- SPI通信用関数。複数バイト送信用
- 相手からのデータを返す
 
この2つの関数を使ってSPI通信を行います。
SDカード読み書き用のソフト
SDカード読み書き用のソフトがなかなか見つかりません。本家のMicrochipのHPにそれらしきソースを見つけましたが容量が大きくてPIC24FJ64の64Kbyteではメモリーが足らない様です。
以前(かなり前)MicrochipがFAT16対応の比較的サイズの小さいソースを公開していた事を思い出しHPを探したのですが流石に有りませんでした。当時ダウンロードしたのですが、度重なるOS更新時に無くしてしまった様です。
そこで、PICの聖地 ”電子工作の実験室” に行ったら有りました。本体は MP3プレーヤー ですが、曲データをSDカードから読み出しています。それに嬉しい事に使っているPICはPIC24Fです。そこでSDカードに関係する部分のみ抜き出してソースを見て行くと、SDカードとの通信部分のみ今回MCCで作成したコードに置き換えれば動くように見えます。そしてそこを修正したら見事に動きました。実はその他にも修正箇所が有るのでソースを見ながら説明します。
必要なソース
必要はソースは下記の7つです。
| ファイル名 | 説明 | 
|---|---|
| FSIO.c | ファイルシステムの中心ファイル。 | 
| FSIO.h | そのヘッダーファイル。 | 
| SD-SPI.c | SDカードとPICの通信用ファイル。 | 
| SD-SPI.h | そのヘッダーファイル。 | 
| FSconfig.h | Memory Disk Driveの指定。ファイル機能の設定する為のヘッダーファイル | 
| FSDefs.h | ファイルシステム状態パラメータ用ヘッダーファイル | 
| GenericTypeDefs.h | PIC PIN 定義ヘッダーファイル。 | 
以下に主な変更点を説明します。
SD-SPI.c :PICとSDカード間の通信を行うソース。

- SDカードに書き込む部分を修正しました。- unsigned char WriteSPIM( unsigned char data_out )
 - コメント部分(/* */で囲われた部分)がオリジナルのコードです。
- 1バイトの引数をSPIを使ってSDカードに送る
- 送信が完了すると、”0”を戻り値として返す
- 戻り値は呼び出した関数では使われない。
 
- uint8_t SPI1_Exchange8bit( uint8_t data )関数がこれと同じ働きをします
- retrunを使ってSPI1_Exchange8bit()の戻り値をWriteSPIM()の戻り値に使用。
 
 

- SDカードからの読み込み部です。
- BYTE ReadMedia(void)
- コメント部分(/* */で囲われた部分)がオリジナルのコードです。
- ダミーで1バイト(0xFF)を送る。
- SDカードからデータが送られて来るとそれを返す
 
 
- uint8_t SPI1_Exchange8bit( uint8_t data )関数で以下の様に代用
- SPI1_Exchange8bit( ) にダミーの引数 0xFFを与える。
- 帰って来た戻り値をそのままReadMedia()関数の戻り値に使用
 

- メディア検出部の削除:BYTE MediaDetect()
- このソフトはハードがSDカードの挿入を検出する機能を持っている事を前提としています。
- 今回のハードのその機能が無いので、関係する箇所をコメントアウトしています。
- SD_CD_TRIS:検出用ピンのIO設定用変数
- MediaDetect():検出関数
 
- よって、カードの検出機能は有りません。リーダーにカードが入っている事が前提です。
 


- ライトプロテクトの編集- このソフトはハードがSDカードのライトプロテクトを検出する機能を持っている事を前提としています。
 - 今回のハードのその機能が無いので、関係する箇所を修正しています。
- SD_WE_TRIS:検出用ピンのIO設定用変数ー>コメントアウト
- BYTE WriteProtectState(void):検出関数
- この関数は他の部分で使用されているためコメントアウト出来ない。
- 戻り値に 0 を返し、プロテクトがかかっていない状態にしている。
 
 
- よって、カードの検出機能は有りません。プロテクトがかかっていない事が前提です。
- つまり実際にライトプロテクトがかかっていてもかかっていないと判断します。
 
SD-SPI.h
ハードの設定を行っています。CSやSPI用の各ピンはここで設定されています。

各変数とピンの対応は以下の通り。
| 説明 | 定数 | 設定 | 
|---|---|---|
| チップセレクトピン | SD_CS / SD_CS_TRIS | RB10を指定 | 
| メディア検出用ピン | SD_CD / SD_CD_TRIS | コメントアウト | 
| ライトプロテクト検出用ピン | SD_WE / SD_WE_TRIS | コメントアウト | 
| SPI クロック (SCK) | SPICLOCK | RB12を指定 | 
| SPI MISO | SPIIN | RB13を指定 | 
| SPI MOSI | SPIOUT | RB11を指定 | 
FSIO.h
PICに合わせてファイルを読み込む部分があるのですが、オリジナルでは <p24fxxxx.h> となっていました。コンパイルでファイルが無いとエラーになったので、PIC24FJ64GA002.hに変更しました。他のPICを使う時は注意が必要です。

FSconfig.h
このファイルは#define文のコメントを外す事でFATの機能(FORMATとかWRITE等)設定出来ます。

- オリジナルは73行でSYSTEM_CLOCKを定義しています。これをコメントアウト
- この定数はソフトの中でDelayを作る時に使用されています。
 
- システムクロックは、MCCが作成した system.h の中に _XTAL_FREQ と定義していたのでそれに変更
以上が変更箇所です。多い様に見えますが仮にこのソースを使って PIC24FJ64GA002 で独自の回路を設計した場合、SD-SPI.hファイルのピンアサイン部分のみ変更すればSDカードへの読み書きが出来ます。
簡単な検証プログラム
簡単な検証プログラム main.c を書きました。動作は
- 57行: 実行と共にLEDを点灯
- 59行: FAT操作用関数の初期化を行う
- 61行: 新しいファイル ”SPI_TEST.TXT” を書き込みモードで作成
- 62,3行:そのファイルにテキスト ”12345″ を書き込んでファイルを閉じる
- 65行: ”SPI_TEST.TXT” を追加書き込みモードで開く
- 66,7行:そのファイルに ”\nABCDE” テキストを追加して閉じる
- 69,70行:フォルダー ”SPI_SUB” を作成しそこに移動
- 71行: 新しいファイル ”SUB_SPI.TXT” を書き込みモードで作成
- 72,3行:そのファイルにテキスト ”XYZ12″ を書いて閉じる
- 75行: 最後にLEDを消灯して終了

このプログラムを実行しLEDの点灯、消灯を確認。その後SDカードの中身を確認するとプログラム通り処理された事がわかります。

- 2GBのSDカードを使用してのですが、確かにファイルとフォルダーが作られています。
- まずSPI_TEXT.TXTの中身を見ると、最初に書いた ”12345”とその後追加した ”ABCDE”が確認出来ました。
- 続いて SPI_SUBのファオルダーに移動、
- ”SUB.TXT” ファイルが有り
- その中身を見ると、”XYZ12″ と書かれています。
FAT16なのでいくらか制約が有ります。下記は思いつく制約と対策です。
- 問題: 使用できるMAX容量が2GBまでとなります。
- 対策: 容量的に少ないですが、ちょっとしたデータの保管なら十分な容量と思います。
- 問題: フォーマット形式もFTA16に限定されます
- 対策: 専用にフォーマットを行えば(今回はGparteを使いました)問題有りません。
今回は書き込みのみでしたが、当然読み込みも出来ます。今回のプロジェクトと若干違いますがFATの説明書をここに保存しました。
今回のプロジェクト   SPI_SD_Card
資料          Implementing File I/O Functions Using Microchipís Memory Disk Drive File System Library
興味の有る方は覗いて下さい。今回のプログラムでPIC24FJ64GA002のメモリー約36%使用しています。残り60%強です。これだけ有れば、かなりのプログラムが書けます。
次回は
次回は、パワーセーブ関係の話をしたいと思います。
