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 |