📄 hdd driver.c
字号:
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Name: HDD Driver.c //
// Date: 02/01/2004 //
// Version: 1.1 //
// Type: PIC C Driver for MMC //
// Author: Mike Luck & Douglas Kennedy //
// Company: MPIC3.COM //
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Note:
// This code is a work in progress & not a finished fully working
// project. Please check www.mpic3.com reguarly for updates.
/// PIN Assignments //////////////////////////////
#DEFINE _CS PIN_C2 // chip select for MMC
//#DEFINE SDO PIN_C5
//#DEFINE CLK PIN_C3
//#DEFINE SDI PIN_C4
// SPI hardware pins are
// SDO C5
// SDI C4
// SCK C3
///////////////////////////////////////////////////////////////
///// Note old values needed before all SPI modes could be set up using SPI_setup
/// for 16 parts ///////////
//#DEFINE SSPCON 0x14
//#DEFINE SSPSTAT 0x94
//#BIT SMP=SSPSTAT.7
//#BIT CKE=SSPSTAT.6
//#BIT CKP=SSPCON.4
//#BIT SSPEN=SSPCON.5
//////////////////////////////
// For 18F452
#DEFINE SSPSTAT 0x0FC7
#DEFINE SSPCON1 0x0FC6
#BIT SMP=SSPSTAT.7
#BIT CKE=SSPSTAT.6
#BIT CKP=SSPCON1.4
#DEFINE MAX_FILES 2 /// max number of open files
#DEFINE MMC_BUFF_SIZE 32 /// 32 for PCM
#DEFINE MMC_FILE_NAME_SIZE 32
#DEFINE ROOT_CLUSTER 0
#DEFINE NEXT_CLUSTER 1
#define MMC_INIT_TRACE FALSE
#define MMC_CMD_TRACE FALSE
#define MMC_CLUSTER_TRACE FALSE // if true prints to serial port
#define MMC_OPEN_TRACE FALSE // if true prints to serial port
#define MMC_READ_TRACE FALSE // if true prints file_addr,cluster index etc
#define MMC_WRITE_TRACE FALSE
#define MMC_READ_BLOCK_TRACE FALSE
#define MMC_SET_BLOCK_LEN_TRACE FALSE
#define MMC_WRITE_BLOCK_TRACE FALSE
#define MMC_NEW_CLUSTER FALSE
////// MMC prototypes
#separate
int init_MMC(int max_tries);
#separate
int open_file(int fnbr,char *fname,int16 rec_length);
#separate
int file_read(int8 fnbr,char *buff);
#separate
int file_write(int8 fnbr,int *buff);
#separate
int file_set(int fnbr,int32 offset);
#separate
int file_new_cluster(int8 fnbr,int8 mode); /// mode 1=fat1 2=fat2
int32 atoint32 (char *s );
signed int strncmp(char *s1, char *s2, int n);
///////////////////// MMC GLOBALS /////////////////////////////
int16 cluster_size_bytes; // bytes in a cluster
//int16 dir_cluster_chain_ptr; // link to the first cluster in the dir
int32 fat1_address; // physical address of fat1 cluster table assigned by INIT_MMC
int32 fat2_address; // physical address of fat1 cluster table assigned by INIT_MMC
int32 root_dir_address; // physical address of volume,file,folder tiles assigned by INIT_MMC
int32 data_area_address; // physical address of data area assigned by INIT_MMC
int32 winhex_adj; // Win hex hides the bytes in the reserved sectors
// this means Fat1 is address 512
// so adj is fat1-512
int32 block_size; // current MMC block size
int MMC_init=FALSE;
int MMC_dir_protected=TRUE;
////////// open file specific globals ///////////////////////
struct{
char name[MMC_FILE_NAME_SIZE+1]; // fopen file name
int32 dir_addr_ptr; // physical address of this files tile info
int16 root_cluster_ptr; // location of first cluster in FAT
int16 this_cluster_ptr; // location of current cluster in FAT
int16 next_cluster_ptr; // location of the next cluster for a file or sub dir in FAT
int32 addr_ptr; // physical address in the file the current
// cluster points to
// address=(this_chain_ptr-2)*cluster_size_bytes+data_area_address
//
// cluster_addr(THIS_CLUSTER) assigns it
// cluster_addr(NEXT_CLUSTER) moves to the data the next
// cluster points to
int32 size; // size of open file in bytes
int32 cluster_offset; // offset within the file representing the start of the current cluster
// (0 is start and ends with the cluster contianing eof )
// auto increased by cluster_size_bytes each time a new cluster is entered
int32 offset; // current offset into the open file ( 0 is start size(file size) is end)
// auto increased by rec size each time a rec is read
// addr_prt+offset-cluster_offset is physical address of
// the current position within the file
// the physical positions are not always contiguous since the
// clusters of the file are not always adjacent to each other
int16 rec_size; // fopen record_size
// char buff[MMC_BUFF_SIZE+1]; // used for open and for read write
// init MMC uses file 0 buff to fetch the globals
} file[MAX_FILES];
#separate
int mmc_cmd(int8 cmd,int32 address,int8 tries,int8 valid,int8 invalid){
int i,r1;
for( i=0;i<16;i++) SPI_READ(0xFF);// digest prior operation
// commands
// 7 6 5 4 3 2 1 0
// 0 1 b b b b b b bbbbbb=cmd
// 16=0x50 set blocklength
// 17=0x51 read block
// 24=0x58 write block
#if MMC_CMD_TRACE
printf("\n\r cmd=%2X \n\r",cmd);
#endif
SPI_READ(cmd);
SPI_READ(MAKE8(address,3));
SPI_READ(MAKE8(address,2));
SPI_READ(MAKE8(address,1));
SPI_READ(MAKE8(address,0));
SPI_READ(0x95); // valid crc for 0x40 only invalid for others but spi mode doesn't care
for(i=0;i< tries;i++) {
r1=SPI_READ(0xFF);
#if MMC_CMD_TRACE
printf(" %2X",r1);
#endif
if (r1==valid) break;
if (r1==invalid) break;
}
return(r1);
}
#separate
int set_BLOCKLEN( int32 size){
int r1;
r1=mmc_cmd(0x50,size,16,0x00,0x40); /// cmd.data,tries,valid code,invlaid code
if (r1==0x00) goto done ;
if (r1==0x40) goto invalid;
return(false);
invalid:
#IF MMC_SET_BLOCK_LEN_TRACE
printf("\n\r para err\n\r");
#ENDIF
done:
block_size=size; //// assign global block size
//printf("\n\r blk size=%lu",block_size);
return(true);
}
#separate
int read_BLOCK( int32 address, char *buff){
//// low level read ..requires block len to be called first to set global blocksize
int r1;
long i,iw; /// allows large gt 255 buff size addressing
//int data[128];
r1=mmc_cmd(0x51,address,16,0x00,0x40);
if (r1==0x00) goto get_token ; // we can read data payload
if (r1==0x40) goto invalid;
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 1 address=%lu \n\r",address);
#ENDIF
return(false);
invalid:
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 2 adress=%lu \n\r",address);
#ENDIF
return(false);
get_token:
for(iw=0;iw<1024;iw++){
r1=SPI_READ(0xFF);
//data[iw]=r1;
if (r1==0xFE) goto read_data; // read token $FE
}
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 3 address=%lu \n\r",address);
#ENDIF
return(false);
read_data:
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block tries for FE =%lu \n\r",iw);
#ENDIF
for (i=0;i<block_size;i++) buff[i]=SPI_READ(0xFF);
SPI_READ(0xFF); // read crc
SPI_READ(0xFF);
return(true);
}
//////////////////////////////////////////////////////////////////
///////////////////////////////// INIT MMC ///////////////////////
//////////////////////////////////////////////////////////////////
#separate
int init_MMC(int max_tries){
int32 start_lsec;
int16 sec_resv,sec_for_FAT,bytes_per_sector,root_dir_entries,
sec_for_data,count_of_clusters,root_dir_sectors,total_sectors;
int i,tries,sec_per_cluster,c;
char buff[32];
tries=0;
cmd0:
///////////////////// place null treminators in globals fname and buff
for(i=0;i<MAX_FILES;i++){
file[i].name[0]=0;
file[i].rec_size=32; //// default rec_size = 32 byte tile size of FAT16
}
//buff[MMC_BUFF_SIZE]=0;
//frec_size=32; //// default rec_size = 32 byte tile size of FAT16
output_high(_CS); /// reset chip hardware !!! required
delay_ms(20);
for(i=0;i<20;i++) SPI_READ(0xFF); // min 80 clocks to get MMC ready
output_low(_CS); /// !!! required
delay_ms(20);
#if MMC_INIT_TRACE
printf("cmd0");
#ENDIF
c=mmc_cmd(0x40,0x00000000,128,0x01,0x99);
if (c==0x01) goto exit_cmd1;
// note: i must cycle at least 8 times (16 is safe )
if (tries++<max_tries) goto cmd0; /// restart
else return (10);
exit_cmd1:
// CPDMOD - This SOMETIMES seems to be necessary
// output_high(_CS);
// SPI_READ(0xFF); // min 8 clocks to get MMC ready
// output_low(_CS);
//CPDMOD End
tries=0;
cmd1:
/// now try to switch to idle mode
/// Note: cmd1(idle) is the only command allowed after a cmd0(reset)
//
c=mmc_cmd(0x41,0x00000000,128,0x00,0x99);
if (c==0x00) { goto ready;}
if( tries++<max_tries) { printf("cmd1"); goto cmd1;}
else return(11);
ready:
//for( i=0;i<32;i++) SPI_READ(0xFF);// digest operation
/// MMC is inialized and in idle state ready for commands
////
//// we need to first access the master boot sector physical address=0
///
if(set_BLOCKLEN((int32)32)==false) return(12); /// sets global block_size to 32
if (read_block(0x00000000,buff)==false) return (99); /// read the first few bytes
#if MMC_INIT_TRACE
printf("\n\r sector0=");
for(i=0;i<32;i++)printf("%2X ",buff[i]);
#ENDIF
if (buff[0]==0xEB || buff[0]==0xE9){
/// sector 0 is the boot sector
#if MMC_INIT_TRACE
printf("\n\r boot sector= 0");
#ENDIF
}
else{
//// partition
/// access the master boot sector physical address 0 at offset 1BE
if (read_BLOCK(0x000001BE,buff)==false) return(13);
#if MMC_INIT_TRACE
for(i=0;i<32;i++)printf("%2X ",buff[i]);
#ENDIF
// start_lsec is address of the partion boot sector
start_lsec=make32(buff[11],buff[10],buff[9],buff[8]);
#if MMC_INIT_TRACE
printf("\n\r boot sector= %lu",start_lsec);
#ENDIF
if (read_BLOCK(start_lsec*512,buff)==false) return(14);
}
bytes_per_sector=make16(buff[12],buff[11]);
if(bytes_per_sector!=512) return(15);
sec_per_cluster=buff[13];
cluster_size_bytes=(int16)sec_per_cluster*bytes_per_sector;
sec_resv=make16(buff[15],buff[14]);
root_dir_entries=make16(buff[18],buff[17]);// number of 32 byte tiles
total_sectors=make16(buff[20],buff[19]);
sec_for_FAT=make16(buff[23],buff[22]);
//branch to file directory
fat1_address=(start_lsec+sec_resv)*bytes_per_sector;
fat2_address=fat1_address+bytes_per_sector*sec_for_FAT;
root_dir_address=(sec_for_FAT*2+start_lsec+sec_resv)*bytes_per_sector;
data_area_address=root_dir_address+root_dir_entries*32;
///// check for FAT16
root_dir_sectors=root_dir_entries>>4;
sec_for_data=total_sectors - sec_resv -sec_for_fat*2 -root_dir_sectors;
count_of_clusters=sec_for_data/sec_per_cluster;
if (count_of_clusters <4085 || count_of_clusters>65525) return(17);
winhex_adj=fat1_address-bytes_per_sector;
#if MMC_INIT_TRACE
printf("Files:/n/r");
for(i=0;i<MAX_FILES;i++){
printf("/n/r",file[i].name[i]);
}
#ENDIF
return(0);
}
#separate
int get_CID(char s){
int i,r1;
r1=mmc_cmd(0x4A,0x00000000,16,0x00,0x99);
if (r1==0x00) goto get_token ; // we can read data payload
return(false);
get_token:
for(i=0;i<16;i++)if (SPI_READ(0xFF)==0xFE) goto read_CID; // read token $FE
return(false);
read_CID:
//for (i=0;i<18;i++) s[i]=SPI_READ(0xFF);
return(true);
}
#separate
int get_CSD(char s){
int i,r1;
r1=mmc_cmd(0x4A,0x00000000,16,0x00,0x99);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -