Top > TOPPERS >FatFsの移植

FatFsの移植

 ELMさんが 公開されているFATファイルシステム・モジュールをTOPPERS用に移植してみました。 TOPPERS用のFatFsも公式ホームページにて公開されていますが、ターゲット システムが限定されているようなので、H8用にFatFsのサンプルプログラムを 基に修正しました。 基本的にはR8C/ELMさんのFatFsと同様、 たいしたことはしていません。本プログラムは以下の環境を想定しています。

項目条件
OSTOPPERS/JSP Release 1.4.3
SystemAKI H8 3069f
MediaSD/MMC
FatFsFatFs R0.07a
排他制御しない
SCISCI2
PortPortB
CSPB0

下位レイヤI/F

 下位レイヤのプログラムはELMさんのFatFsサンプルプログラム(mmc.c)を少し修正しただけです。 基本的には(Platform dependent)の項目を修正するだけです。

インクルードとレジスタ定義

 システムレイヤーにアクセスするため、s_services.hを、 ビット操作を行うためのインライン関数を使うためにcpu_insn.hを インクルードします。また、H8はポートディレクションレジスタが 書き込み専用であるために、&=や|=といった操作ができない。 この問題を回避するためのバッファアクセス関数が用意されているので h8_sil.hもインクルードします。

#include <s_services.h>
#include <cpu_insn.h>
#include <h8_sil.h>
#include "diskio.h"

//レジスタアドレス定義
#define	H8MMC			H8SCI2
#define	H8MMC_TDR		(*(volatile UB*)(H8MMC + H8TDR))
#define	H8MMC_RDR		(*(volatile UB*)(H8MMC + H8RDR))
#define	H8MMC_SSR		(*(volatile UB*)(H8MMC + H8SSR))
#define	H8MMC_SCR		(*(volatile UB*)(H8MMC + H8SCR))
#define	H8MMC_SMR		(*(volatile UB*)(H8MMC + H8SMR))
#define	H8MMC_BRR		(*(volatile UB*)(H8MMC + H8BRR))
#define	H8MMC_SCMR		(*(volatile UB*)(H8MMC + H8SCMR))
#define H8SCMR_SDIR_BIT		3
#define H8SCMR_SDIR		(1<<H8SCMR_SDIR_BIT)

Port controls

ポート関連の項目です。CS信号の制御マクロを修正します。 今回、SOCKWPとSOCKINSは使用しないので適当に処理しておきます。 bclrとbset命令はcpu_insn.hでインライン関数が用意されてますが、 コンパイル時に24bit絶対アドレッシングモードでアクセスされていたので、 インラインアセンブラで書くことにしました。

/* Port Controls  (Platform dependent) */
#define	SELECT()	asm("bclr #0:3 @0xda:8")	/* MMC CS = L */
#define	DESELECT()	asm("bset #0:3 @0xda:8")	/* MMC CS = H */

#define	SOCKPORT	(*(volatile UB*)(H8PBDR))	/* Socket contact port */
#define	SOCKWP		0x00			/* Write protect switch (not use) */
#define	SOCKINS		0x00			/* Card detect switch (not use) */

SPI入出力

 SCI2モジュールを介してMMCにアクセスします。動作モードはクロック同期式 の送受信同時動作です。送信レジスタにデータをセットして、 エラーフラグをクリアして送信開始します。その後、RDRFフラグを監視して 受信データを取得します。

/*-----------------------------------------------------------------------*/
/* Transmit a byte to MMC via SPI  (Platform dependent)                  */
/*-----------------------------------------------------------------------*/

#define xmit_spi(dat) \
	H8MMC_TDR=(dat); \
	H8MMC_SSR &= ~(H8SSR_TDRE | H8SSR_ORER | H8SSR_FER | H8SSR_PER); \
	while ( !(H8MMC_SSR & H8SSR_RDRF) ); \
	H8MMC_SSR &= ~H8SSR_RDRF;


/*-----------------------------------------------------------------------*/
/* Receive a byte from MMC via SPI  (Platform dependent)                 */
/*-----------------------------------------------------------------------*/

static
BYTE rcvr_spi (void)
{
	BYTE d;
	
	//ダミーデータセット
	H8MMC_TDR = 0xff;
	
	//受信開始
	H8MMC_SSR &= ~(H8SSR_TDRE | H8SSR_ORER | H8SSR_FER | H8SSR_PER);
	while ( !(H8MMC_SSR & H8SSR_RDRF) );
	d = H8MMC_RDR;
	H8MMC_SSR &= ~H8SSR_RDRF;
	
	return d;
}

/* Alternative macro to receive data fast */
#define	rcvr_spi_m(dst) \
	H8MMC_TDR=0xff; \
	H8MMC_SSR &= ~(H8SSR_TDRE | H8SSR_ORER | H8SSR_FER | H8SSR_PER); \
	while ( !(H8MMC_SSR & H8SSR_RDRF) ); \
	*(dst)=H8MMC_RDR; \
	H8MMC_SSR &= ~H8SSR_RDRF;

Power control

今回、SD/MMCの電源管理はしないので、 SCIモジュールの初期化終了処理のみ記述しておきます。

/*-----------------------------------------------------------------------*/
/* 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 */
	
	SOCKPORT = 1 | H8PBDDR_TXD2;		//PB[0,TXD2]=1;
	sil_orb_ddr(IO_PORTB, 1 | H8PBDDR_TXD2 | H8PBDDR_SCK2);
						//PB[0,TXD2,SCK2]=output;
	H8MMC_SCR = 0;
	H8MMC_SCMR = H8SCMR_SDIR;		//SPI Mode0 MSB first
	H8MMC_BRR = 4;				//クロック最大
	H8MMC_SMR = H8SMR_GM;			//クロック同期式シリアルI/O
	H8MMC_SSR = 0;
	dly_tsk(1);				//1ms待ち
	H8MMC_SCR = H8SCR_TE | H8SCR_RE;	//送受信許可
	Stat &= ~(STA_PROTECT | STA_NODISK);	//準備OK
}

static
void power_off (void)
{
	SELECT();				/* Wait for card ready */
	wait_ready();
	release_spi();

	SOCKPORT = 1 | H8PBDDR_TXD2;		//PB[0,TXD2]=1;
	Stat |= STA_NOINIT;			/* Set STA_NOINIT */
}

static
int chk_power(void)				/* Socket power state: 0=off, 1=on */
{
	return 1;
}

FatFs用タイマ

今回、ライトプロテクトSWとカード検出SWは使用しないので、該当部を削除します。 関数は10ms間隔で非同期に実行させるために周期ハンドラとして登録します。

mmc.c
void disk_timerproc (VP_INT exinf)
{
	BYTE n;

	n = Timer1;			// 100Hz decrement timer
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;
}
main.cfg
INCLUDE("\"diskio.h\"");
CRE_CYC(CYCHDR2, { TA_HLNG, 0, disk_timerproc, 10, 0 });

時刻の取得

時刻に関しては、とりあえず適当な時刻を返すようにしておきます。 適宜、リアルタイムクロック等実装してください。

DWORD get_fattime ()
{
	return	  ((DWORD)(2008 - 1980) << 25)
		| ((DWORD)5 << 21)
		| ((DWORD)14 << 16)
		| ((DWORD)3 << 11)
		| ((DWORD)23 << 5)
		| ((DWORD)0 >> 1);
}

サンプルプログラム

 一秒毎にtest.txtに文字列を追記するサンプルプログラムです。 configureしてmake dependしてmakeしてください。

$./configure -C h8 -S akih8_3069f -A main
$make depend
$make