diff --git a/poc/poc_mmc/Makefile b/poc/poc_mmc/Makefile new file mode 100644 index 0000000..93ef1eb --- /dev/null +++ b/poc/poc_mmc/Makefile @@ -0,0 +1,446 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# WinAVR makefile written by Eric B. Weddington, Jörg Wunsch, et al. +# Released to the Public Domain +# Please read the make user manual! +# +# Additional material for this makefile was submitted by: +# Tim Henigan +# Peter Fleury +# Reiner Patommel +# Sander Pool +# Frederik Rouleau +# Markus Pfaff +# +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF (for use with AVR Studio 3.x or VMLAB). +# +# make extcoff = Convert ELF to AVR Extended COFF (for use with AVR Studio +# 4.07 or greater). +# +# make program = Download the hex file to the device, using avrdude. Please +# customize the avrdude settings below first! +# +# make filename.s = Just compile filename.c into the assembler code only +# +# To rebuild project do "make clean" then "make all". +# + +# mth 2004/09 +# Differences from WinAVR 20040720 sample: +# - DEPFLAGS according to Eric Weddingtion's fix (avrfreaks/gcc-forum) +# - F_OSC Define in CFLAGS and AFLAGS + + +# MCU name +MCU = atmega8 + +# Main Oscillator Frequency +# This is only used to define F_OSC in all assembler and c-sources. +F_OSC = 8000000 + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + +# Target file name (without extension). +TARGET = main + + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(TARGET).c uart.c fat.c mmc.c + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +#DEBUG = stabs +#DEBUG = dwarf-2 + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +EXTRAINCDIRS = + + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 + +# Place -D or -U options here +CDEFS = + +# Place -I options here +CINCS = + + +# Compiler flags. +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) $(CINCS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wstrict-prototypes +CFLAGS += -Wa,-adhlns=$(<:.c=.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) +CFLAGS += -DF_OSC=$(F_OSC) +CFLAGS += -DF_CPU=8000000UL +#CFLAGS += -DF_CPU=3686400UL + + +# Assembler flags. +# -Wa,...: tell GCC to pass this to the assembler. +# -ahlms: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +ASFLAGS += -DF_OSC=$(F_OSC) + + +#Additional libraries. + +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +PRINTF_LIB = + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +SCANF_LIB = + +MATH_LIB = -lm + +# External memory options + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + +# Linker flags. +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) + + + + +# Programming support using avrdude. Settings and variables. + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = stk500v2 + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = /dev/ttyUSB0 # programmer connected to serial device + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + +# +# Mega8 set to internal 4mhz +# avrdude -p atmega8 -P /dev/ttyUSB0 -c stk500v2 -U lfuse:w:0xe3:m +# + + +# --------------------------------------------------------------------------- + +# Define directories, if needed. +DIRAVR = c:/winavr +DIRAVRBIN = $(DIRAVR)/bin +DIRAVRUTILS = $(DIRAVR)/utils/bin +DIRINC = . +DIRLIB = $(DIRAVR)/avr/lib + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +COPY = cp + + + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: + + + + +# Define all object files. +OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) + + +# Compiler flags to generate dependency files. +### GENDEPFLAGS = -Wp,-M,-MP,-MT,$(*F).o,-MF,.dep/$(@F).d +GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter finished end + +build: elf hex eep lss sym + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +finished: + @echo $(MSG_ERRORS_NONE) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) -A $(TARGET).elf +sizebefore: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi + +sizeafter: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. + +flash_avrdude: flash + +flash: $(TARGET).hex $(TARGET).eep + sudo $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +flash_uisp: + sudo uisp -dprog=avr910 -dpart=ATmega8 -dserial=/dev/ttyUSB0 --verify --erase -v --upload if=$(TARGET).hex + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +# Target: clean project. +clean: begin clean_list finished end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).a90 + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lnk + $(REMOVE) $(TARGET).lss + $(REMOVE) $(OBJ) + $(REMOVE) $(LST) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) .dep/* + + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list program + diff --git a/poc/poc_mmc/fat.c b/poc/poc_mmc/fat.c new file mode 100644 index 0000000..22e38ed --- /dev/null +++ b/poc/poc_mmc/fat.c @@ -0,0 +1,316 @@ +/*####################################################################################### +FAT for AVR (MMC/SD) + +Copyright (C) 2004 Ulrich Radig + +Bei Fragen und Verbesserungen wendet euch per EMail an + +mail@ulrichradig.de + +oder im Forum meiner Web Page : www.ulrichradig.de + + +Dieses Programm ist freie Software. Sie können es unter den Bedingungen der +GNU General Public License, wie von der Free Software Foundation veröffentlicht, +weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder +(nach Ihrer Option) jeder späteren Version. + +Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, +daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, +sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT +FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. + +Sie sollten eine Kopie der GNU General Public License zusammen mit diesem +Programm erhalten haben. +Falls nicht, schreiben Sie an die Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +#######################################################################################*/ + +#include "fat.h" + +unsigned char cluster_size; +unsigned int fat_offset; +unsigned int cluster_offset; +unsigned int volume_boot_record_addr; + +//############################################################################ +//Auslesen Cluster Size der MMC/SD Karte und Speichern der größe ins EEprom +//Auslesen Cluster Offset der MMC/SD Karte und Speichern der größe ins EEprom +void fat_init (uint8_t *Buffer) +//############################################################################ +{ + struct BootSec *bootp; //Zeiger auf Bootsektor Struktur + +// unsigned char Buffer[BlockSize]; + + //volume_boot_record_addr = fat_addr (Buffer); + mmc_read_sector (MASTER_BOOT_RECORD,Buffer); //Read Master Boot Record + if (Buffer[510] == 0x55 && Buffer[511] == 0xAA) + { + FAT_DEBUG("MBR Signatur found!\r\n"); + } + else + { + FAT_DEBUG("MBR Signatur not found!\r\n"); + while(1); + } + + + volume_boot_record_addr = Buffer[VBR_ADDR] + (Buffer[VBR_ADDR+1] << 8); + + mmc_read_sector (volume_boot_record_addr,Buffer); + if (Buffer[510] == 0x55 && Buffer[511] == 0xAA) + { + FAT_DEBUG("VBR Signatur found!\r\n"); + } + else + { + FAT_DEBUG("VBR Signatur not found!\r\n"); + volume_boot_record_addr = MASTER_BOOT_RECORD;//<- added by Hennie + mmc_read_sector (MASTER_BOOT_RECORD,Buffer); //Read Master Boot Record + } + + bootp=(struct BootSec *)Buffer; + cluster_size = bootp->BPB_SecPerClus; + fat_offset = bootp->BPB_RsvdSecCnt; + + cluster_offset = ((bootp->BPB_BytesPerSec * 32)/BlockSize); + cluster_offset += fat_root_dir_addr(Buffer); +} + +//############################################################################ +//Auslesen der Adresse des First Root Directory von Volume Boot Record +unsigned int fat_root_dir_addr (unsigned char *Buffer) +//############################################################################ +{ + struct BootSec *bootp; //Zeiger auf Bootsektor Struktur + unsigned int FirstRootDirSecNum; + //auslesen des Volume Boot Record von der MMC/SD Karte + mmc_read_sector (volume_boot_record_addr,Buffer); + bootp=(struct BootSec *)Buffer; + + //berechnet den ersten Sector des Root Directory + FirstRootDirSecNum = ( bootp->BPB_RsvdSecCnt + + (bootp->BPB_NumFATs * bootp->BPB_FATSz16)); + + FirstRootDirSecNum+= volume_boot_record_addr; + + return(FirstRootDirSecNum); +} + +//############################################################################ +// Ausgabe des angegebenen Directory Eintrag in Entry_Count +// ist kein Eintrag vorhanden, ist der Eintrag im +// Rückgabe Cluster 0xFFFF. Es wird immer nur ein Eintrag ausgegeben +// um Speicherplatz zu sparen um es auch für kleine Atmels zu benutzen +unsigned int fat_read_dir_ent (unsigned int dir_cluster, //Angabe Dir Cluster + unsigned char Entry_Count, //Angabe welcher Direintrag + unsigned long *Size, //Rückgabe der File Größe + unsigned char *Dir_Attrib, //Rückgabe des Dir Attributs + unsigned char *Buffer) //Working Buffer +//############################################################################ +{ + unsigned char *pointer; + unsigned int TMP_Entry_Count = 0; + unsigned long Block = 0; + struct DirEntry *dir; //Zeiger auf einen Verzeichniseintrag + + pointer = Buffer; + + if (dir_cluster == 0) + { + Block = fat_root_dir_addr(Buffer); + } + else + { + //Berechnung des Blocks aus BlockCount und Cluster aus FATTabelle + //Berechnung welcher Cluster zu laden ist + //Auslesen der FAT - Tabelle + fat_load (dir_cluster,&Block,Buffer); + Block = ((Block-2) * cluster_size) + cluster_offset; + } + + //auslesen des gesamten Root Directory + for (unsigned int blk = Block;;blk++) + { + mmc_read_sector (blk,Buffer); //Lesen eines Blocks des Root Directory + for (unsigned int a=0;aDIR_Name[0] == 0) //Kein weiterer Eintrag wenn erstes Zeichen des Namens 0 ist + { + return (0xFFFF); + } + + //Prüfen ob es ein 8.3 Eintrag ist + //Das ist der Fall wenn es sich nicht um einen Eintrag für lange Dateinamen + //oder um einen als gelöscht markierten Eintrag handelt. + if ((dir->DIR_Attr != ATTR_LONG_NAME) && + (dir->DIR_Name[0] != DIR_ENTRY_IS_FREE)) + { + //Ist es der gewünschte Verzeichniseintrag + if (TMP_Entry_Count == Entry_Count) + { + //Speichern des Verzeichnis Eintrages in den Rückgabe Buffer + for(unsigned char b=0;b<11;b++) + { + if (dir->DIR_Name[b] != SPACE) + { + if (b == 8) + { + *pointer++= '.'; + } + *pointer++=dir->DIR_Name[b]; + } + } + *pointer++='\0'; + *Dir_Attrib = dir->DIR_Attr; + + //Speichern der Filegröße + *Size=dir->DIR_FileSize; + + //Speichern des Clusters des Verzeichniseintrages + dir_cluster = dir->DIR_FstClusLO; + + //Eintrag gefunden Rücksprung mit Cluster File Start + return(dir_cluster); + } + TMP_Entry_Count++; + } + } + } + return (0xFFFF); //Kein Eintrag mehr gefunden Rücksprung mit 0xFFFF +} + +//############################################################################ +// Auslesen der Cluster für ein File aus der FAT +// in den Buffer(512Byte). Bei einer 128MB MMC/SD +// Karte ist die Cluster größe normalerweise 16KB groß +// das bedeutet das File kann max. 4MByte groß sein. +// Bei größeren Files muß der Buffer größer definiert +// werden! (Ready) +// Cluster = Start Clusterangabe aus dem Directory +void fat_load ( unsigned int Cluster, //Angabe Startcluster + unsigned long *Block, + unsigned char *TMP_Buffer) //Workingbuffer +//############################################################################ +{ + //Zum Überprüfen ob der FAT Block schon geladen wurde + unsigned int FAT_Block_Store = 0; + + //Byte Adresse innerhalb des Fat Blocks + unsigned int FAT_Byte_Addresse; + + //FAT Block Adresse + unsigned int FAT_Block_Addresse; + + //Berechnung für den ersten FAT Block (FAT Start Addresse) + for (unsigned int a = 0;;a++) + { + if (a == *Block) + { + *Block = (0x0000FFFF & Cluster); + return; + } + + if (Cluster == 0xFFFF) + { + break; //Ist das Ende des Files erreicht Schleife beenden + } + //Berechnung des Bytes innerhalb des FAT Block´s + FAT_Byte_Addresse = (Cluster*2) % BlockSize; + + //Berechnung des Blocks der gelesen werden muß + FAT_Block_Addresse = ((Cluster*2) / BlockSize) + + volume_boot_record_addr + fat_offset; + //Lesen des FAT Blocks + //Überprüfung ob dieser Block schon gelesen wurde + if (FAT_Block_Addresse != FAT_Block_Store) + { + FAT_Block_Store = FAT_Block_Addresse; + //Lesen des FAT Blocks + mmc_read_sector (FAT_Block_Addresse,TMP_Buffer); + } + + //Lesen der nächsten Clusternummer + Cluster = (TMP_Buffer[FAT_Byte_Addresse + 1] << 8) + + TMP_Buffer[FAT_Byte_Addresse]; + } + return; +} + +//############################################################################ +//Lesen eines 512Bytes Blocks von einem File +void fat_read_file (unsigned int Cluster,//Angabe des Startclusters vom File + unsigned char *Buffer, //Workingbuffer + unsigned long BlockCount) //Angabe welcher Bock vom File geladen + //werden soll a 512 Bytes +//############################################################################ +{ + //Berechnung des Blocks aus BlockCount und Cluster aus FATTabelle + //Berechnung welcher Cluster zu laden ist + + unsigned long Block = (BlockCount/cluster_size); + + //Auslesen der FAT - Tabelle + fat_load (Cluster,&Block,Buffer); + Block = ((Block-2) * cluster_size) + cluster_offset; + //Berechnung des Blocks innerhalb des Cluster + Block += (BlockCount % cluster_size); + //Read Data Block from Device + mmc_read_sector (Block,Buffer); + return; +} + +//############################################################################ +//Lesen eines 512Bytes Blocks von einem File +void fat_write_file (unsigned int cluster,//Angabe des Startclusters vom File + unsigned char *buffer, //Workingbuffer + unsigned long blockCount) //Angabe welcher Bock vom File gespeichert + //werden soll a 512 Bytes +//############################################################################ +{ + //Berechnung des Blocks aus BlockCount und Cluster aus FATTabelle + //Berechnung welcher Cluster zu speichern ist + unsigned char tmp_buffer[513]; + unsigned long block = (blockCount/cluster_size); + + //Auslesen der FAT - Tabelle + fat_load (cluster,&block,tmp_buffer); + block = ((block-2) * cluster_size) + cluster_offset; + //Berechnung des Blocks innerhalb des Cluster + block += (blockCount % cluster_size); + //Write Data Block to Device + mmc_write_sector (block,buffer); + return; +} + +//#################################################################################### +//Sucht ein File im Directory +unsigned char fat_search_file (unsigned char *File_Name, //Name des zu suchenden Files + unsigned int *Cluster, //Angabe Dir Cluster welches + //durchsucht werden soll + //und Rückgabe des clusters + //vom File welches gefunden + //wurde + unsigned long *Size, //Rückgabe der File Größe + unsigned char *Dir_Attrib,//Rückgabe des Dir Attributs + unsigned char *Buffer) //Working Buffer +//#################################################################################### +{ + unsigned int Dir_Cluster_Store = *Cluster; + for (unsigned char a = 0;a < 100;a++) + { + *Cluster = fat_read_dir_ent(Dir_Cluster_Store,a,Size,Dir_Attrib,Buffer); + if (*Cluster == 0xffff) + { + return(0); //File not Found + } + if(strcasecmp((char *)File_Name,(char *)Buffer) == 0) + { + return(1); //File Found + } + } + return(2); //Error +} diff --git a/poc/poc_mmc/fat.h b/poc/poc_mmc/fat.h new file mode 100644 index 0000000..198809e --- /dev/null +++ b/poc/poc_mmc/fat.h @@ -0,0 +1,109 @@ +/*####################################################################################### +Connect ARM to MMC/SD + +Copyright (C) 2004 Ulrich Radig +#######################################################################################*/ + +#ifndef _FAT_H_ + #define _FAT_H_ + +#include +#include "mmc.h" +#include "uart.h" + +#define FAT_DEBUG uart_puts +//#define FAT_DEBUG(...) + + +//Prototypes +extern unsigned int fat_root_dir_addr (unsigned char *); +extern unsigned int fat_read_dir_ent (unsigned int,unsigned char,unsigned long*,unsigned char *,unsigned char *); +extern void fat_load (unsigned int,unsigned long *,unsigned char *); +extern void fat_read_file (unsigned int,unsigned char *,unsigned long); +extern void fat_write_file (unsigned int,unsigned char *,unsigned long); +extern void fat_init (uint8_t *Buffer); +extern unsigned char fat_search_file (unsigned char *,unsigned int *,unsigned long *,unsigned char *,unsigned char *); + +//Block Size in Bytes +#define BlockSize 512 + +//Master Boot Record +#define MASTER_BOOT_RECORD 0 + +//Volume Boot Record location in Master Boot Record +#define VBR_ADDR 0x1C6 + +//define ASCII +#define SPACE 0x20 +#define DIR_ENTRY_IS_FREE 0xE5 +#define FIRST_LONG_ENTRY 0x01 +#define SECOND_LONG_ENTRY 0x42 + +//define DIR_Attr +#define ATTR_LONG_NAME 0x0F +#define ATTR_READ_ONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME_ID 0x08 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 + +struct BootSec +{ + unsigned char BS_jmpBoot[3]; + unsigned char BS_OEMName[8]; + unsigned int BPB_BytesPerSec; //2 bytes + unsigned char BPB_SecPerClus; + unsigned int BPB_RsvdSecCnt; //2 bytes + unsigned char BPB_NumFATs; + unsigned int BPB_RootEntCnt; //2 bytes + unsigned int BPB_TotSec16; //2 bytes + unsigned char BPB_Media; + unsigned int BPB_FATSz16; //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 +}; + +//FAT12 and FAT16 Structure Starting at Offset 36 +#define BS_DRVNUM 36 +#define BS_RESERVED1 37 +#define BS_BOOTSIG 38 +#define BS_VOLID 39 +#define BS_VOLLAB 43 +#define BS_FILSYSTYPE 54 + +//FAT32 Structure Starting at Offset 36 +#define BPB_FATSZ32 36 +#define BPB_EXTFLAGS 40 +#define BPB_FSVER 42 +#define BPB_ROOTCLUS 44 +#define BPB_FSINFO 48 +#define BPB_BKBOOTSEC 50 +#define BPB_RESERVED 52 + +#define FAT32_BS_DRVNUM 64 +#define FAT32_BS_RESERVED1 65 +#define FAT32_BS_BOOTSIG 66 +#define FAT32_BS_VOLID 67 +#define FAT32_BS_VOLLAB 71 +#define FAT32_BS_FILSYSTYPE 82 +//End of Boot Sctor and BPB Structure + +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; //set to zero + unsigned char DIR_CrtTimeTenth; //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_FstClusLO; //first cluster low word + unsigned long DIR_FileSize; + }; + +#endif //_FAT_H_ diff --git a/poc/poc_mmc/main.c b/poc/poc_mmc/main.c new file mode 100644 index 0000000..dbdab26 --- /dev/null +++ b/poc/poc_mmc/main.c @@ -0,0 +1,228 @@ +#define F_CPU 8000000 + +#include +#include +#include + +#include "uart.h" +#include "mmc.h" +#include "fat.h" + +//SREG defines +#define S_MOSI PB3 +#define S_MISO PB4 +#define S_SCK PB5 +#define S_LATCH PB2 + +//DEBUG defines +#define D_LED0 PC5 + +//SRAM defines +#define R_WR PB6 +#define R_RD PB7 +#define R_DATA PORTD +#define R_DIR DDRD + + + +void SPI_MasterInit(void) +{ + /* Set MOSI and SCK output, all others input */ + DDRB |= ((1<>16)); + SPI_MasterTransmit((uint8_t)(addr>>8)); + SPI_MasterTransmit((uint8_t)(addr>>0)); + + PORTB |= (1<>16)); + SPI_MasterTransmit((uint8_t)(addr>>8)); + SPI_MasterTransmit((uint8_t)(addr>>0)); + + PORTB |= (1< + +//############################################################################ +//Routine zur Initialisierung der MMC/SD-Karte (SPI-MODE) +unsigned char mmc_init () +//############################################################################ +{ + unsigned int Timeout = 0,i; + + //Konfiguration des Ports an der die MMC/SD-Karte angeschlossen wurde + DDRC |= ( (1< 20) + { + MMC_Disable(); + return(1); //Abbruch bei Commando1 (Return Code1) + } + } + + //Sendet Commando CMD1 an MMC/SD-Karte + Timeout = 0; + + CMD[0] = 0x41;//Commando 1 + CMD[5] = 0xFF; + + while( mmc_write_command (CMD) !=0) + { + if (Timeout++ > 800) + { + MMC_Disable(); + return(9); //Abbruch bei Commando2 (Return Code2) + } + } + return(0); +} + +//############################################################################ +//Sendet ein Commando an die MMC/SD-Karte +unsigned char mmc_write_command (unsigned char *cmd) +//############################################################################ +{ + unsigned char tmp = 0xff; + unsigned int Timeout = 0; + + + //sendet 6 Byte Commando + for (unsigned char a = 0;a<0x06;a++) //sendet 6 Byte Commando zur MMC/SD-Karte + { + mmc_write_byte(*cmd++); + } + + //Wartet auf ein gültige Antwort von der MMC/SD-Karte + while (tmp == 0xff) + { + tmp = mmc_read_byte(); + + if (Timeout++ > 50) + { + break; //Abbruch da die MMC/SD-Karte nicht Antwortet + } + } + return(tmp); +} + +//############################################################################ +//Routine zum Empfangen eines Bytes von der MMC-Karte +unsigned char mmc_read_byte (void) +//############################################################################ +{ + uint8_t Byte=0,j; + + for(j=0; j<8; j++){ + Byte = (Byte<<1); + + PORTC |= (1<>24 ); + cmd[2] = ((addr & 0x00FF0000) >>16 ); + cmd[3] = ((addr & 0x0000FF00) >>8 ); + + //Sendet Commando cmd24 an MMC/SD-Karte (Write 1 Block/512 Bytes) + tmp = mmc_write_command (cmd); + if (tmp != 0) + { + return(tmp); + } + + //Wartet einen Moment und sendet einen Clock an die MMC/SD-Karte + for (unsigned char a=0;a<100;a++) + { + mmc_read_byte(); + } + + //Sendet Start Byte an MMC/SD-Karte + mmc_write_byte(0xFE); + + //Schreiben des Bolcks (512Bytes) auf MMC/SD-Karte + for (unsigned int a=0;a<512;a++) + { + mmc_write_byte(*Buffer++); + } + + //CRC-Byte schreiben + mmc_write_byte(0xFF); //Schreibt Dummy CRC + mmc_write_byte(0xFF); //CRC Code wird nicht benutzt + + //Fehler beim schreiben? (Data Response XXX00101 = OK) + if((mmc_read_byte()&0x1F) != 0x05) return(1); + + //Wartet auf MMC/SD-Karte Bussy + while (mmc_read_byte() != 0xff){}; + + +return(0); +} + +//############################################################################ +//Routine zum lesen des CID Registers von der MMC/SD-Karte (16Bytes) +void mmc_read_block(unsigned char *cmd,unsigned char *Buffer,unsigned int Bytes) +//############################################################################ +{ + //Sendet Commando cmd an MMC/SD-Karte + if (mmc_write_command (cmd) != 0) + { + return; + } + + //Wartet auf Start Byte von der MMC/SD-Karte (FEh/Start Byte) + + while (mmc_read_byte() != 0xfe){}; + + //Lesen des Bolcks (normal 512Bytes) von MMC/SD-Karte + for (unsigned int a=0;a>24 ); + cmd[2] = ((addr & 0x00FF0000) >>16 ); + cmd[3] = ((addr & 0x0000FF00) >>8 ); + + mmc_read_block(cmd,Buffer,512); + + return(0); +} + +//############################################################################ +//Routine zum lesen des CID Registers von der MMC/SD-Karte (16Bytes) +unsigned char mmc_read_cid (unsigned char *Buffer) +//############################################################################ +{ + //Commando zum lesen des CID Registers + unsigned char cmd[] = {0x4A,0x00,0x00,0x00,0x00,0xFF}; + + mmc_read_block(cmd,Buffer,16); + + return(0); +} + +//############################################################################ +//Routine zum lesen des CSD Registers von der MMC/SD-Karte (16Bytes) +unsigned char mmc_read_csd (unsigned char *Buffer) +//############################################################################ +{ + //Commando zum lesen des CSD Registers + unsigned char cmd[] = {0x49,0x00,0x00,0x00,0x00,0xFF}; + + mmc_read_block(cmd,Buffer,16); + return(0); +} diff --git a/poc/poc_mmc/mmc.h b/poc/poc_mmc/mmc.h new file mode 100644 index 0000000..2a251a0 --- /dev/null +++ b/poc/poc_mmc/mmc.h @@ -0,0 +1,57 @@ +/*####################################################################################### +Connect ARM to MMC/SD + +Copyright (C) 2004 Ulrich Radig +#######################################################################################*/ + +#ifndef _MMC_H_ + #define _MMC_H_ + +#include + +//#define SPI_Mode 1 //1 = Hardware SPI | 0 = Software SPI +#define SPI_Mode 0 + +#define MMC_Write PORTC //Port an der die MMC/SD-Karte angeschlossen ist also des SPI +#define MMC_Read PINC +#define MMC_Direction_REG DDRC + +#if defined (__AVR_ATmega8__) +#define MMC_CS PC0 +#define MMC_DO PC1 +#define MMC_DI PC2 +#define MMC_CLK PC3 + #define SPI_SS 4 //Nicht Benutz muß aber definiert werden +#endif + + +//Prototypes +extern unsigned char mmc_read_byte(void); + +extern void mmc_write_byte(unsigned char); + +extern void mmc_read_block(unsigned char *,unsigned char *,unsigned in); + +extern unsigned char mmc_init(void); + +extern unsigned char mmc_read_sector (unsigned long,unsigned char *); + +extern unsigned char mmc_write_sector (unsigned long,unsigned char *); + +extern unsigned char mmc_write_command (unsigned char *); + +extern unsigned char mmc_read_csd (unsigned char *); + +extern unsigned char mmc_read_cid (unsigned char *); + +//set MMC_Chip_Select to high (MMC/SD-Karte Inaktiv) +#define MMC_Disable() MMC_Write|= (1< +#include + +#ifndef SIGNAL +#include +#endif // SIGNAL + +#include "uart.h" + +// Folgende Zeile einkommentieren, falls FIFO verwendet werden soll +// #include "fifo.h" + +#define BAUDRATE 9600 +#define F_CPU 8000000 + +#define nop() __asm volatile ("nop") + +#ifdef SUART_TXD + #define SUART_TXD_PORT PORTB + #define SUART_TXD_DDR DDRB + #define SUART_TXD_BIT PB1 + static volatile uint16_t outframe; +#endif // SUART_TXD + +#ifdef SUART_RXD + #define SUART_RXD_PORT PORTB + #define SUART_RXD_PIN PINB + #define SUART_RXD_DDR DDRB + #define SUART_RXD_BIT PB0 + static volatile uint16_t inframe; + static volatile uint8_t inbits, received; + + #ifdef _FIFO_H_ + #define INBUF_SIZE 4 + static uint8_t inbuf[INBUF_SIZE]; + fifo_t infifo; + #else // _FIFO_H_ + static volatile uint8_t indata; + #endif // _FIFO_H_ +#endif // SUART_RXD + + +// Initialisierung für einen ATmega8 +// Für andere AVR-Derivate sieht dies vermutlich anders aus: +// Registernamen ändern sich (zB TIMSK0 anstatt TIMSK, etc). +void uart_init() +{ + uint8_t tifr = 0; + uint8_t sreg = SREG; + cli(); + + // Mode #4 für Timer1 + // und volle MCU clock + // IC Noise Cancel + // IC on Falling Edge + TCCR1A = 0; + TCCR1B = (1 << WGM12) | (1 << CS10) | (0 << ICES1) | (1 << ICNC1); + + // OutputCompare für gewünschte Timer1 Frequenz + OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE); + +#ifdef SUART_RXD + SUART_RXD_DDR &= ~(1 << SUART_RXD_BIT); + SUART_RXD_PORT |= (1 << SUART_RXD_BIT); + TIMSK |= (1 << TICIE1); + tifr |= (1 << ICF1) | (1 << OCF1B); +#else + TIMSK &= ~(1 << TICIE1); +#endif // SUART_RXD + +#ifdef SUART_TXD + tifr |= (1 << OCF1A); + SUART_TXD_PORT |= (1 << SUART_TXD_BIT); + SUART_TXD_DDR |= (1 << SUART_TXD_BIT); + outframe = 0; +#endif // SUART_TXD + + TIFR = tifr; + + SREG = sreg; +} + + +#ifdef SUART_TXD +void uart_putc (uint8_t c) +{ + do + { + sei(); nop(); cli(); // yield(); + } while (outframe); + + // frame = *.P.7.6.5.4.3.2.1.0.S S=Start(0), P=Stop(1), *=Endemarke(1) + outframe = (3 << 9) | (((uint8_t) c) << 1); + + TIMSK |= (1 << OCIE1A); + TIFR = (1 << OCF1A); + + sei(); +} + +void uart_puts (uint8_t *buf) +{ + while( *buf ) + uart_putc ( *buf++ ); + +} +#endif // SUART_TXD + + +#ifdef SUART_TXD +SIGNAL (SIG_OUTPUT_COMPARE1A) +{ + uint16_t data = outframe; + + if (data & 1) SUART_TXD_PORT |= (1 << SUART_TXD_BIT); + else SUART_TXD_PORT &= ~(1 << SUART_TXD_BIT); + + if (1 == data) + { + TIMSK &= ~(1 << OCIE1A); + } + + outframe = data >> 1; +} +#endif // SUART_TXD + + + +#ifdef SUART_RXD +SIGNAL (SIG_INPUT_CAPTURE1) +{ + uint16_t icr1 = ICR1; + uint16_t ocr1a = OCR1A; + + // Eine halbe Bitzeit zu ICR1 addieren (modulo OCR1A) und nach OCR1B + uint16_t ocr1b = icr1 + ocr1a/2; + if (ocr1b >= ocr1a) + ocr1b -= ocr1a; + OCR1B = ocr1b; + + TIFR = (1 << OCF1B); + TIMSK = (TIMSK & ~(1 << TICIE1)) | (1 << OCIE1B); + inframe = 0; + inbits = 0; +} +#endif // SUART_RXD + + + + +#ifdef SUART_RXD +SIGNAL (SIG_OUTPUT_COMPARE1B) +{ + uint16_t data = inframe >> 1; + + if (SUART_RXD_PIN & (1 << SUART_RXD_BIT)) + data |= (1 << 9); + + uint8_t bits = inbits+1; + + if (10 == bits) + { + if ((data & 1) == 0) + if (data >= (1 << 9)) + { +#ifdef _FIFO_H_ + _inline_fifo_put (&infifo, data >> 1); +#else + indata = data >> 1; +#endif // _FIFO_H_ + received = 1; + } + + TIMSK = (TIMSK & ~(1 << OCIE1B)) | (1 << TICIE1); + TIFR = (1 << ICF1); + } + else + { + inbits = bits; + inframe = data; + } +} +#endif // SUART_RXD + + + +#ifdef SUART_RXD +#ifdef _FIFO_H_ + +uint8_t uart_getc_wait() +{ + return (int) fifo_get_wait (&infifo); +} + +int uart_getc_nowait() +{ + return fifo_get_nowait (&infifo); +} + +#else // _FIFO_H_ + +uint8_t uart_getc_wait() +{ + while (!received) {} + received = 0; + + return (uint8_t) indata; +} + +uint8_t uart_getc_nowait() +{ + if (received) + { + received = 0; + return (uint8_t) indata; + } + + return -1; +} + +#endif // _FIFO_H_ +#endif // SUART_RXD + diff --git a/poc/poc_mmc/uart.h b/poc/poc_mmc/uart.h new file mode 100644 index 0000000..8fa2209 --- /dev/null +++ b/poc/poc_mmc/uart.h @@ -0,0 +1,23 @@ +#ifndef _UART_H_ +#define _UART_H_ + +#define SUART_TXD +#define SUART_RXD + +#include +#include + +void uart_init(); + +#ifdef SUART_TXD + void uart_putc(uint8_t byte); + void uart_puts(uint8_t *buf); +#endif // SUART_RXD + +#ifdef SUART_RXD + uint8_t uart_getc_wait(); + uint8_t uart_getc_nowait(); +#endif // SUART_RXD + +#endif /* _UART_H_ */ +