ELMさんが 公開されているFATファイルシステム・モジュールをR8C用に移植してみました。 FatFsは非常によくできています。少し修正するだけで様々なプラットフォームに 移植することができます。今回は以下の条件を想定します。 古いバージョンのFatFsなので多少変更がでているかもしれません。
項目 | 条件 |
---|---|
コンパイラ | KPIT GNU v0801 |
FatFs | FatFs R0.06 |
メディア | SD/MMC |
デバイス | R8C/2A |
シリアルI/F | USART2 |
CS | p6_0 |
DI | p6_3/TXD2 |
DO | p6_4/RXD2 |
CLK | p6_5/CLK2 |
WriteProtectSW | なし |
CardDetectSW | なし |
if (c == 'c') { /* Type is character */ /* どうやら、KPIT_GNUでは va_arg に char を渡すとエラーらしい。 int に修正 */ cc = fputc(va_arg(arp, int), fil); if (cc != EOF) cc = 1; continue; }
下位レイヤのプログラムはELMさんのFatFsサンプルプログラム(mmc.c)を少し修正しただけです。 基本的には(Platform dependent)の項目を修正するだけです。
ポート関連の項目です。CS信号の制御マクロを修正します。 今回、SOCKWPとSOCKINSは使用しないので適当に処理しておきます。
/* Port Controls (Platform dependent) */ #define SELECT() p6_0 = 0 /* MMC CS = L */ #define DESELECT() p6_0 = 1 /* MMC CS = H */ #define SOCKPORT p6 /* Socket contact port */ #define SOCKWP 0x00 /* Write protect switch (not use) */ #define SOCKINS 0x00 /* Card detect switch (not use) */
UART2モジュールを介してMMCにアクセスします。受信完了フラグRIは、 u2rbレジスタをリードしないとクリアされません。なので、 読み出し開始前にu2rbレジスタを空読みします。 また、u2rbレジスタはワードアクセスが推奨されています。
/*-----------------------------------------------------------------------*/ /* Transmit a byte to MMC via SPI (Platform dependent) */ /*-----------------------------------------------------------------------*/ #define xmit_spi(dat) u2tbl=(dat); while( txept_u2c0==0 ) /*-----------------------------------------------------------------------*/ /* Receive a byte from MMC via SPI (Platform dependent) */ /*-----------------------------------------------------------------------*/ static BYTE rcvr_spi (void) { WORD d = u2rb.word; u2tbl = 0xFF; while ( ri_u2c1==0 ); return (BYTE)u2rb.word; } /* Alternative macro to receive data fast */ static void rcvr_spi_m (BYTE* dst) { WORD d = u2rb.word; u2tbl = 0xFF; while ( ri_u2c1==0 ); *dst = (BYTE)u2rb.word; }
今回、SD/MMCの電源管理はしないので、 UARTモジュールの初期化終了処理のみ記述しておきます。
/*-----------------------------------------------------------------------*/ /* Power Control (Platform dependent) */ /*-----------------------------------------------------------------------*/ /* When the target system does not support socket power control, there */ /* is nothing to do in these functions and chk_power always returns 1. */ static void power_on (void) { for (Timer1 = 3; Timer1; ); /* Wait for 30ms */ p6.byte = 0x05; //P6[0,3]=1 pd6.byte = 0x6f; //P6[0-3,5,6]出力ポート u2mr.byte = _BV(SMD0); //クロック同期式シリアルI/O u2brg.byte = 0; //クロック分周なし u2c0.byte = _BV(UFORM); //SPI Mode0 MSB first u2c1.byte = _BV(TE) | _BV(RE); //送受信許可 } static void power_off (void) { SELECT(); /* Wait for card ready */ wait_ready(); release_spi(); u2c1.byte = 0; /* Disable SPI function */ p6.byte = 0x00; Stat |= STA_NOINIT; /* Set STA_NOINIT */ } static int chk_power(void) /* Socket power state: 0=off, 1=on */ { return 1; }
今回、ライトプロテクトSWとカード検出SWは使用しないので、該当部を削除します。 また、この関数は割り込み処理から10msおきに呼び出す必要があります。
/*-----------------------------------------------------------------------*/ /* Device Timer Interrupt Procedure */ /*-----------------------------------------------------------------------*/ /* This function must be called in period of 10ms */ void disk_timerproc (void) { BYTE n; n = Timer1; // 100Hz decrement timer if (n) Timer1 = --n; n = Timer2; if (n) Timer2 = --n; }
以下の設定でのコンパイル後のサイズは10351バイトでした。 今回使用したソースファイルを置いておきます。
項目 | 設定 |
---|---|
_MCU_ENDIAN | 1 |
_FS_READONLY | 0 |
_FS_MINIMIZE | 0 |
_USE_STRFUNC | 0 |
_USE_MKFS | 0 |
_DRIVES | 1 |
_MULTI_PARTITION | 0 |
_USE_FSINFO | 0 |
_USE_SJIS | 1 |
_USE_NTFLAG | 1 |