ChaNさんの
FatFs 汎用FATファイルシステム・モジュールで汎用FATファイルシステムを作ってみました。 サンプル・プロジェクト (FatFs R0.09b) をダウンロードし、avrディレクトリより下記のファイルを使用しました。 diskio.h ff.c ff.h ffconf.h (#define _USE_STRFUNC 1に変更する。 _FS_READONLY = 0, _USE_STRFUNC = 1でf_gets(), f_puts(), f_printf()が使用でき、 \n→\r\n変換はなしです。) integer.h mmcbb.c (回路図に合わせてPORTの#defineなどを下記のように変更する。) rtc.c (RTCに合わせ新しく作る。) rtc.h(新しく作る。) その他、main()の有るファイルに下記を書き加えます。 #include "ff.h" #include "rtc.h" DWORD get_fattime (void) { RTC rtc; /// if (!RtcOk) return 0; /* Get local time */ rtc_gettime(&rtc); /* Pack date and time into a DWORD variable */ return ((DWORD)(rtc.year - 1980) << 25) | ((DWORD)rtc.month << 21) | ((DWORD)rtc.mday << 16) | ((DWORD)rtc.hour << 11) | ((DWORD)rtc.min << 5) | ((DWORD)rtc.sec >> 1); }下記にmainプログラム (KINGMAX 2GB SDカード使用) とその結果をのっけておきます。 |
mainプログラム
/* * sd_card_test.c * atmega644P * * * Fuses(システムクロック:10MHz) * * 水晶 * EXTENDED 0xFF * HIGH 0xD9 * LOW 0xF7 */ #include <stdio.h> /* sprintf() */ #include <string.h> /* strcat(), strtok() */ #include <avr/io.h> #include <avr/interrupt.h> #define F_CPU 10.0E6 /* 10 MHz */ #include <util/delay.h> #include "monitor.h" #include "rtc.h" #include "timer.h" #include "usart0.h" #include "ff.h" extern unsigned short timerWDT; /* timer.cより */ static SYSTIM tim; /*---------------------------------------------------------*/ /* User Provided Timer Function for FatFs module */ /*---------------------------------------------------------*/ /* This is a real time clock service to be called from */ /* FatFs module. Any valid time must be returned even if */ /* the system does not support a real time clock. */ /* This is not required in read-only configuration. */ DWORD get_fattime (void) { RTC rtc; /// if (!RtcOk) return 0; /* Get local time */ rtc_gettime(&rtc); /* Pack date and time into a DWORD variable */ return ((DWORD)(rtc.year - 1980) << 25) | ((DWORD)rtc.month << 21) | ((DWORD)rtc.mday << 16) | ((DWORD)rtc.hour << 11) | ((DWORD)rtc.min << 5) | ((DWORD)rtc.sec >> 1); } FRESULT scan_files ( char* path, /* 開始ノード (ワークエリアとしても使用) */ char* buffer ) { FRESULT res; FILINFO fno; DIR dir; int i; char *fn; /* 非Unicode構成を想定 */ #if _USE_LFN static char lfn[_MAX_LFN + 1]; fno.lfname = lfn; fno.lfsize = sizeof lfn; #endif res = f_opendir(&dir, path); /* ディレクトリを開く */ if (res == FR_OK) { i = strlen(path); for (;;) { res = f_readdir(&dir, &fno); /* ディレクトリ項目を1個読み出す */ if (res != FR_OK || fno.fname[0] == 0) break; /* エラーまたは項目無しのときは抜ける */ if (fno.fname[0] == '.') continue; /* ドットエントリは無視 */ #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno.fname; #endif if (fno.fattrib & AM_DIR) { /* ディレクトリ */ sprintf(&path[i], "/%s", fn); res = scan_files(path, buffer); if (res != FR_OK) break; path[i] = 0; } else { /* ファイル */ ///printf_sio("%s/%s\r", path, fn); strcat(buffer, path); strcat(buffer, fn); strcat(buffer, ","); } } } return res; } ///static void delay_us(unsigned short t){while(t--) _delay_us(1);} static void delay_ms(unsigned short t){while(t--) _delay_ms(1);} int main(void) { static unsigned long ot[1]; FATFS fs; FIL fp; BYTE buffer[512]; FRESULT res; UINT bw; UINT br; TCHAR *tres; FILINFO fno; char path[32]; char seps[] = " ,\t\n\r"; char *token; FATFS *pfs; DWORD fre_clust, fre_sect, tot_sect; DWORD i; DDRA = 0b10001101; /* SCL SDA ----- ----- CS CLK SDO SDI */ DDRB = 0b00000001; /* SCK MISO MOSI ----- ----- ----- ----- LED */ DDRC = 0b00000000; /* ----- ----- ----- ----- ----- ----- ----- ----- */ DDRD = 0b00000000; /* ----- ----- ----- ----- ----- ----- TXD0 RXD0 */ PORTA = 0b01111011; PORTB = 0b11111110; PORTC = 0b11111111; PORTD = 0b11111100; initRTC(); initTIMER(); initUSART0(); /* WDT ON (タイムアウト値:1秒) */ __asm__ __volatile__("WDR"::); /* WDTクリア */ WDTCSR |= _BV(WDCE) | _BV(WDE); WDTCSR |= _BV(WDE) | _BV(WDP2) | _BV(WDP1); /* 4クロック以内に出す */ sei(); print_sio("START\r"); delay_ms(1); /* ドライブ0にワーク・エリアを与える (常に成功する) */ f_mount(0, &fs); /* ドライブ0にバイナリファイルを作成する */ /* ファイルを作成します。同名のファイルがある場合は、サイズを0にしてから開きます。 */ for(i=0; i<8; i++) buffer[i] = i + 0x10; res = f_open(&fp, "0:def.dat", FA_CREATE_ALWAYS | FA_WRITE); if(res != 0) printf_sio("ファイル 0:def.dat はオープンできません\r"); else{ f_write(&fp, buffer, 8, &bw); f_close(&fp); } /* ドライブ0のバイナリファイルを読む */ /* 既存のファイルを開きます。ファイルが無いときはエラーになります。(デフォルト) */ for(i=0; i<8; i++) buffer[i] = 0; res = f_open(&fp, "0:def.dat", FA_OPEN_EXISTING | FA_READ); if(res != 0) print_sio("ファイル 0:def.dat はオープンできません\r"); else{ while(1){ f_read(&fp, buffer, sizeof(buffer), &br); if(br == 0) break; for(i=0; i<br; i++) printf_sio("0x%02x ", buffer[i]); } f_close(&fp); } putchar_sio('\r'); putchar_sio('\r'); /* ドライブ0にテキストファイルを作成する */ /* ファイルを作成します。同名のファイルがある場合は、サイズを0にしてから開きます。 */ res = f_open(&fp, "0:abc.dat", FA_CREATE_ALWAYS | FA_WRITE); if(res != 0) printf_sio("ファイル 0:abc.dat はオープンできません\r"); else{ f_puts("abcdefg\r\n", &fp); f_puts("hijklmn\r\n", &fp); f_close(&fp); } /* ドライブ0のテキストファイルを読む */ /* 既存のファイルを開きます。ファイルが無いときはエラーになります。(デフォルト) */ res = f_open(&fp, "0:abc.dat", FA_OPEN_EXISTING | FA_READ); if(res != 0) print_sio("ファイル 0:abc.dat はオープンできません\r"); else{ while(1){ tres = f_gets((TCHAR *)buffer, sizeof(buffer), &fp); if(tres == NULL) break; print_sio((char *)buffer); } f_close(&fp); } /* ドライブ0にテキストファイルを作成する */ /* 既存のファイルを開きます。ファイルが無いときはファイルを作成します。追記の場合は、 */ /* この方法でオープンした後、f_lseek()でファイルの最後尾に移動してください。 */ res = f_open(&fp, "0:zzz.dat", FA_OPEN_ALWAYS | FA_WRITE); if(res != 0) printf_sio("ファイル 0:zzz.dat はオープンできません\r"); else{ /* ファイル終端へ移動(ファイル追記の準備) */ f_lseek(&fp, fp.fsize); f_printf(&fp, "%u, %u\r\n", 12345, 22345); f_close(&fp); } /* 追記 */ res = f_open(&fp, "0:zzz.dat", FA_OPEN_ALWAYS | FA_WRITE); if(res != 0) printf_sio("ファイル 0:zzz.dat はオープンできません\r"); else{ f_lseek(&fp, fp.fsize); f_printf(&fp, "%u, %u\r\n", 32345, 42345); f_close(&fp); } /* ドライブ0のテキストファイルを開く */ /* 既存のファイルを開きます。ファイルが無いときはエラーになります。(デフォルト) */ res = f_open(&fp, "0:zzz.dat", FA_OPEN_EXISTING | FA_READ); if(res != 0) print_sio("ファイル 0:zzz.dat はオープンできません\r"); else{ while(1){ tres = f_gets((TCHAR *)buffer, sizeof(buffer), &fp); if(tres == NULL) break; print_sio((char *)buffer); } f_close(&fp); } /* ファイル/ディレクトリの削除 */ f_unlink( "0:zzz.dat"); /* ファイル/ディレクトリのタイムスタンプの変更 */ fno.fdate = (WORD)(((2013 - 1980) * 512U) | 4 * 32U | 3); fno.ftime = (WORD)(12 * 2048U | 34 * 32U | 56 / 2U); f_utime("0:abc.dat", &fno); /* ファイル・ステータスの取得 */ f_stat("0:abc.dat", &fno); printf_sio("%s %lu %04d/%02d/%02d %02d:%02d:%02d 0x%02X\r", fno.fname, fno.fsize, (fno.fdate >> 9) + 1980, fno.fdate >> 5 & 0x0f, fno.fdate & 0x1f, fno.ftime >> 11, fno.ftime >> 5 & 0x3f, (fno.ftime & 0x1f) * 2, fno.fattrib); putchar_sio('\r'); /* ディレクトリの読み出し */ strcpy(path, "0:"); buffer[0] = '\0'; scan_files (path, (char *)buffer); /* 上にこの関数が有ります */ token = strtok((char *)buffer, seps); while(token != NULL){ printf_sio("%s\r", token); token = strtok(NULL, seps); } putchar_sio('\r'); /* ドライブ0のボリューム情報と空きクラスタ数を得る */ f_getfree("0:", &fre_clust, &pfs); /* 全セクタ数と空きセクタ数を計算 */ tot_sect = (pfs->n_fatent - 2) * pfs->csize; fre_sect = fre_clust * pfs->csize; /* ボリュームとと空きのサイズをKiB単位で表示 (512バイト/セクタと仮定) */ printf_sio("%lu KB total drive space.\r%lu KB available.\r", tot_sect / 2, fre_sect / 2); printf_sio("Number of FAT entries (= number of clusters + 2) = %lu\r", pfs->n_fatent); printf_sio("Sectors per cluster (1,2,4...128) = %u\r", pfs->csize); /* ワーク・エリアを開放する */ f_mount(0, NULL); get_tim(&tim); ot[0] = tim.ltime; while(1){ get_tim(&tim); if((unsigned long)(tim.ltime - ot[0]) >= 500/MSEC){ ot[0] = tim.ltime; PORTB ^= 0b00000001; } monitor(); if(timerWDT != 0xffff) timerWDT = 0; /* WDTのリセット */ } } |
上記プログラムの結果
回路図
実験風景