// // GPSのトラックログをSDカードに保存する. // // by Noe 2005 // // 参考資料: // ゆきさんのページ. // http://yuki-lab.jp/ // // kunioさんのページ. // http://www.cek.ne.jp/~kunio.h/index.htm // // このソースはゆきさんが公開されているものを参考にしています. // 以下、著作権表示. // ------------------------------------------------------------------ // EasyMP3(VS1001K) + MMC/SD MP3 Player(prototype) // // MCU: ATmega8 // FUSE bit: D9EFh (external clock) // Compiler: AVR-GCC // // 2003.6.3 KAWAKAMI Yukio // ------------------------------------------------------------------ // #include <16f877.h> //#include //#include "std_type.h" //#include "picdef_ccs.h" typedef unsigned int1 BIT; typedef unsigned int16 WORD; typedef unsigned int32 DWORD; //@nave union tagADDR_CNV{ DWORD dwaddr; struct tagBADDR{ BYTE a1; BYTE a2; BYTE a3; BYTE a4; } BADDR; } ADDR_CNV; struct tagPORTA{ short bit0; short bit1; short bit2; short bit3; short bit4; short bit5; short bit6; short bit7; }PORTA; #byte PORTA = 5 struct tagPORTB{ short bit0; short bit1; short bit2; short bit3; short bit4; short bit5; short bit6; short bit7; }PORTB; #byte PORTB = 6 #byte PORTC = 7 #byte PORTD = 8 #byte PORTE = 9 #define HIGH 1 #define LOW 0 #fuses hs,nowdt,noprotect,put,nobrownout,nolvp #use delay(clock=20000000) static BYTE Buff[72]; #define SPI_CS PORTB.bit5 #define SPI_DI PORTB.bit4 #define SPI_CLK PORTB.bit3 #define SPI_DO PORTB.bit2 #define MEM_WE PORTB.bit1 #define MEM_OE PORTB.bit0 #define PILOT_LED PORTA.bit0 #define SWITCH_01 PORTA.bit1 #define ACCESS_LED PORTA.bit5 //#define DEBUG_PRINTF 0 #use rs232(BAUD=4800, XMIT=PIN_A2, RCV=PIN_A3) VOID MMReadData(DWORD address); BYTE MMSendByte(BYTE c); BYTE MMGetResponse(VOID); BYTE MMReset(VOID); //BYTE FATtype; // 0:FAT12 1:FAT16. BYTE SectorsPerCluster; // 1クラスタのセクタ数. WORD RootDirEntriesCount; // ルートディレクトリエントリー数. WORD FATstart; // FAT開始セクタ. WORD FATsector; // FATのセクタ数. WORD DIRstart; // ルートディレクトリ開始セクタ. DWORD DataStart; // データ領域開始セクタ. BYTE FileNum; //現在のファイル番号. //NMEA0000.LOG〜NMEA9999.LOG BYTE BuffPtr; //バッファの位置. WORD NowFATSector; //現在の空きFATセクタ. WORD NowEntrySector; //現在の空きエントリセクタ WORD NowEmptyCluster; //現在の空きクラスタ番号. DWORD NowWriteCluster; //現在の書き込みクラスタ. //ファイルサイズを求めるのに使う. WORD EntryOffset; //ディレクトリエントリのオフセット. //////////////////////////////////////////////////////////////////////////// // シリアルポート送信. // // IN: // c 送信文字. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID seri_send(int c) { putc(c); } //////////////////////////////////////////////////////////////////////////// // SRAM書き込み. // // IN: // addr 書き込み先アドレス. // dat 書き込むデータ. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID write_sram(WORD addr, BYTE dat) { set_tris_d(0x00); PORTC = addr & 0xff; PORTE = addr >> 8; PORTD = dat; MEM_WE = LOW; MEM_WE = HIGH; } //////////////////////////////////////////////////////////////////////////// // SRAM読み込み. // // IN: // addr 読み込むアドレス. // // OUT: // // RETURN: // 読み込んだデータ. // //////////////////////////////////////////////////////////////////////////// BYTE read_sram(WORD addr) { BYTE dat; set_tris_d(0xff); PORTC = addr & 0xff; PORTE = addr >> 8; MEM_OE = LOW; dat = PORTD; MEM_OE = HIGH; return dat; } //////////////////////////////////////////////////////////////////////////// // DWORD値の表示. // // 16進数の8桁で表示する. // // IN: // val 表示したい値. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID print_dword(DWORD val) { BYTE b; b = (val >> 24) & 0xff; printf(seri_send, "%X", b); b = (val >> 16) & 0xff; printf(seri_send, "%X", b); b = (val >> 8) & 0xff; printf(seri_send, "%X", b); b = (val >> 0) & 0xff; printf(seri_send, "%X", b); printf(seri_send, "\r\n"); } //////////////////////////////////////////////////////////////////////////// // WORD値の表示. // // 10進数で表示する. // // IN: // val 表示したい値. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID print_word10(WORD val) { putc((val / 10000) + '0'); val %= 10000; putc((val / 1000) + '0'); val %= 1000; putc((val / 100) + '0'); val %= 100; putc((val / 10) + '0'); val %= 10; putc(val + '0'); putc('\r'); putc('\n'); } //////////////////////////////////////////////////////////////////////////// // カードから512バイト読み込む. // // 読み込んだデータはSRAMのアドレス0に格納. // // IN: // address 読み込みたいアドレス. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// BYTE MMReadData(DWORD address) { WORD i; // BYTE j; // BYTE b; BYTE rc; // BYTE response; //@nave DWORD addr; //BYTE n; //WORD start; //printf(seri_send, "MMReadData in\r\n"); ACCESS_LED = HIGH; SPI_CS = LOW; //@nave addr = address & 0xfffffe00; //printf(seri_send, "ADDR="); //print_dword(addr); //printf(seri_send, "address = %X:%X:%X\r\n", addr, (addr >> 8) & 0xff, addr & 0xff); MMSendByte(17 | 0x40); #if 1 //@nave ADDR_CNV.dwaddr = address; //@nave MMSendByte(ADDR_CNV.BADDR.a4); MMSendByte(ADDR_CNV.BADDR.a3); MMSendByte(ADDR_CNV.BADDR.a2); MMSendByte(ADDR_CNV.BADDR.a1); #else MMSendByte((addr >> 24) & 0xff); MMSendByte((addr >> 16) & 0xff); MMSendByte((addr >> 8) & 0xff); MMSendByte(addr & 0xff); #endif MMSendByte(0xff); //printf(seri_send, "MMSendCommand in MMReadData\r\n"); rc = 0; if(MMGetResponse() == 0){ //printf(seri_send, "%X%X%X%X\r\n", CmdBuffer[1],CmdBuffer[2],CmdBuffer[3],CmdBuffer[4]); //printf(seri_send, "MMGetResponse == 0\r\n"); for(i = 0; i < 9; i++){ //b = MMSendByte(0xff); //printf(seri_send, "Find Token in MMReadData %X\r\n", b); if(MMSendByte(0xff) == 0xfe){ //printf(seri_send, "Data Token in MMReadData\r\n"); rc = 1; break; } } } else{ //printf(seri_send, "MMGetResponse != 0\r\n"); } //printf(seri_send, "rc=%X\r\n", rc); #if 1 // start = (WORD)address & 0x01ff; //printf(seri_send, "START="); //print_dword(start); #endif if(rc == 1){ for(i = 0; i < 512; i++){ #if 0 if(i == start){ //printf(seri_send, "i == start\r\n"); for(n = 0; n < 32; n++){ Buff[n] = MMSendByte(0xff); //putc(Buff[n]); i++; } } else{ MMSendByte(0xff); } #else write_sram(i, MMSendByte(0xff)); #endif //b = MMSendByte(0xff); //if(flag == 1) putc(b); //if(flag == 1){ // if(!(i % 16) && i > 0){ // printf(seri_send, "\r\n"); // } // printf(seri_send, "%X ", b); //} } //printf(seri_send, "\r\n"); //CRCの2バイト空読み. MMSendByte(0xff); MMSendByte(0xff); delay_us(1); #if 0 response = MMSendByte(0xff); //pending j = MMSendByte(0xff); i = 0; //printf(seri_send, "j=%X\r\n", j); while(j == 0 && i < 255){ j = MMSendByte(0xff); //printf(seri_send, "j=%X\r\n", j); i++; } #else for(i = 0; i < 2048; i++){ if(MMSendByte(0xff) == 0xff) break; } #endif } SPI_CS = HIGH; ACCESS_LED = LOW; //printf(seri_send, "Exit MMReadData rc=%X\r\n", rc); //putc('E'); return rc; } //////////////////////////////////////////////////////////////////////////// // カードへ512バイト書き込む. // // SRAMのアドレス0にあるデータを書き込む. // // IN: // address 書き込みたいアドレス. // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// BYTE MMWriteData(DWORD address, BYTE flag) { WORD i; // BYTE j; // BYTE b; BYTE rc; BYTE response; //@nave DWORD addr; ACCESS_LED = HIGH; SPI_CS = LOW; //@nave addr = address & 0xfffffe00; MMSendByte(24 | 0x40); #if 1 //@nave ADDR_CNV.dwaddr = address; //@nave MMSendByte(ADDR_CNV.BADDR.a4); MMSendByte(ADDR_CNV.BADDR.a3); MMSendByte(ADDR_CNV.BADDR.a2); MMSendByte(ADDR_CNV.BADDR.a1); #else MMSendByte((addr >> 24) & 0xff); MMSendByte((addr >> 16) & 0xff); MMSendByte((addr >> 8) & 0xff); MMSendByte(addr & 0xff); #endif MMSendByte(0xff); #ifdef DEBUG_PRINTF if(flag == 1){ //printf(seri_send, "Write Address="); print_dword(addr); } #endif rc = 0; if(MMGetResponse() == 0){ //printf(seri_send, "MMGetResponse = 0\r\n"); MMSendByte(0xfe); delay_us(1); rc = 1; } else{ #ifdef DEBUG_PRINTF printf(seri_send, "Write Response ERROR!!\r\n"); #endif } if(rc == 1){ for(i = 0; i < 512; i++){ //b = read_sram(i); #if 0 rc = read_sram(i); MMSendByte(rc); putc(rc); #else MMSendByte(read_sram(i)); #endif //if((i % 16) == 0) printf(seri_send, "\r\n"); //printf(seri_send, "%X ", b); //delay_us(1); } //printf(seri_send, "\r\n"); #if 1 //書き込み時はCRC無し?. //CRCの2バイト空読み. MMSendByte(0xff); MMSendByte(0xff); #endif delay_us(1); #if 1 //printf(seri_send, "Res="); for(i = 0; i < 2048; i++){ response = MMSendByte(0xff); //printf(seri_send, "%X ", response); if(response == 0xff){ //printf(seri_send, "Card not busy\r\n"); break; } else{ //printf(seri_send, "Card busy\r\n"); } } //printf(seri_send, "\r\n"); #else response = MMSendByte(0xff); response &= 0x0f; if(response == 0x05){ //printf(seri_send, "Responce = TRUE\r\n"); } else{ //printf(seri_send, "Responce = FALSE\r\n"); } #endif } SPI_CS = HIGH; ACCESS_LED = LOW; return rc; } //////////////////////////////////////////////////////////////////////////// // カードへ1バイト送信する. // // 送信中のDOUTデータを返す. // 単にクロックを与えたり、カードから受信する場合にも使う. // // IN: // c 送信するデータ. // // OUT: // // RETURN: // カードからのデータ. // //////////////////////////////////////////////////////////////////////////// BYTE MMSendByte(BYTE c) { BYTE i; BYTE input; //ACCESS_LED = HIGH; input = 0x00; //printf(seri_send, "MMSendByte Send=%X\r\n", c); for(i = 0; i < 8; i++){ SPI_DI = HIGH; //delay_us(10); SPI_CLK = LOW; //delay_us(10); if((c & 0x80) == 0){ SPI_DI = LOW; } //delay_us(10); SPI_CLK = HIGH; //delay_us(10); #if 0 if(SPI_DO == HIGH){ input |= 0x01; } #else input |= SPI_DO; #endif if(i < 7){ input <<= 1; //pending } c <<= 1; } //printf(seri_send, "MMSendByte Recv=%X\r\n", input); //ACCESS_LED = LOW; return input; } //////////////////////////////////////////////////////////////////////////// // カードからのレスポンスを受信. // // IN: // // OUT: // // RETURN: // カードからのレスポンス. // //////////////////////////////////////////////////////////////////////////// BYTE MMGetResponse(VOID) { BYTE i; BYTE ret; ret = 0xff; for(i = 0; i < 9; i++){ ret = MMSendByte(0xff); //if(ret == 1 || ret == 0){ //ret==1 || ret==0 if(!(ret & 0xfe)){ //ret==1 || ret==0 //printf(seri_send, "Response %X in MMGetResponse\r\n", ret); break; } } return ret; } //////////////////////////////////////////////////////////////////////////// // カードバスの初期設定. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID MMInit(VOID) { SPI_CS = HIGH; SPI_CLK = HIGH; SPI_DI = HIGH; } //////////////////////////////////////////////////////////////////////////// // カードの初期化. // // 電源ON時にSPIモードへの移行手続き. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// BYTE MMReset(VOID) { // BYTE i; BYTE ret; BYTE status; SPI_CS = HIGH; //printf(seri_send, "Send Dummy Clock\r\n"); // for(i = 0; i < 10; i++){ // MMSendByte(0xff); // } //ダミーの80クロック. MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); MMSendByte(0xff); SPI_CS = LOW; MMSendByte(0x40); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x95); //printf(seri_send, "MMSendCommand in MMReset\r\n"); ret = MMGetResponse(); //printf(seri_send, "MMGetResponse in MMReset %X\r\n", ret); while(ret == 0x01){ SPI_CS = HIGH; MMSendByte(0xff); SPI_CS = LOW; MMSendByte(1 | 0x40); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x00); MMSendByte(0x95); ret = MMGetResponse(); //printf(seri_send, "MMGetResponse in MMReset2 %X\r\n", ret); } SPI_CS = HIGH; MMSendByte(0xff); status = 0; // for(i = 0; i < 3; i++){ // status = MMReadData(0); // } status = MMReadData(0); status = MMReadData(0); status = MMReadData(0); //printf(seri_send, "Success MMReset %X\r\n", ret); return ret; } //////////////////////////////////////////////////////////////////////////// // 空きクラスタの検索. // // FATテーブルを読んでいき、空きクラスタを得る. // // 検索の効率化: // 検索終了時、空きクラスタが記録されているセクタを保存しておく. // 次回の検索は上記セクタから検索することで、FATテーブルを常に先頭から // 舐め直す必要がなくなる. // // IN: // // OUT: // // RETURN: // 空きクラスタ番号. // //////////////////////////////////////////////////////////////////////////// WORD GetEmptyCluster(VOID) { WORD i; WORD j; WORD num; WORD sect; sect = 0; //for(i = 0; i < FATsector; i++){ for(i = NowFATSector; i < FATsector; i++){ //MMReadData(((DWORD)FATstart + i) * 512); //@ MMReadData(((DWORD)FATstart + i) << 9); //@ sect = 0; for(j = 0; j < 512; j += 2){ num = read_sram(j); num <<= 8; num |= read_sram(j + 1); if(num == 0){ ////printf(seri_send, "Empty Cluster "); ////print_dword((DWORD)sect); write_sram(j, 0xff); write_sram(j + 1, 0xff); //MMWriteData(((DWORD)FATstart + i) * 512, 0); //@ MMWriteData(((DWORD)FATstart + i) << 9, 0); //@ break; } sect++; } if(num == 0){ break; } } NowFATSector = i; // printf(seri_send, "Fat="); // print_dword(NowFATSector); #if 1 NowEmptyCluster = ((NowFATSector * 256) + sect); //printf(seri_send, "NowClst="); //print_word10(NowEmptyCluster); return (NowFATSector * 256) + sect; #else NowEmptyCluster = sect - 2; printf(seri_send, "NowEmptyCluster="); print_dword(NowEmptyCluster); return sect; #endif } //////////////////////////////////////////////////////////////////////////// // 空きルートディレクトリエントリの検索. // // ディレクトリエントリを読んでいき、空きを得る. // ファイル名、日時、クラスタ番号、初期ファイルサイズなどを書き込む. // // 検索の効率化: // 検索終了時、空きエントリが記録されているセクタを保存しておく. // 次回の検索は上記セクタから検索することで、ディレクトリエントリを常に // 先頭から舐め直す必要がなくなる. // // IN: // // OUT: // // RETURN: // 空きエントリ番号. // //////////////////////////////////////////////////////////////////////////// WORD GetEmptyEntry(WORD empty_no) { WORD ent; DWORD sec; DWORD fsize; //BYTE i, j; BYTE i; WORD offset; BYTE flag; //WORD filestat; //DWORD filesize; WORD NowFileNum; flag = 0; NowFileNum = FileNum; //sec = ((DWORD)DIRstart + (DWORD)NowEntrySector) * 512; //@@ sec = ((DWORD)DIRstart + (DWORD)NowEntrySector) << 9; //@@ //for (ent=0; ent < RootDirEntriesCount; ent++){ for (ent=NowEntrySector; ent < RootDirEntriesCount; ent++){ MMReadData(sec); //print_dword(sec); offset = 0; for (i=0; i < 16; i++){ //if (read_sram(offset) == 0){ // break; //} #if 0 putc('['); for(j = 0; j < 11; j++){ putc(read_sram(offset + j)); } putc(']'); printf(seri_send, "%X%X%X%X %X %X", //read_sram(offset + 26), //read_sram(offset + 27), //read_sram(offset + 11), read_sram(offset + 28), read_sram(offset + 29), read_sram(offset + 30), read_sram(offset + 31), read_sram(offset + 11) & 0x18, read_sram(offset) ); putc('\r');putc('\n'); #endif // if((read_sram(offset + 26) == 0 && read_sram(offset + 27) == 0) || // read_sram(offset) == 0xe5){ // クラスタ番号 if (read_sram(offset) == 0x00 || ((read_sram(offset + 26) == 0)||(read_sram(offset + 27) == 0))&& // クラスタ番号 (read_sram(offset) == 0xE5)&& // 削除マーク ((read_sram(offset + 11) & 0x18))){ // 通常ファイル ////printf(seri_send, "Empty Entry "); ////print_dword(sec); ////printf(seri_send, "Offset "); ////print_dword(offset); //for(dmy = 0; dmy < 512; dmy++){ // printf(seri_send, "%X ", read_sram(dmy)); //} //printf(seri_send, "\r\n"); //Filename write_sram(offset + 0, 'N'); write_sram(offset + 1, 'M'); write_sram(offset + 2, 'E'); write_sram(offset + 3, 'A'); write_sram(offset + 4, '0'); write_sram(offset + 5, (NowFileNum / 100) + '0'); NowFileNum %= 100; write_sram(offset + 6, (NowFileNum / 10) + '0'); NowFileNum %= 10; write_sram(offset + 7, NowFileNum + '0'); write_sram(offset + 8, 'L'); write_sram(offset + 9, 'O'); write_sram(offset + 10, 'G'); FileNum += 1; //ファイル属性 R:0x01 H:0x02 A:0x20 write_sram(offset + 11, 0x20); //作成時間の1/10秒 write_sram(offset + 13, 0x00); //ファイル作成時間. write_sram(offset + 14, 0x00); write_sram(offset + 15, 0x00); //ファイル作成日. write_sram(offset + 16, 0x21); write_sram(offset + 17, 0x30); //最終アクセス日. write_sram(offset + 18, 0x21); write_sram(offset + 19, 0x30); //FAT16は常にゼロ. write_sram(offset + 20, 0x00); write_sram(offset + 21, 0x00); //最終ファイル書き込み時間. write_sram(offset + 22, 0x00); write_sram(offset + 23, 0x00); //最終ファイル書き込み日. write_sram(offset + 24, 0x21); write_sram(offset + 25, 0x30); //クラスタ番号. write_sram(offset + 26, (empty_no) & 0xff); //pending write_sram(offset + 27, (empty_no >> 8) & 0xff); //pending #ifdef DEBUG_PRINTF printf(seri_send, "Write empty entry=%X %X ", (empty_no) & 0xff, (empty_no >> 8) & 0xff); print_word10(empty_no); #endif //ファイルサイズ. //fsize = (NowWriteCluster * SectorsPerCluster) * 512; //@ fsize = (NowWriteCluster * SectorsPerCluster) << 9; //@ write_sram(offset + 28, fsize & 0xff); //pending write_sram(offset + 29, (fsize >> 8) & 0xff); //pending write_sram(offset + 30, (fsize >> 16) & 0xff); //pending write_sram(offset + 31, (fsize >> 24) & 0xff); //pending flag = 1; EntryOffset = offset; MMWriteData(sec, 0); //ディレクトリエントリの保存. for(offset = 0; offset < 512; offset++){ write_sram(1024 + offset, read_sram(offset)); } break; } if(flag == 1) break; offset += 32; //ent++; //sec += 32; } if(flag == 1) break; sec += 512; // 次のセクタ } NowEntrySector = ent; //printf(seri_send, "Sec="); //print_dword(NowEntrySector); } //////////////////////////////////////////////////////////////////////////// // ファイルサイズのアップデートを行う. // // ディレクトリエントリを読んでいき、空きを得る. // ファイル名、日時、クラスタ番号、初期ファイルサイズなどを書き込む. // // 検索の効率化: // 検索終了時、空きエントリが記録されているセクタを保存しておく. // 次回の検索は上記セクタから検索することで、ディレクトリエントリを常に // 先頭から舐め直す必要がなくなる. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// void UpdateFileSize(WORD addsize) { #if 0 // WORD ent; // DWORD sec; // DWORD fsize; // //BYTE i, j; // BYTE i; // WORD offset; // BYTE flag; // // //WORD filestat; // //DWORD filesize; // // WORD NowFileNum; // // flag = 0; // NowFileNum = FileNum; // // //printf(seri_send, "Update Filesize in\r\nFileNum="); // //print_dword(FileNum); // // //sec = ((DWORD)DIRstart + NowEntrySector) * 512; //@@ // sec = ((DWORD)DIRstart + NowEntrySector) << 9; //@@ // //for (ent=0; ent < RootDirEntriesCount; ent++){ // for (ent=NowEntrySector; ent < RootDirEntriesCount; ent++){ // MMReadData(sec); // //print_dword(sec); // // offset = 0; // for (i=0; i < 16; i++){ // if (read_sram(offset) == 0){ // break; // } // // if (((read_sram(offset + 26) != 0)||(read_sram(offset + 27) != 0))&& // クラスタ番号 // (read_sram(offset) != 0xE5)&& // 削除マーク // (!(read_sram(offset + 11) & 0x18))){ // 通常ファイル // // //printf(seri_send, "Exist File\r\n"); // // NowFileNum = (read_sram(offset + 5) - '0') * 100; // NowFileNum += (read_sram(offset + 6) - '0') * 10; // NowFileNum += (read_sram(offset + 7) - '0'); // // //print_dword(NowFileNum); // // //Filename // if(read_sram(offset + 0) == 'N' && // read_sram(offset + 1) == 'M' && // read_sram(offset + 2) == 'E' && // read_sram(offset + 3) == 'A' && // read_sram(offset + 4) == '0' && // read_sram(offset + 8) == 'L' && // read_sram(offset + 9) == 'O' && // read_sram(offset + 10) == 'G' && NowFileNum == (FileNum - 1)){ // // //printf(seri_send, "Update Filesize\r\n"); // //ファイルサイズ. // //fsize = (((DWORD)NowWriteCluster * (DWORD)SectorsPerCluster) * 512) + addsize; //@ //#if 0 // fsize = (((DWORD)NowWriteCluster * (DWORD)SectorsPerCluster) << 9) + addsize; //@ // write_sram(offset + 28, fsize & 0xff); //pending // write_sram(offset + 29, (fsize >> 8) & 0xff); //pending // write_sram(offset + 30, (fsize >> 16) & 0xff); //pending // write_sram(offset + 31, (fsize >> 24) & 0xff); //pending //#else // ADDR_CNV.dwaddr = (((DWORD)NowWriteCluster * (DWORD)SectorsPerCluster) << 9) + addsize; //@ // write_sram(offset + 28, ADDR_CNV.BADDR.a1); //pending // write_sram(offset + 29, ADDR_CNV.BADDR.a2); //pending // write_sram(offset + 30, ADDR_CNV.BADDR.a3); //pending // write_sram(offset + 31, ADDR_CNV.BADDR.a4); //pending //#endif // flag = 1; // // MMWriteData(sec, 0); // // break; // } // if(flag == 1) break; // } // if(flag == 1) break; // offset += 32; // //ent++; // //sec += 32; // } // if(flag == 1) break; // // sec += 512; // 次のセクタ // } //// printf(seri_send, "Sec="); //// print_dword(NowEntrySector); #else WORD i; WORD offset; DWORD sec; offset = 1024 + EntryOffset; ADDR_CNV.dwaddr = (((DWORD)NowWriteCluster * (DWORD)SectorsPerCluster) << 9) + addsize; //@ write_sram(offset + 28, ADDR_CNV.BADDR.a1); //pending write_sram(offset + 29, ADDR_CNV.BADDR.a2); //pending write_sram(offset + 30, ADDR_CNV.BADDR.a3); //pending write_sram(offset + 31, ADDR_CNV.BADDR.a4); //pending for(i = 0; i < 512; i++){ write_sram(i, read_sram(1024 + i)); } sec = ((DWORD)DIRstart + NowEntrySector) << 9; //@@ MMWriteData(sec, 0); #endif } //////////////////////////////////////////////////////////////////////////// // FAT情報読み込み. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// BYTE read_VFAT_info(VOID) { DWORD sec; WORD bpb; WORD n; // VFAT情報読み取り。セクタ長は 512bytesで決め打ちしている //MMReadData(446); // MBR読み込み MMReadData(0); // MBR読み込み bpb = (WORD)read_sram(446 + 8) + ((WORD)read_sram(446 + 9)<<8); // BPB先頭セクタ //printf(seri_send, "BPB sector "); //print_dword(bpb); MMReadData((DWORD)bpb * 512); // 読み込み //n = (WORD)Buff[11] + ((WORD)Buff[12] << 8); // セクタ長 n = (WORD)read_sram(11) + ((WORD)read_sram(12) << 8); // セクタ長 //printf(seri_send, "Sector Length "); //print_dword(n); if (n != 512){ return 2; // 1セクタが 512bytesでない } //SectorsPerCluster = Buff[13]; // クラスタあたりのセクタ数 SectorsPerCluster = read_sram(13); // クラスタあたりのセクタ数 //printf(seri_send, "Sector Per Cluster "); //print_dword(SectorsPerCluster); //FATstart = bpb + (WORD)Buff[14] + ((WORD)Buff[15] << 8); // 予約セクタ数 FATstart = bpb + (WORD)read_sram(14) + ((WORD)read_sram(15) << 8); // 予約セクタ数 //printf(seri_send, "FATstart "); //print_dword(FATstart); //RootDirEntriesCount = (WORD)Buff[17] + ((WORD)Buff[18] << 8); // ルートディレクトリエントリ数 RootDirEntriesCount = (WORD)read_sram(17) + ((WORD)read_sram(18) << 8); // ルートディレクトリエントリ数 //printf(seri_send, "RootDirEntriesCount "); //print_dword(RootDirEntriesCount); //n = (WORD)Buff[22] + ((WORD)Buff[23] << 8); // FATのセクタ数 n = (WORD)read_sram(22) + ((WORD)read_sram(23) << 8); // FATのセクタ数 //printf(seri_send, "Sector Num "); //print_dword(n); FATsector = n; //printf(seri_send, "FATsector "); //print_dword(FATsector); if (n == 0){ return 1; // FAT32らしい } //DIRstart = (WORD)FATstart + (WORD)Buff[16] * n; // FATの数×セクタ数 DIRstart = (WORD)FATstart + (WORD)read_sram(16) * n; // FATの数×セクタ数 //printf(seri_send, "DIRstart "); //print_dword(DIRstart); n = RootDirEntriesCount / 16; // ルートディレクトリに必要なセクタ数 //printf(seri_send, "Rootdir Sector "); //print_dword(n); if (RootDirEntriesCount % 16){ n++; // 念のため、余りが出たら切り上げ。通常は不要だと思うが } DataStart = (DWORD)DIRstart + (DWORD)n; // データ格納領域 //printf(seri_send, "DataStart "); //print_dword(DataStart); //sec = (DWORD)Buff[19] + ((DWORD)Buff[20] << 8); // 総セクタ数 sec = (DWORD)read_sram(19) + ((DWORD)read_sram(20) << 8); // 総セクタ数 //printf(seri_send, "Total Sector "); //print_dword(sec); if (sec == 0){ //MMReadData((DWORD)bpb * 512 + 32); // 読み込み MMReadData((DWORD)bpb * 512); // 読み込み //sec = (DWORD)Buff[0] + ((DWORD)Buff[1] << 8) + ((DWORD)Buff[2] << 16) + ((DWORD)Buff[3] << 24); sec = (DWORD)read_sram(32 + 0) + ((DWORD)read_sram(32 + 1) << 8) + ((DWORD)read_sram(32 + 2) << 16) + ((DWORD)read_sram(32 + 3) << 24); //printf(seri_send, "Total Sector "); //print_dword(sec); } sec -= FATstart; sec /= SectorsPerCluster; if (sec >= 0x1000){ //FATtype = 1; // FAT16 //printf(seri_send, "FAT16\r\n"); } else { //FATtype = 0; // FAT12 //printf(seri_send, "FAT12\r\n"); } return 0; } //////////////////////////////////////////////////////////////////////////// // ファイルの時間を表示. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// void print_time(WORD dat) { BYTE num; num = (dat >> 11) & 0x1f; printf(seri_send, "%02u:", num); num = (dat >> 5) & 0x3f; printf(seri_send, "%02u:", num); num = dat & 0x1f; num *= 2; printf(seri_send, "%02u", num); } //////////////////////////////////////////////////////////////////////////// // ファイルの日付を表示. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// void print_date(WORD dat) { BYTE num; num = (dat >> 9) & 0x7f; num = (num + 1980) % 8; printf(seri_send, "%02u/", num); num = (dat >> 5) & 0x0f; printf(seri_send, "%02u/", num); num = dat & 0x1f; printf(seri_send, "%02u", num); } //////////////////////////////////////////////////////////////////////////// // ディレクトリエントリのファイル一覧を表示. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// VOID rootdir_flist(VOID) { WORD ent; DWORD sec; BYTE i, j; // WORD n; // char fname[12]; WORD offset; WORD filestat; DWORD filesize; WORD NowFileNum; BYTE FindFileFlag; NowFileNum = 0; FindFileFlag = 0; // n = 0; //sec = (DWORD)DIRstart * 512; //@ sec = (DWORD)DIRstart << 9; //@ for (ent=0; ent < RootDirEntriesCount; ent++){ MMReadData(sec); offset = 0; //if (SPI_read_open(sec)) return n; for (i=0; i < 16; i++){ //printf(seri_send, "ADDR="); //print_dword(sec); //MMReadData(sec); //for(j = 0; j < 32; j++){ // printf(seri_send, "%X ", Buff[j]); //} //printf(seri_send, "\r\n"); //for (j = 0; j < 32; j++){ // Buff[j] = SPI_in(); //} if (read_sram(offset) == 0){ //printf(seri_send, "File End\r\n"); break; } if (((read_sram(offset + 26) != 0)||(read_sram(offset + 27) != 0))&& // クラスタ番号 (read_sram(offset) != 0xE5)&& // 削除マーク (!(read_sram(offset + 11) & 0x18))){ // 通常ファイル //(Buff[8]=='M')&&(Buff[9]=='P')&&(Buff[10]=='3')){ // 拡張子MP3 //n++; //if (--num == 0) break; //for(j = 0; j < 12; j++){ // fname[j] = Buff[j]; //} //fname[j] = NULL; //Buff[11] = NULL; //printf(seri_send, "%S ", Buff); //printf(seri_send, "Find File\r\n"); if(read_sram(offset) == 'N' && read_sram(offset + 1) == 'M' && read_sram(offset + 2) == 'E' && read_sram(offset + 3) == 'A' && read_sram(offset + 8) == 'L' && read_sram(offset + 9) == 'O' && read_sram(offset + 10) == 'G'){ NowFileNum = (read_sram(offset + 5) - '0') * 100; NowFileNum += (read_sram(offset + 6) - '0') * 10; NowFileNum += (read_sram(offset + 7) - '0'); if(NowFileNum > FileNum){ FileNum = NowFileNum; } FindFileFlag = 1; } #ifdef DEBUG_PRINTF for(j = 0; j < 11; j++){ putc(read_sram(offset + j)); } putc(' '); #if 0 //Filename R H A //DSC00001JPG - - - 00 //DSC00002JPG - - o 20 //DSC00003JPG - o - 02 //DSC00004JPG - o o 22 //DSC00005JPG o - - 01 //DSC00006JPG o - o 21 //DSC00007JPG o o - 03 //DSC00008JPG o o o 23 //R:0x01 H:0x02 A:0x20 if((read_sram(offset + 11) & 0x01)) putc('R'); else putc('-'); if((read_sram(offset + 11) & 0x02)) putc('H'); else putc('-'); if((read_sram(offset + 11) & 0x20)) putc('A'); else putc('-'); putc(' '); #endif #if 1 //最終ファイル書き込み日 filestat = read_sram(offset + 25); filestat <<= 8; filestat |= read_sram(offset + 24); print_date(filestat); putc(' '); //最終ファイル書き込み時間 filestat = read_sram(offset + 23); filestat <<= 8; filestat |= read_sram(offset + 22); print_time(filestat); putc(' '); putc(' '); //ファイル作成日 filestat = read_sram(offset + 17); filestat <<= 8; filestat |= read_sram(offset + 16); print_date(filestat); putc(' '); //ファイル作成時間 filestat = read_sram(offset + 15); filestat <<= 8; filestat |= read_sram(offset + 14); print_time(filestat); putc(' '); putc(' '); //最終アクセス日 filestat = read_sram(offset + 19); filestat <<= 8; filestat |= read_sram(offset + 18); print_date(filestat); #endif #if 0 for(j = 0; j < 32; j++){ printf(seri_send, "%X ", Buff[j]); } #endif printf(seri_send, "\r\n"); #endif //DEBUG_PRINTF } else{ //printf(seri_send, "Not Find File\r\n"); } offset += 32; //ent++; //sec += 32; } //SPI_read_close(); if (read_sram(offset) == 0) break; //if (num == 0) break; sec += 512; // 次のセクタ } // return n; if(FindFileFlag == 1){ FileNum += 1; } else{ FileNum = 0; } } //#define UPDATE_NUM (SectorsPerCluster*2) #define UPDATE_SECTOR 8 BYTE NowWriteSect; BYTE NowWriteRecord; //////////////////////////////////////////////////////////////////////////// // 受信した文字列によって処理を振り分け. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// void command_execute(void) { BYTE i; // unsigned char j; DWORD address; WORD empclust; WORD OldCluster; WORD OldFATSector; //if(Buff[0] == '$' && // Buff[1] == 'G' && // Buff[2] == 'P' && // Buff[3] == 'R' && // Buff[4] == 'M' && // Buff[5] == 'C' ){ if(Buff[5] != 'C') return; if(Buff[4] != 'M') return; if(Buff[3] != 'R') return; if(Buff[2] != 'P') return; if(Buff[1] != 'G') return; if(Buff[0] != '$') return; PILOT_LED = HIGH; putc('N'); //printf(seri_send, "NowWriteRecord="); //print_dword(NowWriteRecord); //empclust = (WORD)NowWriteRecord * 64 + 512; //printf(seri_send, "empclust="); //print_dword(empclust); for(i = 0; i < 64; i++){ empclust = ((WORD)NowWriteRecord * 64) + i + 512; //@ //empclust = ((WORD)NowWriteRecord << 6) + i + 512; //@ write_sram(empclust, ' '); //write_sram((NowWriteRecord * 64) + i + 512, ' '); } for(i = 0; i < BuffPtr - 7; i++){ empclust = ((WORD)NowWriteRecord * 64) + i + 512; //@ //empclust = ((WORD)NowWriteRecord << 6) + i + 512; //@ write_sram(empclust, Buff[i + 7]); } PILOT_LED = LOW; NowWriteRecord += 1; if(NowWriteRecord >= UPDATE_SECTOR){ NowWriteRecord = 0; for(empclust = 0; empclust < 512; empclust++){ write_sram(empclust, read_sram(empclust + 512)); } //1セクタ書き込み. //address = (((DWORD)DataStart + ((DWORD)NowEmptyCluster * (DWORD)SectorsPerCluster)) + (DWORD)NowWriteSect) * 512; //@ address = (DWORD)DataStart; address += (((DWORD)NowEmptyCluster - 2) * (DWORD)SectorsPerCluster); address += (DWORD)NowWriteSect; //address *= 512; //@ address <<= 9; //@ //address = (DataStart + (NowEmptyCluster * SectorsPerCluster) + NowWriteSect) << 9; //@ MMWriteData(address, 1); //MMReadData(address); //for(empclust = 0; empclust < 20; empclust++){ // putc(read_sram(empclust)); //} //printf(seri_send, "\r\n"); NowWriteSect += 1; } if(NowWriteSect >= SectorsPerCluster){ //putc('S'); NowWriteSect = 0; NowWriteCluster += 1; OldCluster = NowEmptyCluster; //一時退避(GetEmptyClusterで更新されるため). OldFATSector = NowFATSector; //一時退避(GetEmptyClusterで更新されるため). //printf(seri_send, "PrvClst="); #ifdef DEBUG_PRINTF print_word10(OldCluster); #endif empclust = GetEmptyCluster(); //次の空きクラスタを検索し、予約する. if(((OldCluster + 1 ) % 256) == 0 && OldCluster != 0){ //address = ((DWORD)FATstart + (DWORD)OldFATSector) * 512; //@ address = ((DWORD)FATstart + (DWORD)OldFATSector) << 9; //@ } else{ //address = ((DWORD)FATstart + (DWORD)NowFATSector) * 512; //@ address = ((DWORD)FATstart + (DWORD)NowFATSector) << 9; //@ } //address = (FATstart + (OldCluster / 256)) * 512; //@ //address = (FATstart + (OldCluster / 256)) << 9; //@ MMReadData(address); OldCluster = OldCluster % 256; //printf(seri_send, "UpdClst="); #ifdef DEBUG_PRINTF print_word10(empclust); #endif write_sram((OldCluster * 2), empclust & 0xff); //@ //write_sram((OldCluster << 1), empclust & 0xff); //@ write_sram((OldCluster * 2) + 1, (empclust >> 8) & 0xff); //@ //write_sram((OldCluster << 1) + 1, (empclust >> 8) & 0xff); //@ //printf(seri_send, "FatArry="); //print_word10(((DWORD)OldCluster * 2)); MMWriteData(address, 0); //putc('S'); UpdateFileSize(0); //putc('E'); #ifndef DEBUG_PRINTF putc('\r'); putc('\n'); #endif //putc('E'); } //PILOT_LED = LOW; //} } //////////////////////////////////////////////////////////////////////////// // メイン. // // IN: // // OUT: // // RETURN: // //////////////////////////////////////////////////////////////////////////// main() { // BYTE dat; // DWORD i; // char addr[16]; // BYTE j; // WORD empclust; // DWORD address; // WORD i; BYTE rcv; // BYTE sw_flag; WORD ent; setup_adc(NO_ANALOGS); //Not Used set_tris_a(0x02); //PORT A set_tris_b(0x04); //PORT B set_tris_c(0x00); //PORT C set_tris_d(0x00); //PORT D set_tris_e(0x00); //PORT E #use rs232(BAUD=4800, XMIT=PIN_A2, RCV=PIN_A3) //printf(seri_send, "Call MMInit()\r\n"); MMInit(); MEM_WE = HIGH; MEM_OE = HIGH; PILOT_LED = LOW; ACCESS_LED = LOW; //sw_flag = 0; FileNum = 0; BuffPtr = 0; NowWriteSect = 0; NowWriteRecord = 0; NowEmptyCluster = 0; NowWriteCluster = 0; NowFATSector = 0; //現在の空きFATセクタ. NowEntrySector = 0; //現在の空きエントリセクタ delay_ms(1000); //fail safe //printf(seri_send, "Call MMReset()\r\n"); //dat = MMReset(); if(MMReset() == 0xff){ printf(seri_send, "MMC/SD not exist\r\n"); while(1) ; } printf(seri_send, "MMC/SD exist\r\n"); while(1){ while(1){ if(SWITCH_01 == LOW){ delay_ms(100); while(1){ if(SWITCH_01 == HIGH){ break; } } break; } } printf(seri_send, "Logging Start\r\n"); #if 1 FileNum = 0; BuffPtr = 0; NowWriteSect = 0; NowWriteRecord = 0; NowEmptyCluster = 0; NowWriteCluster = 0; NowFATSector = 0; //現在の空きFATセクタ. NowEntrySector = 0; //現在の空きエントリセクタ EntryOffset = 0; read_VFAT_info(); rootdir_flist(); ent = GetEmptyCluster(); GetEmptyEntry(ent); #ifdef DEBUG_PRINTF printf(seri_send, "Start cluster="); print_word10(ent); #endif #endif while(1){ rcv = getc(); #if 0 switch(rcv){ case 0x0d: command_execute(); BuffPtr = 0; break; case 0x0a: BuffPtr -= 1; command_execute(); BuffPtr = 0; break; default: Buff[BuffPtr] = rcv; BuffPtr += 1; if(BuffPtr >= 72){ command_execute(); BuffPtr = 0; } break; } #else if(rcv == 0x0d){ command_execute(); BuffPtr = 0; } else if(rcv == 0x0a){ BuffPtr -= 1; command_execute(); BuffPtr = 0; } else{ Buff[BuffPtr] = rcv; BuffPtr += 1; if(BuffPtr >= 72){ command_execute(); BuffPtr = 0; } } #endif if(SWITCH_01 == LOW){ delay_ms(100); while(1){ if(SWITCH_01 == HIGH){ delay_ms(100); break; } } break; } } printf(seri_send, "\r\nLogging End\r\n"); } }