ELMさんが 公開されているFATファイルシステム・モジュールをTOPPERS用に移植してみました。 TOPPERS用のFatFsも公式ホームページにて公開されていますが、ターゲット システムが限定されているようなので、H8用にFatFsのサンプルプログラムを 基に修正しました。 基本的にはR8C/ELMさんのFatFsと同様、 たいしたことはしていません。本プログラムは以下の環境を想定しています。
| 項目 | 条件 |
|---|---|
| OS | TOPPERS/JSP Release 1.4.3 |
| System | AKI H8 3069f |
| Media | SD/MMC |
| FatFs | FatFs R0.07a |
| 排他制御 | しない |
| SCI | SCI2 |
| Port | PortB |
| CS | PB0 |
下位レイヤのプログラムは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)
ポート関連の項目です。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) */
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;
今回、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;
}
今回、ライトプロテクトSWとカード検出SWは使用しないので、該当部を削除します。 関数は10ms間隔で非同期に実行させるために周期ハンドラとして登録します。
void disk_timerproc (VP_INT exinf)
{
BYTE n;
n = Timer1; // 100Hz decrement timer
if (n) Timer1 = --n;
n = Timer2;
if (n) Timer2 = --n;
}
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