さて、LCDも何とか動くようになったので、避けては通れないSDカードのアクセス
をやってみたいと思います。
先日 Flash が64Kある事が判ったので、RAM容量は心細いですが、
SDカードアクセスに不安はありません。
組み込みでSDカードと言ったら ChaN さんでしょうー、えるむさんが実装して、ソース
を公開しているSDカードのソリューションは非常に柔軟性があり、細部まで良く考えら
れており、組み込みマイコンにおけるSDカードスタンダードだと思います。
少ないリソースでも動作するように、プチ fatfs もあり、今回のR8Cに最適な
ソリューションです。(感激!感謝です!)
SDカードですが、FlashAir を使えるように、標準SDカードソケットを使います。
標準SDカードソケットなら、直接ユニバーサル基板にハンダ付けできますが、スイッチ
関係のパッドが狭く、その部分は、絶縁テープで保護して、直接配線します。
SDカードソケットは、ヒロセ製(DM1B-DSF-PEJ)を使いました。
このソケットは、価格は高いですが、機能と品質が非常に優れています。
事前に考えておかなければならない点として、ポートにどのように、各信号を割り当てる
かです。
まず・・
・「/RESET(3)」は、ポートにも割り当てが出来るけど、一応キープ。
・「MODE(8)」端子は当然のようにキープ。
・「TXD(16)、RXD(15)」もシリアル通信で必須なのでキープ
・「AN0(20)、AN1(19)、AN2(18)、AN3(17)」は、とりあえずキープ
・「XIN(6)」は、高精度なクロックを入れて使う場合があるのでキープ
・「TRJIO(13)」は、周期測定用としてキープ
// P4_2(1): LCD_SCK ,SD_CLK(5) // P3_7(2): LCD_/CS // /RES(3): (System reset) // P4_7(4): ,SD_DO/DAT0(7) // VSS:(5) (Power GND) // P4_6(6): XIN (高精度なクロック用) // VCC(7): (Power +V) // MODE(8): (System mode) // P3_5(9): I2C_SDA // P3_4(10): ,SD_/CS(1) // P1_0(20): AN0 (keep) // P1_1(19): AN1 (keep) // P1_2(18): AN2 (keep) // P1_3(17): AN3 (keep) // P1_4(16): TXD0 // P1_5(15): RXD0 // P1_6(14): LCD_A0 (share) // P1_7(13): TRJIO (keep) // P4_5(12): LCD_SDA ,SD_DI/CMD(2) // P3_3(11): I2C_SCL
こんな感じになりました、これで、ほぼ全てのポートが埋まりました。
「P1_6(16)」は、Flash 書き込み時に使うので注意が必要です。
※無難な、LCD_A0(コマンド/データ切り替え信号)にしています。
※AN0、AN1、AN2、AN3 はアプリによって自由に使えるポートとしています。
※電源は3.3Vで動かします!
R8Cは3.3Vで動かしても、20MHzで動作します、フラッシュプログラムも問題なくできます。
ぷち FatFsはソースコードを展開して、pffconf.h で基本的な設定を行います。
/*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ #define _USE_READ 1 /* Enable pf_read() function */ #define _USE_DIR 1 /* Enable pf_opendir() and pf_readdir() function */ #define _USE_LSEEK 1 /* Enable pf_lseek() function */ #define _USE_WRITE 1 /* Enable pf_write() function */ #define _FS_FAT12 1 /* Enable FAT12 */ #define _FS_FAT16 1 /* Enable FAT16 */ #define _FS_FAT32 1 /* Enable FAT32 */
とりあえず、全て「1」で良いでしょう。
FAT12、FAT16 は「0」でも問題は少ないですが、古いSDカードは「FAT12」や「FAT16」
でフォーマットされており、それらを使う必要があるなら「1」にする必要があります、
但し、実行バイナリーは多少大きくなります。(おおよそ1Kバイト増加)
※FAT32でフォーマットをやり直せば、使える物もあるかと思います。
/*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ #define _USE_LCC 1 /* Allow lower case characters for path name */ #define _CODE_PAGE 932
「_USE_LCC」を「1」にして
コードページは932にしておきます。
Sample プロジェクトの generic を参考に、「diskio.c」シリアル/パラレル変換の部分を書き換えます。
自分のシステムでは、I/O ポートの制御部分は C++ のクラスで構成されているので、
「diskio.cpp」として、メインのポート定義「port_def.hpp」を使って、実装します。
※port_def で宣言しているポートクラスの実体は、「diskio.cpp」で宣言していますが、
このクラスは、最適化されインラインで組み込まれるものと思います。
他に、「マイクロ秒」単位の時間待ちルーチンが必要で、「common/delay.hpp」に該当する
関数があるので、それを使います。
※「utils::delay::micro_second(n);」
// マイクロ秒単位の、「時間待ち」 static void dly_us(unsigned int n) /*-----------------------------------------------------------------------*/ /* Transmit a byte to the MMC (bitbanging) */ /*-----------------------------------------------------------------------*/ static void xmit_mmc(BYTE d) /*-----------------------------------------------------------------------*/ /* Receive a byte from the MMC (bitbanging) */ /*-----------------------------------------------------------------------*/ static BYTE rcvr_mmc(void) /*-----------------------------------------------------------------------*/ /* Receive a byte from the MMC (bitbanging) */ /*-----------------------------------------------------------------------*/ static BYTE rcvr_mmc()
基本的に以上の4つの関数を実装すれば良く、他に、元のソースでは、コマンド
の定義を、「#define」で行っていたので、「static const BYTE」に換えました、C++
では、この定数は、コンパイル時にのみ使われ、メモリー上に置かれる事はありません。
これで完了です。
簡単なテストとして、カードをマウントして、ディレクトリーをリストしてみます。
FATFS fatfs; bool mount = false; // pfatfs を開始 { if(pf_mount(&fatfs) != FR_OK) { sci_puts("SD mount error\n"); } else { sci_puts("SD mount OK!\n"); mount = true; } } if(mount) { DIR dir; if(pf_opendir(&dir, "") != FR_OK) { sci_puts("Can't open dir\n"); } else { for(;;) { FILINFO fno; // Read a directory item if(pf_readdir(&dir, &fno) != FR_OK) { sci_puts("Can't read dir\n"); break; } if(!fno.fname[0]) break; if(fno.fattrib & AM_DIR) { utils::format(" /%s\n") % fno.fname; } else { utils::format("%8d %s\n") % static_cast<uint32_t>(fno.fsize) % fno.fname; } } }