📄 mmcdump.c
字号:
/*****************************************************
Project : Fat filesystem and MMC-memeory card
Version : 0.0
Date : 1.11.2005
Author : Ari Naukkarinen
Company : Metsys Oy
Comments:
Program does:
- Read all files from MMC card (using FAT-16 filesystem)
- Dump all sectors
- Fill all files with 'Z'
- Only FAT-16 compatible
- Assume BlockSize = 512 bytes
- Program is for educational use only (does nothing useful)
- You have to create files using (for ex.) PC, and fill them with AVR
Limitations:
Program do not:
- Create files
- Update file size (or any other fields in DIR-entry)
- Understand FAT-12 or FAT-32 or others (ONLY FAT-16)
Chip type : ATmega32
Program type : Application
Clock frequency : 16,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
// include files from CodevisionC
#include <mega8.h>
#include <spi.h>
#include <stdio.h>
#include <stdlib.h>
#include <delay.h>
#include <string.h>
#define MMC_DEBUG4 // show mmcInit messages
//#define MMC_DEBUG3 // show mmc_read, mmcWrite messages
//#define MMC_DEBUG2 // show FAT addresses
#define IDLE_STATE 0 // MMC to SPI
#define INIT_COMMAND 1 // initialize card
#define CRC_OFF 59 // CRC checking on/off (normally automatically off in SPI)
#define SET_BLKLEN 16 // Set number of bytes to transfer per block (default 512 in SPI)
#define WRITE_BLK 24 // write a block
#define READ_BLK 17 // read a block
// Data tokens values
#define STARTBYTE_RDWR 0xFE // startbyte, block starts with 0xFE (both write and read block)
#define DR_MASK 0x1F
#define DR_ACCEPT 0x05
#define BlockSize 512
struct BootSec
{
unsigned char BPB_dummy1[11]; // 11 bytes OEM-name
unsigned int BPB_BytesPerSec; // 2 bytes
unsigned char BPB_SecPerClus; // 1 byte
unsigned int BPB_ResrvdSector; // 2 bytes
unsigned char BPB_NumOfFat; // 1 byte
unsigned int BPB_RootEntries; // 2 bytes
unsigned int BPB_TotSec16; // 2 bytes
unsigned char BPB_Media; // 1 byte
unsigned int BPB_SectPerFat; // 2 bytes
unsigned int BPB_SecPerTrk; // 2 bytes
unsigned int BPB_NumHeads; // 2 bytes
unsigned long BPB_HiddSec; // 4 bytes
unsigned long BPB_TotSec32; // 4 bytes
};
struct DirEntry {
unsigned char DIR_Name[11]; //8 chars filename
unsigned char DIR_Attr; //file attributes RSHA, Longname, Drive Label, Directory
unsigned char DIR_NTRes; //reserved to NT
unsigned char DIR_CrtTimems; //creation time part in milliseconds
unsigned int DIR_CrtTime; //creation time
unsigned int DIR_CrtDate; //creation date
unsigned int DIR_LastAccDate; //last access date
unsigned int DIR_FstClusHI; //first cluster high word
unsigned int DIR_WrtTime; //last write time
unsigned int DIR_WrtDate; //last write date
unsigned int DIR_FirstCluster; //first cluster low word
unsigned long DIR_FileSize;
};
// Declare your global variables here
unsigned int FatStart;
unsigned int ClustCnt; // cluster counter
unsigned int SectPerCluster;
unsigned int ClusterOffset;
unsigned long FileSize;
unsigned int RootDirEntry;
char RxBuffer;
char TxBuff[24];
char block[512];
/* functions start */
void send_char(unsigned char sch) // send data to serial port (not used)
{ char uart_stat;
uart_stat = 0x20&UCSRA;
{ while((uart_stat=(0x20&UCSRA)), uart_stat!=0x20); // wait for TX complete
UDR = sch;
}
}
void send_str() // send string to serial port (not used)
{ unsigned char i;
i = 0;
while(TxBuff[i] != 0)
{ send_char(TxBuff[i]);
i++;
}
}
unsigned char mmc_command(unsigned char cmd, unsigned long arg) // Write command to MMC, returns R1 result code, leaves ENABLE ON
{
unsigned char resp;
unsigned char retry=0;
PORTB.2 = 0;
spi(cmd | 0x40); // note command is CMD-X + 0x40
spi(arg>>24);
spi(arg>>16);
spi(arg>>8);
spi(arg);
spi(0x95); // spi CRC = always 0xFF OR 0x95 for MMC_GO_IDLE_STATE command
while((resp = spi(0xFF)) == 0xFF)
if(retry++ > 8) break; // card has timed out
return resp; // Note! MMC enable is ON
}
unsigned char mmc_init(void) // Initialize mmc-card, returns zero if successful.
{
unsigned char retry, i, resp=0;
retry = 0;
do // max 10 retries
{
// send 74+ (=80) dummy bits with CS high before accessing
for(i=0;i<10;i++)
spi(0xFF);
// resetting card, go to SPI mode
resp = mmc_command(IDLE_STATE, 0); // command 0
#ifdef MMC_DEBUG4
printf("IDLE_STATE-status:%x\r\n", resp);
#endif
retry++;
if(retry>10) return -1;
} while(resp != 0x01);
retry = 0;
do // max 100 retries
{ // send init cmd (1)
resp = mmc_command(INIT_COMMAND, 0);
#ifdef MMC_DEBUG4
printf("INIT_CMD-status:%x\r\n", resp);
#endif
retry++;
if(retry>100) return -1;
} while(resp);
// turn off CRC checking (not actually needed CRC-off is default)
resp = mmc_command(CRC_OFF, 0);
#ifdef MMC_DEBUG4
printf("CRC_OFF-status:%x\r\n", resp);
#endif
// set block length to 512 bytes (not actually needed 512 bytes is default)
resp = mmc_command(SET_BLKLEN, 512);
#ifdef MMC_DEBUG4
printf("SET_BLKLEN-status:%x\r\n", resp);
#endif
return 0;
}
unsigned char mmc_write(unsigned long sector, unsigned char* buffer) // write to MMC (from buffer or 'Z')
{ unsigned char resp;
unsigned int i;
PORTB.2 = 0; // set chip select
resp = mmc_command(WRITE_BLK, sector<<9);
#ifdef MMC_DEBUG3
printf("Write SECT %lu:%x\r\n", sector, resp);
#endif
if(resp != 0x00) return resp; // check for response
spi(0xFF); // send dummy
spi(STARTBYTE_RDWR); // send data start token
for(i=0; i<0x200; i++)
{ spi('Z'); // write data
// spi(*buffer++);
}
spi(0xFF); // write 16-bit CRC (dummy values)
spi(0xFF);
resp = spi(0xFF);
if( (resp & DR_MASK) != DR_ACCEPT) return resp; // read data response
#ifdef MMC_DEBUG3
printf("Data Response=0x%x\r\n", resp);
#endif
while(!spi(0xFF)); // wait until card not busy
PORTB.2 = 1; // release chip select
return 0; // return ok
}
unsigned char mmc_read(unsigned long sector, unsigned char* buffer) // Read buffer, returns zero if successful.
{
unsigned char resp;
unsigned int i;
PORTB.2 = 0; // set chip select
resp = mmc_command(READ_BLK, sector<<9); // send command:READ-BLOCK
#ifdef MMC_DEBUG3
printf("\r\nRead SECT %lu:%x", sector, resp );
#endif
if(resp != 0x00) return resp; // check response
while(spi(0xFF) != STARTBYTE_RDWR); // wait for block start
for(i=0; i<0x200; i++)
{ *buffer++ = spi(0xFF); // read in data
}
spi(0xFF); // read 16-bit CRC
spi(0xFF);
PORTB.2 = 1; // release chip select
return 0; // return OK
}
dump() // dump block (sector) buffer as hex to serial port
{ unsigned char i,j;
unsigned int m = 0;
for(i=0;i<32;i++)
{ printf("\r\n%3x:", m);
for(j=0;j<16;j++)
{ printf("%3x ", block[m]);
m++;
}
}
printf("\r\n");
}
txtdump() // dump block (sector) buffer as text to serial port
{ unsigned char i,j;
unsigned int m = 0;
for(i=0;i<32;i++)
{ printf("\r\n%3x:", m);
for(j=0;j<16;j++)
{ printf("%c ", block[m]);
m++;
}
}
printf("\r\n");
}
dump_file(unsigned int ClustNumber) // dump file ClustNumber = first cluster nuber of file
{ bit Feof;
unsigned int dSector, i, NextClust;
unsigned int *ptr;
#ifdef MMC_DEBUG2
printf("FileAllocationTable addr:%u\r\n", FatStart);
#endif
Feof = 1;
while(Feof)
{
dSector = ClusterOffset + (ClustNumber - 2) * SectPerCluster; // calculate sector number
#ifdef MMC_DEBUG2
printf("Read Cluster:0x%x ",ClustNumber);
#endif
printf("Read Sectors:", dSector);
for(i=0;i<SectPerCluster;i++)
{ printf("%u, ", dSector);
mmc_read(dSector,block); //Read data
//txtdump();
dSector++;
}
// fetch next cluster number from FAT
printf("\r\nRead FAT table\r\n");
dSector = FatStart + ClustNumber / 256; // calculate current Sector number of FAT table
printf("FatSectorAddr:%u ", dSector);
mmc_read(dSector,block); //Read Fat table
// dump();
ptr = block;
ClustNumber&=0xFF; // Max offset = 0xFF
ptr+=ClustNumber; // pointer to next cluster number
NextClust = *ptr; // get next cluster number
printf("PrevCluster:%u, NextCluster:%u (0x%x)\r\n",ClustNumber, NextClust, (unsigned int *) *ptr);
if(NextClust > 0xFF00) Feof = 0; // only 0xFF00 checked
ClustNumber = NextClust;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -