//********************************************************************** // // compactflash.c // // read/write Compact Flash card (8 bits wide), uses FAT16 and LBA-mode // written by Teunis van Beelen 21-12-2004 // // teuniz@gmail.com // for PIC16F877 and BoostC compiler http://www.sourceboost.com // last revision 21-12-2005 // // crystal 20 MHz (HS) // watchdog timer off // powerup timer on // code protect off // brownout detect on // masterclear disabled // lowvoltageprogram disabled // data EE protect off // flash program write disabled // background debug disabled // //******************************************************************** // #include #include "rs232.h" #include "cf_io.h" //**** CONFIGURATION BITS **************************************** #pragma DATA _CONFIG, _WRT_ENABLE_ON & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC // timing settings Hz crystal frequency #pragma CLOCK_FREQ 20000000 unsigned char check_format(void); void fat(void); void read_file(void); void print_sector(void); void write_bootsector(void); void write_root_dir(void); void write_fat(void); void write_file(unsigned char); void error(unsigned char); void fopen(void); void fclose(void); void receive(void); void send_file(void); void erase_sectors(void); unsigned char card_present, key_stroke, lo_byte, hi_byte, temp; unsigned short lo_word, hi_word; struct{ unsigned char sec_per_clus; unsigned short write_file_buf_cnt; unsigned short start_data_sec; unsigned short start_rootdir_sec; unsigned short cluster_size; unsigned short sec_per_fat; unsigned short total_clusters; unsigned short clusters_written; unsigned long sector; unsigned long total_sect; unsigned long file_size; } fs; // use trailing spaces with filenames shorter then 8 characters! const unsigned char file_name[]={'D','A','T','A','L','O','G',' ','T','X','T',0}; unsigned char bootsector[]={ // template for bootsector 235,60,144,77,83,68,79,83,53,46,48,0,2,2,1,0,2,0,2,0, 0,248,243,0,63,0,255,0,0,0,0,0,0,0,0,0,0,0,41,84, 67,77,83,'P','I','C','-','P','R','O','J','E','C','T',70,65,84,49,54,32, 32,32}; extern volatile unsigned char RecFifo[FIFO_SIZE_A], RecFifoCnt1=0, RecFifoCnt2=0, SndFifo[FIFO_SIZE_A], SndFifoCnt1=0, SndFifoCnt2=0; extern unsigned long total_sect; void main(void) { RESET: //************ HARDWARE INITIALIZATION ******************** intcon = 00000000b; // interrupt control register pie1 = 00000000b; pie2 = 00000000b; pir1 = 00000000b; pir2 = 00000000b; clear_bit(adcon0,0); adcon1 = 0x06; trisa = 11110001b; // set RA1,2,3 as output trisb = 11111100b; // set RB0,1 as output trisc = 10100010b; // set RC0,2,3,4,6 as output trisd = 11111111b; // set RD# as input trise = 00000000b; // set RD# as output porta = 00000110b; // set RA1,2(_CE,R/C) portb = 00000000b; portc = 00011000b; // set RC3,RC4, clear RC0(_OE, _WE, _CE1) portd = 00000000b; porte = 00000000b; //*************** SERIAL PORT SECTION *********************** set_bit(txsta,BRGH); // select high baudrate spbrg = 0x0a; // select 115K2 clear_bit(txsta,TX9); // clear_bit(txsta,SYNC); // initialize set_bit(txsta,TXEN); // serial port set_bit(rcsta,SPEN); // intcon = 11000000b; // interrupt control register pie1 = 00100000b; // periferal interrupt register //*********************************************************** delay_ms(1); card_present = 0; RecFifoCnt1=0; RecFifoCnt2=0; SndFifoCnt1=0; SndFifoCnt2=0; putch(0x0c); // formfeed cprintf("\r\nver. 03-03-2006 10:00\r\n"); set_bit(rcsta,CREN); // enable receive //*************** MAIN LOOP ********************************* MAINLOOP: if(!(portc&2)) // card detected? { if(!card_present) { card_present = 1; cprintf("cf-card detected\r\nresetting now..."); reset_card(); cprintf("done\n\rreading driveparms..."); fs.total_sect = get_drive_param(); if(!fs.total_sect) error(1); cprintf("done\r\ntotal sectors on card: "); print_long_dec(fs.total_sect); cprintf("\r\nreading bootsector..."); if(check_format()) { cprintf("error: "); print_dec(temp); putch(' '); error(2); } else { cprintf("done\r\ntotal sectors on disk: "); print_long_dec(fs.total_sect); cprintf("\r\nsectors per cluster: "); print_dec(fs.sec_per_clus); cprintf("\r\nstart of rootdir sector: "); print_short_dec(fs.start_rootdir_sec); cprintf("\r\nstart of data sector: "); print_short_dec(fs.start_data_sec); cprintf("\r\ntotal available clusters: "); print_short_dec(fs.total_clusters); } cprintf("\r\n"); } //*** when u get here then card is and was present ********** // put here your stuff, things you want to do etc. // } else // no card detected { if(card_present) { delay_ms(10); // delay to deglitch carddetect if(portc&2) // still no card present? { card_present = 0; cprintf("cf-card removed\r\n"); } } } if(kbhit()) // something received on serial port? { key_stroke = getch(); // get a byte from serial port if(key_stroke=='r') // reset request { goto RESET; // I don't like goto's... } if(card_present) { if(key_stroke=='f') fat(); // displays FAT-tabel if(key_stroke=='l') read_file(); // file listing if(key_stroke=='p') print_sector(); if(key_stroke=='w') receive(); if(key_stroke=='s') send_file(); if(key_stroke=='e') { cprintf("erasing sectors..."); erase_sectors(); cprintf("done\r\n"); } if(key_stroke=='b') // format cmd { cprintf("formatting..."); fs.total_sect = get_drive_param(); if(!fs.total_sect) error(1); write_bootsector(); cprintf("done\r\n"); } } } goto MAINLOOP; // END OF MAIN LOOP ******************* } //*********** END OF MAIN FUNCTION ********************* //***************** FUNCTIONS *************************** //***************** FILE I/O **************************** void erase_sectors(void) // erases first 530 sectors of CF-card, { // writes zero's unsigned short i; for(i=0; i<530; i++) { read_write_sector(i,1,1); cf_write_null(512); } } void receive(void) // writes data received by serial port to a file on the CF-card { char chr; cprintf("Start text, end with ctl-Z\r\n\r\n"); fopen(); while(1) { if(kbhit()) { chr = getch(); if(chr==26) break; putch(chr); write_file(chr); } } fclose(); cprintf("\r\ncontrol-Z received\r\n"); } void send_file(void) // sends the content of the file on the CF-card to the serial port { unsigned char byte; unsigned short i, temp; fs.sector = fs.start_data_sec; read_write_sector(fs.start_rootdir_sec,0,1); // root dir for(i=0; i<60; i++) cf_read_byte(); temp = cf_read_word(); fs.file_size = cf_read_word(); fs.file_size <<= 16; fs.file_size += temp; if(fs.file_size) { while(1) { read_write_sector(fs.sector, 0, 1); for(i=0; i<512; i++) { byte = cf_read_byte(); putch(byte); fs.file_size--; if(!fs.file_size) { putch(10); putch(13); return; } } fs.sector++; } } putch(10); putch(13); } void fopen(void) // opens a file for writing { fs.file_size = 0; fs.sector = fs.start_data_sec; fs.write_file_buf_cnt = 0; fs.clusters_written = 0; write_root_dir(); read_write_sector(1, 1, 1); // FAT tabel 1 cf_write_word(0xfff8); cf_write_word(0x8fff); // was 0xffff, changed to 0x8fff (volume is "dirty") cf_write_word(0xffff); cf_write_null(506); read_write_sector(fs.sec_per_fat+1, 1, 1); // FAT tabel 2 cf_write_word(0xfff8); cf_write_word(0x8fff); // was 0xffff, changed to 0x8fff (volume is "dirty") cf_write_word(0xffff); cf_write_null(506); read_write_sector(fs.sector, 1, 1); } void fclose(void) // closes the file { if(fs.write_file_buf_cnt) { fs.file_size += fs.write_file_buf_cnt; fs.write_file_buf_cnt = 512 - fs.write_file_buf_cnt; cf_write_null(fs.write_file_buf_cnt); } write_root_dir(); write_fat(); } void write_file(unsigned char file_byte) // write to a file on the CF-card { cf_write_byte(file_byte); fs.write_file_buf_cnt++; if(fs.write_file_buf_cnt<512) return; fs.write_file_buf_cnt = 0; // sector full fs.file_size += 512; fs.sector++; if(!(fs.sector%fs.sec_per_clus)) fs.clusters_written++; if(fs.clusters_written==fs.total_clusters) // card full { cprintf("card full\r\n"); fclose(); cprintf("file closed\r\n"); } else read_write_sector(fs.sector, 1, 1); } void read_file(void) // simple implementation of the "dir" command { unsigned char i, byte; unsigned short cluster; unsigned long temp; read_write_sector(fs.start_rootdir_sec, 0, 1); byte = cf_read_byte(); while(byte) { if(byte==0xe5) // free entry { for(i=0; i<32; i++) byte = cf_read_byte(); // ga naar volgend entry continue; } putch(byte); for(i=1; i<8; i++) { byte = cf_read_byte(); if(byte!=' ') putch(byte); } putch('.'); for(; i<11; i++) { byte = cf_read_byte(); if(byte!=' ') putch(byte); } for(; i<26; i++) cf_read_byte(); cluster = cf_read_word(); cprintf(" startcluster is "); print_short_dec(cluster); cprintf(", filesize is "); cluster = cf_read_word(); temp = cf_read_word(); temp = (temp << 16) + cluster; print_long_dec(temp); cprintf(" bytes\r\n"); byte = cf_read_byte(); } activate_powersave(); } void print_sector(void) // prints the content of the first sector of the CF-card, { // used for debugging purposes unsigned char i, byte; read_write_sector(0, 0, 1); cprintf("\r\n"); for(i=0; i<200; i++) { byte = cf_read_byte(); print_dec(byte); putch(','); } cprintf("\r\n"); for(i=0; i<200; i++) { byte = cf_read_byte(); print_dec(byte); putch(','); } cprintf("\r\n"); for(i=0; i<112; i++) { byte = cf_read_byte(); print_dec(byte); putch(','); } cprintf("\r\n"); } //***************** FAT ********************************* void write_fat(void) // writes a FAT16 tabel { unsigned char i=2; unsigned short p=2, clusters; fs.sector = 1; // FAT tabel 1 clusters = fs.file_size / fs.cluster_size; read_write_sector(fs.sector, 1, 1); cf_write_word(0xfff8); cf_write_word(0xffff); // volume is clean while(clusters--) { cf_write_word(++p); i++; if(!i) { fs.sector++; read_write_sector(fs.sector, 1, 1); } } cf_write_word(0xffff); i++; while(i++) cf_write_word(0); //--------- FAT tabel 2 ------------------------- p = 2; i = 2; fs.sector = fs.sec_per_fat + 1; // FAT tabel 2 clusters = fs.file_size / fs.cluster_size; read_write_sector(fs.sector, 1, 1); cf_write_word(0xfff8); cf_write_word(0xffff); // volume is clean while(clusters--) { cf_write_word(++p); i++; if(!i) { fs.sector++; read_write_sector(fs.sector,1,1); } } cf_write_word(0xffff); i++; while(i++) cf_write_word(0); } void write_bootsector(void) // writes a valid FAT16 bootsector and { // formats the CF-card unsigned char i; unsigned short stmp; fs.total_sect = get_drive_param(); fs.sec_per_clus = 2; if(fs.total_sect> 0x10000) fs.sec_per_clus = 4; if(fs.total_sect> 0x30000) fs.sec_per_clus = 8; if(fs.total_sect> 0x70000) fs.sec_per_clus = 16; if(fs.total_sect> 0xf0000) fs.sec_per_clus = 32; if(fs.total_sect>0x1f0000) fs.sec_per_clus = 64; bootsector[0x0d] = fs.sec_per_clus; if(fs.total_sect<0x10000) { bootsector[0x13] = fs.total_sect; bootsector[0x14] = fs.total_sect >> 8; } else { bootsector[0x20] = fs.total_sect; bootsector[0x21] = fs.total_sect >> 8; bootsector[0x22] = fs.total_sect >> 16; bootsector[0x23] = fs.total_sect >> 24; } fs.sec_per_fat = 256; bootsector[0x16] = fs.sec_per_fat; bootsector[0x17] = fs.sec_per_fat >> 8; fs.cluster_size = 512 * fs.sec_per_clus; fs.start_rootdir_sec = (fs.sec_per_fat * 2) + 1; fs.start_data_sec = fs.start_rootdir_sec + 32; fs.file_size = 0; read_write_sector(0, 1, 1); for(i=0; i<62; i++) cf_write_byte(bootsector[i]); cf_write_null(448); cf_write_byte(0x55); cf_write_byte(0xaa); for(stmp=1; stmp> 16; cf_write_word(temp); cf_write_null(448); } void fat(void) // prints the first 20 entry's of FAT-tabel, { // used for debugging purposes unsigned char i; unsigned short word; read_write_sector(1, 0, 1); for(i=0; i<20; i++) { word = cf_read_word(); print_short_dec(word); putch(10); putch(13); } putch(10); putch(13); } unsigned char check_format(void) // checks for a valid bootsector and { // initialize important variables unsigned char i; // needed for filesystem unsigned short tmp; unsigned long long_tmp; read_write_sector(0,0,1); for(i=0; i<11; i++) cf_read_byte(); lo_byte = cf_read_byte(); // offset 0x0b hi_byte = cf_read_byte(); if((hi_byte!=2)||(lo_byte)) return(1); // 512 bytes per sector fs.sec_per_clus = cf_read_byte(); // offset 0x0d lo_byte = cf_read_byte(); // offset 0x0e hi_byte = cf_read_byte(); if((hi_byte)||(lo_byte!=1)) return(2); // 1 reserved sector lo_byte = cf_read_byte(); // offset 0x10 if(lo_byte!=2) error(3); // 2 copy's of FAT lo_byte = cf_read_byte(); // offset 0x11 hi_byte = cf_read_byte(); if((hi_byte!=2)||(lo_byte)) return(3); // 512 dir entries in root fs.total_sect = cf_read_word(); // offset 0x13 cf_read_byte(); fs.sec_per_fat = cf_read_word(); // offset 0x16 for(i=0; i<8; i++) cf_read_byte(); if(!fs.total_sect) { tmp = cf_read_word(); // offset 0x20 fs.total_sect = cf_read_word(); // offset 0x22 fs.total_sect <<= 16; fs.total_sect += tmp; } else { for(i=0; i<4; i++) cf_read_byte(); } for(i=0; i<18; i++) cf_read_byte(); lo_byte = cf_read_byte(); // offset 0x36 if(lo_byte!='F') return(4); lo_byte = cf_read_byte(); if(lo_byte!='A') return(5); lo_byte = cf_read_byte(); if(lo_byte!='T') return(6); lo_byte = cf_read_byte(); if(lo_byte!='1') return(7); lo_byte = cf_read_byte(); if(lo_byte!='6') return(8); fs.cluster_size = 512 * fs.sec_per_clus; fs.start_rootdir_sec = (fs.sec_per_fat * 2) + 1; fs.start_data_sec = fs.start_rootdir_sec + 32; long_tmp = fs.total_sect - fs.start_data_sec; // total sectors minus boot, fat and rootdir sectors long_tmp--; long_tmp /= fs.sec_per_clus; fs.total_clusters = long_tmp; return(0); } void error(unsigned char code) { if(code==1) cprintf("wrong media-type..."); if(code==2) cprintf("wrong format..."); } //************* interrupt function *************************************** void interrupt(void) { if(pir1&32) // RCIF USART receive interrupt flag bit, { // handles received characters on serial port if(rcsta&6) // frame error, overrun error { clear_bit(rcsta,CREN); nop(); set_bit(rcsta,CREN); } RecFifo[RecFifoCnt1] = rcreg; if(RecFifoCnt1