mirror of
https://github.com/una1veritas/mac-floppy-emu.git
synced 2024-06-15 08:29:30 +00:00
floppy-emu
This commit is contained in:
parent
2787d1fc77
commit
de725331e6
212
arduino/.cproject
Normal file
212
arduino/.cproject
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
<cconfiguration id="de.innot.avreclipse.configuration.app.debug.46313178">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="de.innot.avreclipse.configuration.app.debug.46313178" moduleId="org.eclipse.cdt.core.settings" name="Flash">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions>
|
||||||
|
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||||
|
</extensions>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<configuration artifactName="${ProjName}" buildArtefactType="de.innot.avreclipse.buildArtefactType.app" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=de.innot.avreclipse.buildArtefactType.app" description="" id="de.innot.avreclipse.configuration.app.debug.46313178" name="Flash" parent="de.innot.avreclipse.configuration.app.debug">
|
||||||
|
<folderInfo id="de.innot.avreclipse.configuration.app.debug.46313178." name="/" resourcePath="">
|
||||||
|
<toolChain id="de.innot.avreclipse.toolchain.winavr.app.debug.1928898112" name="AVR-GCC Toolchain" superClass="de.innot.avreclipse.toolchain.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objcopy.flash.app.debug.1556530364" name="Generate HEX file for Flash memory" superClass="de.innot.avreclipse.toolchain.options.toolchain.objcopy.flash.app.debug" value="true" valueType="boolean"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objcopy.eeprom.app.debug.308984610" name="Generate HEX file for EEPROM" superClass="de.innot.avreclipse.toolchain.options.toolchain.objcopy.eeprom.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objdump.app.debug.726997292" name="Generate Extended Listing (Source + generated Assembler)" superClass="de.innot.avreclipse.toolchain.options.toolchain.objdump.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.size.app.debug.2041004627" name="Print Size" superClass="de.innot.avreclipse.toolchain.options.toolchain.size.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.avrdude.app.debug.720975396" name="AVRDude" superClass="de.innot.avreclipse.toolchain.options.toolchain.avrdude.app.debug"/>
|
||||||
|
<targetPlatform id="de.innot.avreclipse.targetplatform.winavr.app.debug.334176018" name="AVR Cross-Target" superClass="de.innot.avreclipse.targetplatform.winavr.app.debug"/>
|
||||||
|
<builder autoBuildTarget="all" buildPath="${workspace_loc:/mac-floppy-emu}/Debug" cleanBuildTarget="clean" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="de.innot.avreclipse.target.builder.winavr.app.debug.354726525" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="AVR GNU Make Builder" parallelBuildOn="false" superClass="de.innot.avreclipse.target.builder.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.assembler.winavr.app.debug.1172708735" name="AVR Assembler" superClass="de.innot.avreclipse.tool.assembler.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.assembler.option.debug.level.1316218585" name="Generate Debugging Info" superClass="de.innot.avreclipse.assembler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.asm.option.include.paths.1985090351" name="#include paths for preprocessor(-I)" superClass="de.innot.avreclipse.asm.option.include.paths" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.asm.option.omitfcpu.511906405" name="Omit F_CPU" superClass="de.innot.avreclipse.asm.option.omitfcpu" value="false" valueType="boolean"/>
|
||||||
|
<inputType id="de.innot.avreclipse.tool.assembler.input.1420366592" superClass="de.innot.avreclipse.tool.assembler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.compiler.winavr.app.debug.1667398690" name="AVR Compiler" superClass="de.innot.avreclipse.tool.compiler.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.debug.level.1071901049" name="Generate Debugging Info" superClass="de.innot.avreclipse.compiler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.optimize.681726631" name="Optimization Level" superClass="de.innot.avreclipse.compiler.option.optimize" value="de.innot.avreclipse.compiler.optimize.size" valueType="enumerated"/>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.incpath.1596667394" name="Include Paths (-I)" superClass="de.innot.avreclipse.compiler.option.incpath" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.def.359890836" name="Define Syms (-D)" superClass="de.innot.avreclipse.compiler.option.def" valueType="definedSymbols">
|
||||||
|
<listOptionValue builtIn="false" value="BOOT_ADR=0x1F000"/>
|
||||||
|
</option>
|
||||||
|
<inputType id="de.innot.avreclipse.compiler.winavr.input.529999190" name="C Source Files" superClass="de.innot.avreclipse.compiler.winavr.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.cppcompiler.app.debug.447087717" name="AVR C++ Compiler" superClass="de.innot.avreclipse.tool.cppcompiler.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.debug.level.1848796785" name="Generate Debugging Info" superClass="de.innot.avreclipse.cppcompiler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.optimize.2093225400" name="Optimization Level" superClass="de.innot.avreclipse.cppcompiler.option.optimize" value="de.innot.avreclipse.cppcompiler.optimize.size" valueType="enumerated"/>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.incpath.2109134472" name="Include Paths (-I)" superClass="de.innot.avreclipse.cppcompiler.option.incpath" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.def.1974695643" name="Define Syms (-D)" superClass="de.innot.avreclipse.cppcompiler.option.def" valueType="definedSymbols">
|
||||||
|
<listOptionValue builtIn="false" value="BOOT_ADR=0x1F000"/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.undef.116399045" name="Undefine Syms (-U)" superClass="de.innot.avreclipse.cppcompiler.option.undef"/>
|
||||||
|
<inputType id="de.innot.avreclipse.cppcompiler.input.427275686" superClass="de.innot.avreclipse.cppcompiler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.linker.winavr.app.debug.856276136" name="AVR C Linker" superClass="de.innot.avreclipse.tool.linker.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.cpplinker.app.debug.65425799" name="AVR C++ Linker" superClass="de.innot.avreclipse.tool.cpplinker.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.cpplinker.option.nostart.683661851" name="No startup or default libs (-nostdlib)" superClass="de.innot.avreclipse.cpplinker.option.nostart" value="true" valueType="boolean"/>
|
||||||
|
<inputType id="de.innot.avreclipse.tool.cpplinker.input.1415642170" name="OBJ Files" superClass="de.innot.avreclipse.tool.cpplinker.input">
|
||||||
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
</inputType>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.archiver.winavr.base.989913996" name="AVR Archiver" superClass="de.innot.avreclipse.tool.archiver.winavr.base"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objdump.winavr.app.debug.310152597" name="AVR Create Extended Listing" superClass="de.innot.avreclipse.tool.objdump.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objcopy.flash.winavr.app.debug.666445574" name="AVR Create Flash image" superClass="de.innot.avreclipse.tool.objcopy.flash.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objcopy.eeprom.winavr.app.debug.1978977796" name="AVR Create EEPROM image" superClass="de.innot.avreclipse.tool.objcopy.eeprom.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.size.winavr.app.debug.1574639643" name="Print Size" superClass="de.innot.avreclipse.tool.size.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.avrdude.app.debug.1681506261" name="AVRDude" superClass="de.innot.avreclipse.tool.avrdude.app.debug"/>
|
||||||
|
</toolChain>
|
||||||
|
</folderInfo>
|
||||||
|
<sourceEntries>
|
||||||
|
<entry excluding="bootldr|AVR/SdFat/examples" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||||
|
</sourceEntries>
|
||||||
|
</configuration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
<cconfiguration id="de.innot.avreclipse.configuration.app.debug.46313178.1895685496">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="de.innot.avreclipse.configuration.app.debug.46313178.1895685496" moduleId="org.eclipse.cdt.core.settings" name="Bootloader">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions>
|
||||||
|
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||||
|
</extensions>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<configuration artifactName="${ConfigName}" buildArtefactType="de.innot.avreclipse.buildArtefactType.app" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=de.innot.avreclipse.buildArtefactType.app" description="" id="de.innot.avreclipse.configuration.app.debug.46313178.1895685496" name="Bootloader" parent="de.innot.avreclipse.configuration.app.debug">
|
||||||
|
<folderInfo id="de.innot.avreclipse.configuration.app.debug.46313178.1895685496." name="/" resourcePath="">
|
||||||
|
<toolChain id="de.innot.avreclipse.toolchain.winavr.app.debug.907954222" name="AVR-GCC Toolchain" superClass="de.innot.avreclipse.toolchain.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objcopy.flash.app.debug.565173578" name="Generate HEX file for Flash memory" superClass="de.innot.avreclipse.toolchain.options.toolchain.objcopy.flash.app.debug" value="true" valueType="boolean"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objcopy.eeprom.app.debug.110003468" name="Generate HEX file for EEPROM" superClass="de.innot.avreclipse.toolchain.options.toolchain.objcopy.eeprom.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.objdump.app.debug.453613451" name="Generate Extended Listing (Source + generated Assembler)" superClass="de.innot.avreclipse.toolchain.options.toolchain.objdump.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.size.app.debug.1654513920" name="Print Size" superClass="de.innot.avreclipse.toolchain.options.toolchain.size.app.debug"/>
|
||||||
|
<option id="de.innot.avreclipse.toolchain.options.toolchain.avrdude.app.debug.1122910154" name="AVRDude" superClass="de.innot.avreclipse.toolchain.options.toolchain.avrdude.app.debug"/>
|
||||||
|
<targetPlatform id="de.innot.avreclipse.targetplatform.winavr.app.debug.1905439487" name="AVR Cross-Target" superClass="de.innot.avreclipse.targetplatform.winavr.app.debug"/>
|
||||||
|
<builder autoBuildTarget="all" buildPath="${workspace_loc:/mac-floppy-emu}/Debug" cleanBuildTarget="clean" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="de.innot.avreclipse.target.builder.winavr.app.debug.421443985" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="AVR GNU Make Builder" parallelBuildOn="false" superClass="de.innot.avreclipse.target.builder.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.assembler.winavr.app.debug.960984784" name="AVR Assembler" superClass="de.innot.avreclipse.tool.assembler.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.assembler.option.debug.level.684450263" name="Generate Debugging Info" superClass="de.innot.avreclipse.assembler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.asm.option.include.paths.411582041" name="#include paths for preprocessor(-I)" superClass="de.innot.avreclipse.asm.option.include.paths" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/bootldr}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/xsvf}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.asm.option.omitfcpu.804465170" name="Omit F_CPU" superClass="de.innot.avreclipse.asm.option.omitfcpu" value="false" valueType="boolean"/>
|
||||||
|
<inputType id="de.innot.avreclipse.tool.assembler.input.1091218206" superClass="de.innot.avreclipse.tool.assembler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.compiler.winavr.app.debug.447380226" name="AVR Compiler" superClass="de.innot.avreclipse.tool.compiler.winavr.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.debug.level.780095625" name="Generate Debugging Info" superClass="de.innot.avreclipse.compiler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.optimize.648107763" name="Optimization Level" superClass="de.innot.avreclipse.compiler.option.optimize" value="de.innot.avreclipse.compiler.optimize.size" valueType="enumerated"/>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.incpath.1733304105" name="Include Paths (-I)" superClass="de.innot.avreclipse.compiler.option.incpath" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/bootldr}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/xsvf}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.compiler.option.def.347006568" name="Define Syms (-D)" superClass="de.innot.avreclipse.compiler.option.def" valueType="definedSymbols">
|
||||||
|
<listOptionValue builtIn="false" value="BOOT_ADR=0x1F000"/>
|
||||||
|
</option>
|
||||||
|
<inputType id="de.innot.avreclipse.compiler.winavr.input.57550180" name="C Source Files" superClass="de.innot.avreclipse.compiler.winavr.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.cppcompiler.app.debug.1991756259" name="AVR C++ Compiler" superClass="de.innot.avreclipse.tool.cppcompiler.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.debug.level.965905202" name="Generate Debugging Info" superClass="de.innot.avreclipse.cppcompiler.option.debug.level"/>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.optimize.256282861" name="Optimization Level" superClass="de.innot.avreclipse.cppcompiler.option.optimize" value="de.innot.avreclipse.cppcompiler.optimize.size" valueType="enumerated"/>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.incpath.1831223918" name="Include Paths (-I)" superClass="de.innot.avreclipse.cppcompiler.option.incpath" valueType="includePath">
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/bootldr}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/AVR/xsvf}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/SdFat}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/mac-floppy-emu/floppyemu/xsvf}""/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.def.750809700" name="Define Syms (-D)" superClass="de.innot.avreclipse.cppcompiler.option.def" valueType="definedSymbols">
|
||||||
|
<listOptionValue builtIn="false" value="BOOT_ADR=0x1F000"/>
|
||||||
|
</option>
|
||||||
|
<option id="de.innot.avreclipse.cppcompiler.option.undef.819457287" name="Undefine Syms (-U)" superClass="de.innot.avreclipse.cppcompiler.option.undef"/>
|
||||||
|
<inputType id="de.innot.avreclipse.cppcompiler.input.586233877" superClass="de.innot.avreclipse.cppcompiler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.linker.winavr.app.debug.2040136235" name="AVR C Linker" superClass="de.innot.avreclipse.tool.linker.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.cpplinker.app.debug.1333346517" name="AVR C++ Linker" superClass="de.innot.avreclipse.tool.cpplinker.app.debug">
|
||||||
|
<option id="de.innot.avreclipse.cpplinker.option.nostart.156731030" name="No startup or default libs (-nostdlib)" superClass="de.innot.avreclipse.cpplinker.option.nostart" value="false" valueType="boolean"/>
|
||||||
|
<inputType id="de.innot.avreclipse.tool.cpplinker.input.550428840" name="OBJ Files" superClass="de.innot.avreclipse.tool.cpplinker.input">
|
||||||
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
</inputType>
|
||||||
|
</tool>
|
||||||
|
<tool id="de.innot.avreclipse.tool.archiver.winavr.base.2109674810" name="AVR Archiver" superClass="de.innot.avreclipse.tool.archiver.winavr.base"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objdump.winavr.app.debug.1998341406" name="AVR Create Extended Listing" superClass="de.innot.avreclipse.tool.objdump.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objcopy.flash.winavr.app.debug.818265629" name="AVR Create Flash image" superClass="de.innot.avreclipse.tool.objcopy.flash.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.objcopy.eeprom.winavr.app.debug.671424688" name="AVR Create EEPROM image" superClass="de.innot.avreclipse.tool.objcopy.eeprom.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.size.winavr.app.debug.1570739038" name="Print Size" superClass="de.innot.avreclipse.tool.size.winavr.app.debug"/>
|
||||||
|
<tool id="de.innot.avreclipse.tool.avrdude.app.debug.451487219" name="AVRDude" superClass="de.innot.avreclipse.tool.avrdude.app.debug"/>
|
||||||
|
</toolChain>
|
||||||
|
</folderInfo>
|
||||||
|
<sourceEntries>
|
||||||
|
<entry excluding="floppyemu|AVR/SdFat/examples" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||||
|
</sourceEntries>
|
||||||
|
</configuration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<project id="mac-floppy-emu.de.innot.avreclipse.project.winavr.elf_2.1.0.1811389054" name="AVR Cross Target Application" projectType="de.innot.avreclipse.project.winavr.elf_2.1.0"/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||||
|
<configuration configurationName="Release">
|
||||||
|
<resource resourceType="PROJECT" workspacePath="/mac-floppy-emu"/>
|
||||||
|
</configuration>
|
||||||
|
<configuration configurationName="Bootloader">
|
||||||
|
<resource resourceType="PROJECT" workspacePath="/mac-floppy-emu"/>
|
||||||
|
</configuration>
|
||||||
|
<configuration configurationName="Debug">
|
||||||
|
<resource resourceType="PROJECT" workspacePath="/mac-floppy-emu"/>
|
||||||
|
</configuration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||||
|
<storageModule moduleId="scannerConfiguration">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.debug.46313178.1895685496;de.innot.avreclipse.configuration.app.debug.46313178.1895685496.;de.innot.avreclipse.tool.compiler.winavr.app.debug.447380226;de.innot.avreclipse.compiler.winavr.input.57550180">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileC"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.release.1158950851;de.innot.avreclipse.configuration.app.release.1158950851.;de.innot.avreclipse.tool.compiler.winavr.app.release.792334622;de.innot.avreclipse.compiler.winavr.input.1693785873">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileC"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.debug.46313178;de.innot.avreclipse.configuration.app.debug.46313178.;de.innot.avreclipse.tool.compiler.winavr.app.debug.1667398690;de.innot.avreclipse.compiler.winavr.input.529999190">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileC"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.debug.46313178.1895685496;de.innot.avreclipse.configuration.app.debug.46313178.1895685496.;de.innot.avreclipse.tool.cppcompiler.app.debug.1991756259;de.innot.avreclipse.cppcompiler.input.586233877">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileCPP"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.release.1158950851;de.innot.avreclipse.configuration.app.release.1158950851.;de.innot.avreclipse.tool.cppcompiler.app.release.95022568;de.innot.avreclipse.cppcompiler.input.1203907827">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileCPP"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="de.innot.avreclipse.configuration.app.debug.46313178;de.innot.avreclipse.configuration.app.debug.46313178.;de.innot.avreclipse.tool.cppcompiler.app.debug.447087717;de.innot.avreclipse.cppcompiler.input.427275686">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="de.innot.avreclipse.core.AVRGCCManagedMakePerProjectProfileCPP"/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
</storageModule>
|
||||||
|
</cproject>
|
3
arduino/.gitignore
vendored
Normal file
3
arduino/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/Debug/
|
||||||
|
/Bootloader/
|
||||||
|
/Flash/
|
28
arduino/.project
Normal file
28
arduino/.project
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>mac-floppy-emu</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||||
|
<triggers>full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||||
|
<nature>de.innot.avreclipse.core.avrnature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
8
arduino/.settings/de.innot.avreclipse.core.prefs
Normal file
8
arduino/.settings/de.innot.avreclipse.core.prefs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
avrtarget/ClockFrequency=16000000
|
||||||
|
avrtarget/ExtRAMSize=0
|
||||||
|
avrtarget/ExtendedRAM=false
|
||||||
|
avrtarget/MCUType=atmega1284p
|
||||||
|
avrtarget/UseEEPROM=false
|
||||||
|
avrtarget/UseExtendedRAMforHeap=true
|
||||||
|
avrtarget/perConfig=false
|
||||||
|
eclipse.preferences.version=1
|
67
arduino/.settings/org.eclipse.cdt.codan.core.prefs
Normal file
67
arduino/.settings/org.eclipse.cdt.codan.core.prefs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
|
||||||
|
org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||||
|
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
|
||||||
|
org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.checkers.noreturn=Error
|
||||||
|
org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
|
||||||
|
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
17
arduino/.settings/org.eclipse.cdt.core.prefs
Normal file
17
arduino/.settings/org.eclipse.cdt.core.prefs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/delimiter=\:
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/operation=replace
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/value=en-US
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/delimiter=\:
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/operation=replace
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/value=/opt/local/bin\:/usr/bin\:/bin\:/usr/sbin\:/sbin
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/append=true
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/appendContributed=true
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/delimiter=\:
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/operation=replace
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/value=en-US
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/delimiter=\:
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/operation=replace
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/value=/usr/local/arduinotool/bin\:/opt/local/bin\:/usr/bin\:/bin\:/usr/sbin\:/sbin
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/append=true
|
||||||
|
environment/project/de.innot.avreclipse.configuration.app.debug.46313178/appendContributed=true
|
BIN
arduino/CPLD-Xilinx/firmware.xvf
Executable file
BIN
arduino/CPLD-Xilinx/firmware.xvf
Executable file
Binary file not shown.
1
arduino/CPLD-Xilinx/floppyemu.prj
Executable file
1
arduino/CPLD-Xilinx/floppyemu.prj
Executable file
|
@ -0,0 +1 @@
|
||||||
|
verilog work "floppyemu.v"
|
41
arduino/CPLD-Xilinx/floppyemu.ucf
Executable file
41
arduino/CPLD-Xilinx/floppyemu.ucf
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
#PACE: Start of Constraints generated by PACE
|
||||||
|
#PACE: Start of PACE I/O Pin Assignments
|
||||||
|
NET "stepAck_diskInserted" LOC = "P8" ;
|
||||||
|
NET "_enable" LOC = "P20" ;
|
||||||
|
NET "_rst" LOC = "P37" ;
|
||||||
|
NET "_wreq" LOC = "P18" ;
|
||||||
|
NET "_wreqMCU" LOC = "P5" ;
|
||||||
|
NET "byteReady_tk0" LOC = "P7" ;
|
||||||
|
NET "ca0" LOC = "P12" ;
|
||||||
|
NET "ca1" LOC = "P13" ;
|
||||||
|
NET "ca2" LOC = "P14" ;
|
||||||
|
NET "clk" LOC = "P43" ;
|
||||||
|
NET "data<0>" LOC = "P31" ;
|
||||||
|
NET "data<1>" LOC = "P32" ;
|
||||||
|
NET "data<2>" LOC = "P33" ;
|
||||||
|
NET "data<3>" LOC = "P34" ;
|
||||||
|
NET "data<4>" LOC = "P36" ;
|
||||||
|
NET "data<5>" LOC = "P38" ;
|
||||||
|
NET "data<6>" LOC = "P41" ;
|
||||||
|
NET "driveCurrentSide" LOC = "P3" ;
|
||||||
|
NET "stepDirectionMotorOn" LOC = "P1" ;
|
||||||
|
NET "driveTach" LOC = "P28" ;
|
||||||
|
NET "ejectRequest" LOC = "P30" ;
|
||||||
|
NET "led" LOC = "P40" ;
|
||||||
|
NET "lstrb" LOC = "P16" ;
|
||||||
|
NET "outputEnable" LOC = "P2" ;
|
||||||
|
NET "rd" LOC = "P21" ;
|
||||||
|
NET "rdAckWrTick" LOC = "P44" ;
|
||||||
|
NET "SEL" LOC = "P19" ;
|
||||||
|
NET "stepRequest" LOC = "P39" ;
|
||||||
|
NET "wr" LOC = "P22" ;
|
||||||
|
NET "zero" LOC = "P6" ;
|
||||||
|
NET "pwm" LOC = "P23" ;
|
||||||
|
NET "test" LOC = "P27" ;
|
||||||
|
|
||||||
|
#PACE: Start of PACE Area Constraints
|
||||||
|
#PACE: Start of PACE Prohibit Constraints
|
||||||
|
#PACE: End of Constraints generated by PACE
|
||||||
|
#Created by Constraints Editor (xc9572xl-vq44-10) - 2013/11/07
|
||||||
|
NET "clk" TNM_NET = clk;
|
||||||
|
TIMESPEC TS_clk = PERIOD "clk" 50 ns HIGH 50%;
|
433
arduino/CPLD-Xilinx/floppyemu.v
Executable file
433
arduino/CPLD-Xilinx/floppyemu.v
Executable file
|
@ -0,0 +1,433 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Disk registers (read):
|
||||||
|
State-control lines Register
|
||||||
|
CA2 CA1 CA0 SEL addressed Information in register
|
||||||
|
|
||||||
|
0 0 0 0 DIRTN Head step direction (0 = toward track 79, 1 = toward track 0)
|
||||||
|
0 0 0 1 CSTIN Disk in place (0 = disk is inserted)
|
||||||
|
0 0 1 0 STEP Drive head stepping (setting to 0 performs a step, returns to 1 when step is complete)
|
||||||
|
0 0 1 1 WRTPRT Disk locked (0 = locked)
|
||||||
|
0 1 0 0 MOTORON Drive motor running (0 = on, 1 = off)
|
||||||
|
0 1 0 1 TK0 Head at track 0 (0 = at track 0)
|
||||||
|
0 1 1 0 SWITCHED Disk switched (1 = yes?) SWIM3: relax, also eject in progress
|
||||||
|
0 1 1 1 TACH GCR: Tachometer (produces 60 pulses for each rotation of the drive motor), MFM: Index pulse
|
||||||
|
1 0 0 0 RDDATA0 Read data, lower head, side 0
|
||||||
|
1 0 0 1 RDDATA1 Read data, upper head, side 1
|
||||||
|
1 0 1 0 SUPERDR Drive is a Superdrive (0 = no, 1 = yes) SWIM3: two meg drive.
|
||||||
|
1 0 1 1 MFM_MODE SWIM3: MFM_MODE, 1 = yes (opposite of writing?)
|
||||||
|
1 1 0 0 SIDES Single- or double-sided drive (0 = single side, 1 = double side), SWIM: 0 = 4MB, 1 = not 4MB
|
||||||
|
1 1 0 1 READY 0 = yes, SWIM3: SEEK_COMPLETE
|
||||||
|
1 1 1 0 INSTALLED 0 = yes, only used by SWIM, not IWM? SWIM3: drive present.
|
||||||
|
1 1 1 1 HSHK_HD 400K/800K: implements ready handshake if 1, Superdrive: Inserted disk capacity (0 = HD, 1 = DD), SWIM3: 1 = ONE_MEG_MEDIA
|
||||||
|
|
||||||
|
|
||||||
|
Disk registers (write):
|
||||||
|
Control lines Register
|
||||||
|
CA1 CA0 SEL addressed Register function
|
||||||
|
|
||||||
|
0 0 0 DIRTN Set stepping direction (0 = toward track 79, 1 = toward track 0), SWIM3: SEEK_POSITIVE
|
||||||
|
0 0 1 SWITCHED Reset disk switched flag (writing 1 sets switch flag to 0)
|
||||||
|
0 1 0 STEP Step the drive head one track (setting to 0 performs a step, returns to 1 when step is complete)
|
||||||
|
1 0 0 MOTORON Turn drive motor on/off (0 = on, 1 = off)
|
||||||
|
1 0 0 TWOMEGMEDIA_CHECK The first time zero is written, changes the behavior when reading SIDES
|
||||||
|
0 1 1 MFM_MODE 0 = MFM, 1 = GCR
|
||||||
|
1 1 0 EJECT Eject the disk (writing 1 ejects the disk)
|
||||||
|
1 1 0 INDEX if writing 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
`define DRIVE_REG_DIRTN 0
|
||||||
|
`define DRIVE_REG_CSTIN 1
|
||||||
|
`define DRIVE_REG_STEP 2
|
||||||
|
`define DRIVE_REG_WRTPRT 3
|
||||||
|
`define DRIVE_REG_MOTORON 4
|
||||||
|
`define DRIVE_REG_TK0 5
|
||||||
|
`define DRIVE_REG_EJECT 6
|
||||||
|
`define DRIVE_REG_TACH 7
|
||||||
|
`define DRIVE_REG_RDDATA0 8
|
||||||
|
`define DRIVE_REG_RDDATA1 9
|
||||||
|
`define DRIVE_REG_SUPERDR 10
|
||||||
|
`define DRIVE_REG_UNUSED 11
|
||||||
|
`define DRIVE_REG_SIDES 12
|
||||||
|
`define DRIVE_REG_READY 13
|
||||||
|
`define DRIVE_REG_INSTALLED 14
|
||||||
|
`define DRIVE_REG_HSHK_HD 15
|
||||||
|
|
||||||
|
`define FIRMWARE_VERSION_NUMBER 11
|
||||||
|
|
||||||
|
module floppyemu(
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
// Macintosh interface
|
||||||
|
input ca0, // PH0
|
||||||
|
input ca1, // PH1
|
||||||
|
input ca2, // PH2
|
||||||
|
input lstrb, // PH3
|
||||||
|
input SEL, // HDSEL from VIA
|
||||||
|
input _enable,
|
||||||
|
input wr,
|
||||||
|
input _wreq,
|
||||||
|
input pwm, // unused
|
||||||
|
output rd,
|
||||||
|
|
||||||
|
// microcontroller interface
|
||||||
|
input _rst,
|
||||||
|
|
||||||
|
output stepDirectionMotorOn,
|
||||||
|
output reg stepRequest,
|
||||||
|
input stepAck_diskInserted,
|
||||||
|
|
||||||
|
output _wreqMCU,
|
||||||
|
output reg rdAckWrTick,
|
||||||
|
output reg driveCurrentSide,
|
||||||
|
output reg ejectRequest,
|
||||||
|
|
||||||
|
input driveTach,
|
||||||
|
input byteReady_tk0,
|
||||||
|
|
||||||
|
input outputEnable,
|
||||||
|
inout [6:0] data,
|
||||||
|
|
||||||
|
output zero,
|
||||||
|
|
||||||
|
// status display
|
||||||
|
output led,
|
||||||
|
|
||||||
|
// debugging
|
||||||
|
output test
|
||||||
|
);
|
||||||
|
|
||||||
|
/********** drive state data **********/
|
||||||
|
reg _driveRegTK0;
|
||||||
|
reg _driveRegMotorOn;
|
||||||
|
reg driveRegStepDirection;
|
||||||
|
reg _driveRegWriteProtect;
|
||||||
|
reg _driveRegDiskInserted;
|
||||||
|
reg _driveRegMFMMode;
|
||||||
|
|
||||||
|
/********** serial to parallel interface **********/
|
||||||
|
// GCR: One bit every 2 microseconds
|
||||||
|
// The exact rate on the Macintosh is actually 16 clocks @ 7.8336 MHz = 2.04 microseconds.
|
||||||
|
// MFM: One bit every 1 microsecond
|
||||||
|
reg [7:0] shifter;
|
||||||
|
reg [5:0] bitTimer;
|
||||||
|
reg [3:0] bitCounter;
|
||||||
|
reg [6:0] wrData;
|
||||||
|
reg rdHead;
|
||||||
|
reg [1:0] wrHistory;
|
||||||
|
reg mfmWriteSynced;
|
||||||
|
reg wrClear;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
wrHistory <= { wrHistory[0], wr };
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk or negedge _rst) begin
|
||||||
|
if (_rst == 0) begin
|
||||||
|
rdAckWrTick <= 0;
|
||||||
|
_driveRegWriteProtect <= 1;
|
||||||
|
_driveRegDiskInserted <= 1;
|
||||||
|
_driveRegMFMMode <= 1;
|
||||||
|
wrData <= `FIRMWARE_VERSION_NUMBER;
|
||||||
|
mfmWriteSynced <= 0;
|
||||||
|
wrClear <= 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// one-way switch for disk inserted register - until next reset, stepAck_diskInserted will act only as stepAck
|
||||||
|
if (_driveRegDiskInserted == 1 && stepAck_diskInserted == 0) begin
|
||||||
|
_driveRegDiskInserted <= 0;
|
||||||
|
end
|
||||||
|
// is the Macintosh currently writing to the disk?
|
||||||
|
if (_wreq == 0) begin
|
||||||
|
// was there a transition on the wr line?
|
||||||
|
// GCR: any transition
|
||||||
|
// MFM: falling edge
|
||||||
|
if (((wrHistory[1] != wrHistory[0]) && (_driveRegMFMMode == 1)) ||
|
||||||
|
((wrHistory[1] && ~wrHistory[0]) && (_driveRegMFMMode == 0))) begin
|
||||||
|
// has at least half a bit cell time elpased since the last cell boundary?
|
||||||
|
if ((bitTimer >= 20 && _driveRegMFMMode == 1) ||
|
||||||
|
(bitTimer >= 10 && _driveRegMFMMode == 0)) begin
|
||||||
|
shifter <= { shifter[6:0], 1'b1 };
|
||||||
|
bitCounter <= bitCounter - 1'b1;
|
||||||
|
end
|
||||||
|
// do nothing if the clock count was less than half a cell
|
||||||
|
|
||||||
|
// reset the bit timer
|
||||||
|
bitTimer <= 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// have one and a half bit cell times elapsed?
|
||||||
|
if ((bitTimer >= 60 && _driveRegMFMMode == 1) ||
|
||||||
|
(bitTimer >= 30 && _driveRegMFMMode == 0)) begin
|
||||||
|
shifter <= { shifter[6:0], 1'b0 };
|
||||||
|
bitCounter <= bitCounter - 1'b1;
|
||||||
|
|
||||||
|
if (_driveRegMFMMode == 1)
|
||||||
|
bitTimer <= 20;
|
||||||
|
else
|
||||||
|
bitTimer <= 10;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// init shifter at the beginning of a write, so we can recognize the framing bits later
|
||||||
|
if (wrClear == 0) begin
|
||||||
|
shifter <= 0;
|
||||||
|
wrClear <= 1;
|
||||||
|
end
|
||||||
|
// has a complete byte been shifted in?
|
||||||
|
else if (_driveRegMFMMode == 1) begin
|
||||||
|
// GCR
|
||||||
|
if (shifter[7] == 1) begin
|
||||||
|
// GCR: The complete byte is shifter[7:0], but only 7 bits are stored in wrData, since the MSB is always 1.
|
||||||
|
wrData <= shifter[6:0]; // store the byte for the mcu
|
||||||
|
shifter <= 0; // clear the byte from the shifter
|
||||||
|
rdAckWrTick <= ~rdAckWrTick; // signal the mcu that a new byte is ready
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// MFM
|
||||||
|
// If we're in write mode, but haven't yet synched (framed the bytes in the bit stream),
|
||||||
|
// and we see 01000100 in the shifter, assume that it's the first half of an A1 sync
|
||||||
|
if ((bitCounter == 0) ||
|
||||||
|
(shifter == 8'h44 && mfmWriteSynced == 0)) begin
|
||||||
|
// MFM: send the mcu the data nibble in the low 4 bits, and clock bit C2 in bit 4
|
||||||
|
wrData[0] <= shifter[0];
|
||||||
|
wrData[1] <= shifter[2];
|
||||||
|
wrData[2] <= shifter[4];
|
||||||
|
wrData[3] <= shifter[6];
|
||||||
|
wrData[4] <= shifter[5]; // clock bit
|
||||||
|
bitCounter <= 8;
|
||||||
|
|
||||||
|
rdAckWrTick <= (shifter == 8'h44 && mfmWriteSynced == 0) ? 0 : ~rdAckWrTick; // signal the mcu that a new nibble is ready
|
||||||
|
mfmWriteSynced <= mfmWriteSynced | (shifter == 8'h44);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
bitTimer <= bitTimer + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
mfmWriteSynced <= 0;
|
||||||
|
wrClear <= 0;
|
||||||
|
// is it time for a new bit?
|
||||||
|
if ((bitTimer == 40 && _driveRegMFMMode == 1) ||
|
||||||
|
(bitTimer == 20 && _driveRegMFMMode == 0))
|
||||||
|
begin
|
||||||
|
// are all the bits done?
|
||||||
|
if (bitCounter == 0) begin
|
||||||
|
// is there a new byte ready to read?
|
||||||
|
if (byteReady_tk0 == 1) begin
|
||||||
|
// if there's a byte ready, but no disk inserted, then load config options from the MCU
|
||||||
|
if (_driveRegDiskInserted == 1) begin
|
||||||
|
_driveRegWriteProtect <= data[0];
|
||||||
|
_driveRegMFMMode <= data[1];
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// load the new byte.
|
||||||
|
if (_driveRegMFMMode == 1) begin
|
||||||
|
// Only 7 bits are transferred, since the MSB is always 1.
|
||||||
|
shifter <= { 1'b1, data };
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// For MFM, the 7 bits received from the MCU are:
|
||||||
|
// 0 0 m d3 d2 d1 d0
|
||||||
|
// From this we can constuct the MFM-encoded byte with clock and data bits:
|
||||||
|
// c3 d3 c2 d2 c1 d1 c0 d0
|
||||||
|
// where cN = dN+1 NOR dN.
|
||||||
|
// If m is 1, then this is part of a mark byte, and c2 should be forced to 0.
|
||||||
|
shifter[7] <= ~(shifter[7] | data[3]);
|
||||||
|
shifter[6] <= data[3];
|
||||||
|
shifter[5] <= ~(data[3] | data[2]) & ~data[4];
|
||||||
|
shifter[4] <= data[2];
|
||||||
|
shifter[3] <= ~(data[2] | data[1]);
|
||||||
|
shifter[2] <= data[1];
|
||||||
|
shifter[1] <= ~(data[1] | data[0]);
|
||||||
|
shifter[0] <= data[0];
|
||||||
|
end
|
||||||
|
bitCounter <= 7;
|
||||||
|
rdAckWrTick <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// insert a sync byte
|
||||||
|
if (_driveRegMFMMode == 1)
|
||||||
|
begin
|
||||||
|
shifter <= { 8'b11111111 };
|
||||||
|
bitCounter <= 9; // sync "byte" sends 10 bits rather than 8
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
shifter <= { 8'b10101010 }; // logical 0x0, encoded 0xA. Should sync byte be 0x4E instead?
|
||||||
|
bitCounter <= 7;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (bitCounter == 7) begin
|
||||||
|
// Clear rdAck after the first bit is done. This gives the microcontroller 2 microseconds
|
||||||
|
// to react to rdAck before it's deasserted.
|
||||||
|
rdAckWrTick <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// there are still more bits remaining, so shift the next bit
|
||||||
|
shifter <= { shifter[6:0], 1'b0 }; // left shift
|
||||||
|
bitCounter <= bitCounter - 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
/* GCR: After the bit shift is completed, update the read head state, using the MSB of the shift register.
|
||||||
|
A logical 1 is sent as a falling (high to low) transition on the read head at a bit cell boundary time,
|
||||||
|
a logical 0 is sent as no falling transition. */
|
||||||
|
else if (bitTimer == 2 && shifter[7] == 1 && _driveRegMFMMode == 1) begin
|
||||||
|
rdHead <= 1'b0;
|
||||||
|
end
|
||||||
|
/* GCR: Half-way through the bit cell time, set the read head to 1
|
||||||
|
to prepare for a possible falling transition for the next bit. */
|
||||||
|
else if (bitTimer == 20 && _driveRegMFMMode == 1)
|
||||||
|
begin
|
||||||
|
rdHead <= 1'b1;
|
||||||
|
end
|
||||||
|
/* MFM: At the start of the bit cell time, set the read head to 0 if the logical value is 1. */
|
||||||
|
else if (bitTimer == 2 && shifter[7] == 1 && _driveRegMFMMode == 0)
|
||||||
|
begin
|
||||||
|
rdHead <= 1'b0;
|
||||||
|
end
|
||||||
|
/* MFM: About a quarter-way through the bit cell time, always reset read head to 1. */
|
||||||
|
else if (bitTimer == 7 && _driveRegMFMMode == 0)
|
||||||
|
begin
|
||||||
|
rdHead <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
// increment bit timer modulo 40 (20 MFM)
|
||||||
|
if ((bitTimer == 40 && _driveRegMFMMode == 1) ||
|
||||||
|
(bitTimer == 20 && _driveRegMFMMode == 0))
|
||||||
|
bitTimer <= 0;
|
||||||
|
else
|
||||||
|
bitTimer <= bitTimer + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// enable the data output only if the MCU says its data lines are Hi Z
|
||||||
|
assign data = (outputEnable == 1) ? wrData : 7'hZZ;
|
||||||
|
|
||||||
|
/********** register read **********/
|
||||||
|
wire [3:0] driveReadRegisterSelect = {ca2,ca1,ca0,SEL};
|
||||||
|
|
||||||
|
reg registerContents;
|
||||||
|
always @* begin
|
||||||
|
case (driveReadRegisterSelect)
|
||||||
|
`DRIVE_REG_DIRTN:
|
||||||
|
registerContents = driveRegStepDirection; // step direction
|
||||||
|
`DRIVE_REG_CSTIN:
|
||||||
|
registerContents = _driveRegDiskInserted; // disk in drive, 0 = yes
|
||||||
|
`DRIVE_REG_STEP:
|
||||||
|
registerContents = ~stepRequest; // STEP, 1 = complete
|
||||||
|
`DRIVE_REG_WRTPRT:
|
||||||
|
registerContents = _driveRegWriteProtect; // write protect, 0 = on, 1 = off
|
||||||
|
`DRIVE_REG_MOTORON:
|
||||||
|
registerContents = _driveRegMotorOn; // 0 = motor on
|
||||||
|
`DRIVE_REG_TK0:
|
||||||
|
registerContents = _driveRegTK0; // TK0: track 0 indicator
|
||||||
|
`DRIVE_REG_EJECT:
|
||||||
|
registerContents = 1'b0; // disk switched?
|
||||||
|
`DRIVE_REG_TACH:
|
||||||
|
registerContents = driveTach; // TACH: 60 pulses for each rotation of the drive motor
|
||||||
|
`DRIVE_REG_RDDATA0:
|
||||||
|
registerContents = rdHead; // RDDATA0
|
||||||
|
`DRIVE_REG_RDDATA1:
|
||||||
|
registerContents = rdHead; // RDDATA1
|
||||||
|
`DRIVE_REG_SUPERDR:
|
||||||
|
registerContents = 1'b1; // SUPERDR, 1 = yes
|
||||||
|
`DRIVE_REG_UNUSED:
|
||||||
|
registerContents = 1'b0; // UNUSED
|
||||||
|
`DRIVE_REG_SIDES:
|
||||||
|
registerContents = 1'b1; // SIDES = double-sided drive
|
||||||
|
`DRIVE_REG_READY:
|
||||||
|
registerContents = 1'b0; // READY = yes
|
||||||
|
`DRIVE_REG_INSTALLED:
|
||||||
|
registerContents = 1'b0; // INSTALLED = yes
|
||||||
|
`DRIVE_REG_HSHK_HD:
|
||||||
|
registerContents = _driveRegMFMMode; // HSHK_HD = implements ready handshake, or DD/HD media
|
||||||
|
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
assign rd = _enable == 1'b1 ? 1'bZ : registerContents;
|
||||||
|
|
||||||
|
always @(posedge clk or negedge _rst) begin
|
||||||
|
if (_rst == 0) begin
|
||||||
|
driveCurrentSide = 0;
|
||||||
|
end
|
||||||
|
else if (_enable == 1'b0 && lstrb == 1'b0) begin
|
||||||
|
if (driveReadRegisterSelect == `DRIVE_REG_RDDATA0)
|
||||||
|
driveCurrentSide = 0;
|
||||||
|
else if (driveReadRegisterSelect == `DRIVE_REG_RDDATA1)
|
||||||
|
driveCurrentSide = 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// compute the effective _wreq state for the microcontroller
|
||||||
|
assign _wreqMCU = ~(_wreq == 0 && _enable == 0 && _driveRegMotorOn == 0);
|
||||||
|
|
||||||
|
// cheesy: during a step request, stepDirectionMotorOn is the step direction. Otherwise it's motorOn.
|
||||||
|
assign stepDirectionMotorOn = stepRequest ? driveRegStepDirection : _driveRegMotorOn;
|
||||||
|
|
||||||
|
/********** register write **********/
|
||||||
|
wire [2:0] driveWriteRegisterSelect = {ca1,ca0,SEL};
|
||||||
|
|
||||||
|
reg [4:0] lstrbHistory;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
lstrbHistory <= { lstrbHistory[3:0], lstrb };
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk or negedge _rst) begin
|
||||||
|
if (_rst == 1'b0) begin
|
||||||
|
_driveRegTK0 <= 0;
|
||||||
|
_driveRegMotorOn <= 1;
|
||||||
|
driveRegStepDirection <= 0;
|
||||||
|
stepRequest <= 0;
|
||||||
|
ejectRequest <= 0;
|
||||||
|
end
|
||||||
|
// was there a rising edge on lstrb?
|
||||||
|
else if (_enable == 1'b0 && lstrbHistory == 5'b01111) begin
|
||||||
|
case (driveWriteRegisterSelect)
|
||||||
|
`DRIVE_REG_DIRTN:
|
||||||
|
driveRegStepDirection <= ca2;
|
||||||
|
//`DRIVE_REG_SWITCHED: // unused
|
||||||
|
`DRIVE_REG_STEP:
|
||||||
|
begin
|
||||||
|
stepRequest <= 1; // tell the microcontroller that a step was performed
|
||||||
|
end
|
||||||
|
`DRIVE_REG_MOTORON:
|
||||||
|
_driveRegMotorOn <= ca2;
|
||||||
|
`DRIVE_REG_EJECT:
|
||||||
|
if (ca2 == 1'b1) begin
|
||||||
|
ejectRequest <= 1; // tell the microcontroller that the disk was ejected. This stays on forever (until next reset)
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// clear step request after mcu acknowledges it, and get the new track 0 state
|
||||||
|
if (stepRequest == 1 && stepAck_diskInserted == 1'b1) begin
|
||||||
|
stepRequest <= 0;
|
||||||
|
_driveRegTK0 <= byteReady_tk0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
/********** Revision 1.0 board: status LEDs and fake SD writeProtect **********/
|
||||||
|
assign led = _driveRegMotorOn;
|
||||||
|
assign zero = 0;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
210
arduino/CPLD-Xilinx/floppyemu.xise
Executable file
210
arduino/CPLD-Xilinx/floppyemu.xise
Executable file
|
@ -0,0 +1,210 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<!-- ISE source project file created by Project Navigator. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- This file contains project source information including a list of -->
|
||||||
|
<!-- project source files, project and process properties. This file, -->
|
||||||
|
<!-- along with the project source files, is sufficient to open and -->
|
||||||
|
<!-- implement in ISE Project Navigator. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||||
|
|
||||||
|
<files>
|
||||||
|
<file xil_pn:name="floppyemu.v" xil_pn:type="FILE_VERILOG">
|
||||||
|
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
|
||||||
|
<association xil_pn:name="Implementation" xil_pn:seqID="1"/>
|
||||||
|
</file>
|
||||||
|
<file xil_pn:name="testbench.v" xil_pn:type="FILE_VERILOG">
|
||||||
|
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="2"/>
|
||||||
|
<association xil_pn:name="PostRouteSimulation" xil_pn:seqID="2"/>
|
||||||
|
</file>
|
||||||
|
<file xil_pn:name="floppyemu.ucf" xil_pn:type="FILE_UCF">
|
||||||
|
<association xil_pn:name="Implementation" xil_pn:seqID="0"/>
|
||||||
|
</file>
|
||||||
|
</files>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Autosignature Generation" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Bus Delimiter" xil_pn:value="<>" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Clock Enable" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Collapsing Input Limit (2-54)" xil_pn:value="54" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Collapsing Pterm Limit (1-90)" xil_pn:value="90" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Compile CPLD Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Compile uni9000 (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Create IEEE 1532 Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Create Programmable GND Pins on Unused I/O" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Default Powerup Value of Registers" xil_pn:value="Low" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Device" xil_pn:value="xc9572xl" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Device Family" xil_pn:value="XC9500XL CPLDs" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Enable Hardware Co-Simulation" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Exhaustive Fit Mode" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate Post-Fit Power Data" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate Post-Fit Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="HDL Equations Style" xil_pn:value="Source" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="I/O Pin Termination" xil_pn:value="Keeper" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Implementation Template" xil_pn:value="Optimize Density" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Implementation Top" xil_pn:value="Module|floppyemu" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Implementation Top File" xil_pn:value="floppyemu.v" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/floppyemu" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Keep Hierarchy CPLD" xil_pn:value="Yes" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Last Applied Goal" xil_pn:value="Balanced" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Last Applied Strategy" xil_pn:value="Xilinx Default (unlocked)" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Logic Optimization" xil_pn:value="Density" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Macro Preserve" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Macrocell Power Setting" xil_pn:value="Std" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Mux Extraction" xil_pn:value="Yes" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Optimization Effort" xil_pn:value="High" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Optimization Goal" xil_pn:value="Area" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Other CPLD Fitter Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Compiler Options Fit" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Programming Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Simulator Commands Fit" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other Timing Report Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Output File Name" xil_pn:value="floppyemu" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Output Slew Rate" xil_pn:value="Fast" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Package" xil_pn:value="VQ44" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Post Place & Route Simulation Model Name" xil_pn:value="floppyemu_timesim.v" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Preserve Unused Inputs" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Rename Top Level Entity to" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Selected Module Instance Name" xil_pn:value="/testbench" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="work.testbench" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Signature /User Code" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Simulation Run Time ISim" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="work.testbench" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Specify Top Level Instance Names Fit" xil_pn:value="Default" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Speed Grade" xil_pn:value="-10" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Target UCF File Name" xil_pn:value="floppyemu.ucf" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="Timing Report Format" xil_pn:value="Summary" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Project File Fit" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Custom Waveform Configuration File Fit" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Global Clocks" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Global Output Enables" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Global Set/Reset" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Location Constraints" xil_pn:value="Always" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Multi-level Logic Optimization" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Use Timing Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="User Browsed Strategy Files" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="VCCIO Reference Voltage" xil_pn:value="LVTTL" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Verilog 2001 Xst" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="WYSIWYG" xil_pn:value="None" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="XOR Preserve" xil_pn:value="true" xil_pn:valueState="default"/>
|
||||||
|
<!-- -->
|
||||||
|
<!-- The following properties are for internal use only. These should not be modified.-->
|
||||||
|
<!-- -->
|
||||||
|
<property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Module|testbench" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="PROP_DesignName" xil_pn:value="floppyemu" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="xc9500xl" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="PROP_PostFitSimTop" xil_pn:value="" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
|
||||||
|
<property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2011-11-23T15:40:51" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="EA0C44EFBDC8450DA8F8CD96D20935BA" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
|
||||||
|
<property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<bindings/>
|
||||||
|
|
||||||
|
<libraries/>
|
||||||
|
|
||||||
|
<autoManagedFiles>
|
||||||
|
<!-- The following files are identified by `include statements in verilog -->
|
||||||
|
<!-- source files and are automatically managed by Project Navigator. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Do not hand-edit this section, as it will be overwritten when the -->
|
||||||
|
<!-- project is analyzed based on files automatically identified as -->
|
||||||
|
<!-- include files. -->
|
||||||
|
</autoManagedFiles>
|
||||||
|
|
||||||
|
</project>
|
163
arduino/CPLD-Xilinx/testbench.v
Executable file
163
arduino/CPLD-Xilinx/testbench.v
Executable file
|
@ -0,0 +1,163 @@
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Company:
|
||||||
|
// Engineer:
|
||||||
|
//
|
||||||
|
// Create Date: 15:13:07 11/30/2011
|
||||||
|
// Design Name: floppyemu
|
||||||
|
// Module Name: C:/Users/steve/Documents/floppyemu/CPLD-Xilinx/testbench.v
|
||||||
|
// Project Name: floppyemu
|
||||||
|
// Target Device:
|
||||||
|
// Tool versions:
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Verilog Test Fixture created by ISE for module: floppyemu
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
//
|
||||||
|
// Revision:
|
||||||
|
// Revision 0.01 - File Created
|
||||||
|
// Additional Comments:
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
module testbench;
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
reg clk;
|
||||||
|
reg wr;
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
wire [7:0] wrData;
|
||||||
|
wire rdAckWrByte;
|
||||||
|
|
||||||
|
// Instantiate the Unit Under Test (UUT)
|
||||||
|
floppyemu uut (
|
||||||
|
.clk(clk),
|
||||||
|
.wr(wr),
|
||||||
|
.wrData(wrData),
|
||||||
|
.rdAckWrByte(rdAckWrByte)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
clk = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always begin
|
||||||
|
#70 clk = 1;
|
||||||
|
#70 clk = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// Initialize Inputs
|
||||||
|
wr = 0;
|
||||||
|
|
||||||
|
// Wait 100 ns for global reset to finish
|
||||||
|
#4000;
|
||||||
|
|
||||||
|
// send 10-bit sync byte
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// send 10-bit sync byte
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// send 10-bit sync byte
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// send 10-bit sync byte
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// send 10-bit sync byte
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// D5 = 1101 0101
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
|
||||||
|
// AA = 1010 1010
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// 96 = 1001 0110
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
// 96 = 1001 0110
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 wr = ~wr;
|
||||||
|
#2000 ;
|
||||||
|
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
# AvrStudio Solution File, Format Version 11.00
|
# AvrStudio Solution File, Format Version 11.00
|
||||||
Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "floppyemu", "floppyemu.cppproj", "{E27520EB-9B21-411F-B8C6-71C8E4B8B1B6}"
|
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "bootldr", "bootldr\bootldr.cproj", "{4BF88424-65A0-49E2-90B5-584B8FB3E794}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -9,10 +9,10 @@ Global
|
||||||
Release|AVR = Release|AVR
|
Release|AVR = Release|AVR
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{E27520EB-9B21-411F-B8C6-71C8E4B8B1B6}.Debug|AVR.ActiveCfg = Debug|AVR
|
{4BF88424-65A0-49E2-90B5-584B8FB3E794}.Debug|AVR.ActiveCfg = Debug|AVR
|
||||||
{E27520EB-9B21-411F-B8C6-71C8E4B8B1B6}.Debug|AVR.Build.0 = Debug|AVR
|
{4BF88424-65A0-49E2-90B5-584B8FB3E794}.Debug|AVR.Build.0 = Debug|AVR
|
||||||
{E27520EB-9B21-411F-B8C6-71C8E4B8B1B6}.Release|AVR.ActiveCfg = Release|AVR
|
{4BF88424-65A0-49E2-90B5-584B8FB3E794}.Release|AVR.ActiveCfg = Release|AVR
|
||||||
{E27520EB-9B21-411F-B8C6-71C8E4B8B1B6}.Release|AVR.Build.0 = Release|AVR
|
{4BF88424-65A0-49E2-90B5-584B8FB3E794}.Release|AVR.Build.0 = Release|AVR
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
BIN
arduino/bootldr/bootldr.atsuo
Executable file
BIN
arduino/bootldr/bootldr.atsuo
Executable file
Binary file not shown.
157
arduino/bootldr/bootldr/Release/Makefile
Executable file
157
arduino/bootldr/bootldr/Release/Makefile
Executable file
|
@ -0,0 +1,157 @@
|
||||||
|
################################################################################
|
||||||
|
# Automatically-generated file. Do not edit!
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
SHELL := cmd.exe
|
||||||
|
RM := rm -rf
|
||||||
|
|
||||||
|
USER_OBJS :=
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
PROJ :=
|
||||||
|
|
||||||
|
O_SRCS :=
|
||||||
|
C_SRCS :=
|
||||||
|
S_SRCS :=
|
||||||
|
S_UPPER_SRCS :=
|
||||||
|
OBJ_SRCS :=
|
||||||
|
ASM_SRCS :=
|
||||||
|
PREPROCESSING_SRCS :=
|
||||||
|
OBJS :=
|
||||||
|
OBJS_AS_ARGS :=
|
||||||
|
C_DEPS :=
|
||||||
|
C_DEPS_AS_ARGS :=
|
||||||
|
EXECUTABLES :=
|
||||||
|
OUTPUT_FILE_PATH :=
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS :=
|
||||||
|
AVR_APP_PATH :=$$$AVR_APP_PATH$$$
|
||||||
|
QUOTE := "
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
OUTPUT_FILE_DEP:=
|
||||||
|
|
||||||
|
# Every subdirectory with source files must be described here
|
||||||
|
SUBDIRS :=
|
||||||
|
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
C_SRCS += \
|
||||||
|
../lcd.c \
|
||||||
|
../main.c \
|
||||||
|
../mmc.c \
|
||||||
|
../pff.c
|
||||||
|
|
||||||
|
|
||||||
|
PREPROCESSING_SRCS += \
|
||||||
|
../asmfunc.S
|
||||||
|
|
||||||
|
|
||||||
|
ASM_SRCS +=
|
||||||
|
|
||||||
|
|
||||||
|
OBJS += \
|
||||||
|
asmfunc.o \
|
||||||
|
lcd.o \
|
||||||
|
main.o \
|
||||||
|
mmc.o \
|
||||||
|
pff.o
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_AS_ARGS += \
|
||||||
|
asmfunc.o \
|
||||||
|
lcd.o \
|
||||||
|
main.o \
|
||||||
|
mmc.o \
|
||||||
|
pff.o
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS += \
|
||||||
|
lcd.d \
|
||||||
|
main.d \
|
||||||
|
mmc.d \
|
||||||
|
pff.d
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS_AS_ARGS += \
|
||||||
|
lcd.d \
|
||||||
|
main.d \
|
||||||
|
mmc.d \
|
||||||
|
pff.d
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH +=bootldr.elf
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS +=bootldr.elf
|
||||||
|
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
|
||||||
|
OUTPUT_FILE_DEP:= ./makedep.mk
|
||||||
|
|
||||||
|
# AVR32/GNU C Compiler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
./%.o: .././%.c
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR/GNU C Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-gcc.exe$(QUOTE) -mcall-prologues -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -DBOOT_ADR=0x1F000 -Os -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -Wall -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Preprocessing Assembler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Assembler
|
||||||
|
./asmfunc.o: .././asmfunc.s
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR32/GNU C Assembler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-gcc.exe$(QUOTE) -Wa,-gdwarf2 -x assembler-with-cpp -c -DF_CPU=20000000 -DBOOT_ADR=0x1F000 -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
|
||||||
|
./%.o: .././%.s
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR32/GNU C Assembler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-gcc.exe$(QUOTE) -Wa,-gdwarf2 -x assembler-with-cpp -c -DF_CPU=20000000 -DBOOT_ADR=0x1F000 -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
ifneq ($(strip $(C_DEPS)),)
|
||||||
|
-include $(C_DEPS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
|
||||||
|
# All Target
|
||||||
|
all: $(OUTPUT_FILE_PATH) $(ADDITIONAL_DEPENDENCIES)
|
||||||
|
|
||||||
|
$(OUTPUT_FILE_PATH): $(OBJS) $(USER_OBJS) $(OUTPUT_FILE_DEP)
|
||||||
|
@echo Building target: $@
|
||||||
|
@echo Invoking: AVR/GNU C Linker
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-gcc.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="bootldr.map" -Wl,-lm -Wl,--gc-sections -mrelax -Wl,-section-start=.text=0x1f000 -mmcu=atmega1284p
|
||||||
|
@echo Finished building target: $@
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature "bootldr.elf" "bootldr.hex"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "bootldr.elf" "bootldr.eep" || exit 0
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objdump.exe" -h -S "bootldr.elf" > "bootldr.lss"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-size.exe" -C --mcu=atmega1284p "bootldr.elf"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Other Targets
|
||||||
|
clean:
|
||||||
|
-$(RM) $(OBJS_AS_ARGS)$(C_DEPS_AS_ARGS) $(EXECUTABLES)
|
||||||
|
rm -rf "bootldr.hex" "bootldr.lss" "bootldr.eep" "bootldr.map"
|
||||||
|
|
259
arduino/bootldr/bootldr/Release/bootldr.hex
Executable file
259
arduino/bootldr/bootldr/Release/bootldr.hex
Executable file
|
@ -0,0 +1,259 @@
|
||||||
|
:020000021000EC
|
||||||
|
:10F0000097C00000B2C00000B0C00000AEC0000059
|
||||||
|
:10F01000ACC00000AAC00000A8C00000A6C000004C
|
||||||
|
:10F02000A4C00000A2C00000A0C000009EC000005C
|
||||||
|
:10F030009CC000009AC0000098C0000096C000006C
|
||||||
|
:10F0400094C0000092C0000090C000008EC000007C
|
||||||
|
:10F050008CC000008AC0000088C0000086C000008C
|
||||||
|
:10F0600084C0000082C0000080C000007EC000009C
|
||||||
|
:10F070007CC000007AC0000078C0000076C00000AC
|
||||||
|
:10F0800074C0000072C0000070C000001E051E1F8A
|
||||||
|
:10F09000150A0E11111F110E1F15151F05050E154E
|
||||||
|
:10F0A0001D1F041F111F1108100F1F041B1F10101C
|
||||||
|
:10F0B0001F061F1F0E1F0E110E1F05020010001F3E
|
||||||
|
:10F0C0000D16121509011F010F101F0718071F0C3D
|
||||||
|
:10F0D0001F000000031C03000A004552524F525A01
|
||||||
|
:10F0E00058464C41534858495358454D505459007F
|
||||||
|
:10F0F00046454D555142494E584E4F5458464F552E
|
||||||
|
:10F100004E4400464C415348494E475846454D559C
|
||||||
|
:10F110005142494E5851515100464C4F5050595848
|
||||||
|
:10F12000454D5558424F4F544C4F414445520000B5
|
||||||
|
:10F1300011241FBECFEFD0E4DEBFCDBF11E0A0E0B1
|
||||||
|
:10F14000B1E0E8EEFFEF01E00BBF02C007900D92C7
|
||||||
|
:10F15000AA30B107D9F712E0AAE0B1E001C01D92D0
|
||||||
|
:10F16000A733B107E1F7DBD03DC74ACF249A259AF0
|
||||||
|
:10F17000279A2E9A089588EC31973197319700009D
|
||||||
|
:10F180008A95D1F7089502D02C9801C02C9A8FEF60
|
||||||
|
:10F1900098E087FD2D9A87FF2D98880F1E998395FB
|
||||||
|
:10F1A0002F9A2F989A95A9F70895FB018BBF83E0BA
|
||||||
|
:10F1B00080935700E8958091570080FDFCCF81E156
|
||||||
|
:10F1C00080935700E89508950F921F928BBFFB0123
|
||||||
|
:10F1D000DA0190E80D901D9081E080935700E8954A
|
||||||
|
:10F1E00032969A95B9F7FB0185E080935700E89530
|
||||||
|
:10F1F0008091570080FDFCCF81E180935700E89516
|
||||||
|
:10F200001F900F9008955E9808955E9A0895A1E06A
|
||||||
|
:10F21000B0E0ECE0F9EFB8C68983B8DF2A988981BD
|
||||||
|
:10F22000B7DF2A9A2196E2E0CBC6A2E0B0E0EAE19D
|
||||||
|
:10F23000F9EFAAC66A838983E6DF89818068E7DF00
|
||||||
|
:10F240006A81862F8064E3DF2296E2E0B9C6CF931D
|
||||||
|
:10F25000DF93DBDFC8EFD1E080E0D9DF2197E1F772
|
||||||
|
:10F26000DF91CF910895EF92FF920F931F93CF9369
|
||||||
|
:10F27000DF938C01CADF1FC023E0829FC0011124ED
|
||||||
|
:10F280000F5F1F4FEC01C753D0412CECE22E2FEE45
|
||||||
|
:10F29000F22EE80EF91ECE01AA2797FDA095BA2FEF
|
||||||
|
:10F2A000ABBFFC018791880FB2DF2196CE15DF0539
|
||||||
|
:10F2B00091F780E0ACDFC801AA2797FDA095BA2F8F
|
||||||
|
:10F2C000ABBFFC0187918823B9F6CDB7DEB7E6E086
|
||||||
|
:10F2D00073C61F93209A229A569A48DF2A98289A32
|
||||||
|
:10F2E00018EC49DF1150E9F7289818EC44DF115069
|
||||||
|
:10F2F000E9F7289A18EC3FDF1150E9F784DF81E243
|
||||||
|
:10F3000086DF8FEB84DF84E182DF80E280DF8CE0C8
|
||||||
|
:10F310007EDF80E060E089DF9ADF1F910895A2E040
|
||||||
|
:10F32000B0E0E4E9F9EF29C65C9A599A5A9A8FE459
|
||||||
|
:10F3300093EC0197F1F700C00000499956C04C9931
|
||||||
|
:10F3400054C0239AC6DF89E191EF8DDF80E062E04F
|
||||||
|
:10F350006CDF8DE091E0A0D280E091E0ACD3882317
|
||||||
|
:10F3600009F03AC083E091EF7EDFEE24FF248701AD
|
||||||
|
:10F370006E010894C11CD11C88E0B82EC801B701E9
|
||||||
|
:10F3800014DF87E391E06FEF70E040E051E023D6B7
|
||||||
|
:10F3900087E391E060E071E0A601ECD489819A8175
|
||||||
|
:10F3A000009729F0C801B70147E351E00DDF85B1AF
|
||||||
|
:10F3B0008B2585B980E091E0A0E0B0E0E80EF91E71
|
||||||
|
:10F3C0000A1F1B1F90E0E91690EFF90691E009076C
|
||||||
|
:10F3D00090E0190799F603C080EF90EF44DF499B56
|
||||||
|
:10F3E000FECF4C9BFCCF4A9BFACF80E090E0FC0123
|
||||||
|
:10F3F00025913491AFEF2F3F3A0711F0FC010995A9
|
||||||
|
:10F4000068DF80E060E011DF8AED90EF2CDFFFCF56
|
||||||
|
:10F41000DF92EF92FF920F931F93182F042FF52E78
|
||||||
|
:10F42000E62ED72E87FF08C087E740E050E0BA01FC
|
||||||
|
:10F43000EFDF8230E0F41F77A6DE812FA9DE8D2D6D
|
||||||
|
:10F44000A7DE8E2DA5DE8F2DA3DE802FA1DE10344A
|
||||||
|
:10F4500021F0183421F081E003C085E901C087E87C
|
||||||
|
:10F4600097DE1AE094DE87FF02C01150D9F71F9192
|
||||||
|
:10F470000F91FF90EF90DF900895A5E0B0E0E2E4F7
|
||||||
|
:10F48000FAEF7CC573DE04E676DE0150E9F70AE0A8
|
||||||
|
:10F490007DDE0150E9F780E440E050E0BA01B8DFDA
|
||||||
|
:10F4A000813009F067C088E44AEA51E060E070E02A
|
||||||
|
:10F4B000AFDF8130D1F58E010F5F1F4F45E0C42EC5
|
||||||
|
:10F4C000D12CCC0EDD1E780162DEF70181937F0125
|
||||||
|
:10F4D000EC15FD05C9F78B81813009F04BC08C819B
|
||||||
|
:10F4E0008A3A09F047C008C046DE0894E108F108EE
|
||||||
|
:10F4F000E114F10429F43EC030E1E32E37E2F32EAB
|
||||||
|
:10F5000089EE40E050E060E070E482DF882361F73C
|
||||||
|
:10F510003DC03DDEF80181938F01EC15FD05C9F773
|
||||||
|
:10F52000898186FF25C09CE026C089EE40E050E03E
|
||||||
|
:10F53000BA016EDF823020F492E029EEE22E03C0A1
|
||||||
|
:10F5400091E081E4E82E00E117E208C09D8313DE1C
|
||||||
|
:10F55000015010409D810115110561F08E2D40E094
|
||||||
|
:10F5600050E0BA019D8354DF9D81882379F717C04D
|
||||||
|
:10F5700094E001C090E090930A019D8307DE81E052
|
||||||
|
:10F580009D81911180E02596E8E014C58AE740E06E
|
||||||
|
:10F5900050E0BA013DDF882309F4BBCFEBCF80E513
|
||||||
|
:10F5A00040E052E060E070E09D8332DF9D8188237F
|
||||||
|
:10F5B00009F7E1CFA1E0B0E0EFEDFAEFDDC46C01B7
|
||||||
|
:10F5C000590180910A0183FD07C0E9E0440F551FEE
|
||||||
|
:10F5D000661F771FEA95D1F781E51ADF882391F539
|
||||||
|
:10F5E00050E4E52E5CE9F52ED2DD8F3F39F4089426
|
||||||
|
:10F5F000E108F108E114F104B9F724C08E3F11F5D8
|
||||||
|
:10F60000EE24FF24EA18FB0882E092E0E80EF91EDF
|
||||||
|
:10F61000E01AF10AA114B10429F0B9DD0894A10897
|
||||||
|
:10F62000B108F8CFB4DDF60181936F0101501040AD
|
||||||
|
:10F63000C9F7ADDD0894E108F108E114F104C9F758
|
||||||
|
:10F6400080E001C081E08983A1DD89812196EAE023
|
||||||
|
:10F65000AFC4CF93DF93C0910B01D0910C016250E6
|
||||||
|
:10F660007040804090402E813F81488559852250CE
|
||||||
|
:10F67000304040405040621773078407950780F47C
|
||||||
|
:10F680002A8130E040E050E02ED49B01AC018A8911
|
||||||
|
:10F690009B89AC89BD89280F391F4A1F5B1F03C096
|
||||||
|
:10F6A00020E030E0A901B901CA01DF91CF910895AE
|
||||||
|
:10F6B000CF93DF93EC01E0910B01F0910C011982E3
|
||||||
|
:10F6C00018826C817D818E819F81613071058105F9
|
||||||
|
:10F6D000910551F126813781408551856217730765
|
||||||
|
:10F6E0008407950708F5611571058105910539F4C1
|
||||||
|
:10F6F0002081233021F46685778580899189688708
|
||||||
|
:10F7000079878A879B87611571058105910511F0BD
|
||||||
|
:10F71000A0DF04C066857785808991896C877D87A5
|
||||||
|
:10F720008E879F8780E001C081E0DF91CF910895AF
|
||||||
|
:10F73000A4E0B0E0EDE9FBEF25C4DC01CB01E091F2
|
||||||
|
:10F740000B01F0910C0182309105A105B10508F47F
|
||||||
|
:10F7500052C0268137814085518582179307A407BF
|
||||||
|
:10F76000B50708F048C02081223021F0233009F08D
|
||||||
|
:10F7700042C01CC0492F5A2F6B2F77270285138553
|
||||||
|
:10F7800024853585400F511F621F731F9C01307007
|
||||||
|
:10F79000220F331FCE01019602E010E00BDF882319
|
||||||
|
:10F7A00051F529813A8140E050E029C0AC01BD010A
|
||||||
|
:10F7B00027E076956795579547952A95D1F7028565
|
||||||
|
:10F7C000138524853585400F511F621F731F9C01CF
|
||||||
|
:10F7D0002F773070220F331F220F331FCE01019677
|
||||||
|
:10F7E00004E010E0E7DE882331F429813A814B817F
|
||||||
|
:10F7F0005C815F7004C021E030E040E050E0B9017E
|
||||||
|
:10F80000CA012496E4E0DAC3A0E0B0E0E9E0FCEF4E
|
||||||
|
:10F81000B1C3F82EE92E5A016B012EEF31E002E060
|
||||||
|
:10F8200010E0C8DE882369F58F2CE4014E019E2C80
|
||||||
|
:10F83000E401888199812AEA8535920721F58F2D87
|
||||||
|
:10F840009E2DB601A50126E330E0B4DE882331F415
|
||||||
|
:10F850008881998121E486349207B9F08F2D9E2DFD
|
||||||
|
:10F86000B601A50122E530E002E010E0A3DE882326
|
||||||
|
:10F8700071F481E02881398191E42634390741F41B
|
||||||
|
:10F8800004C083E005C082E003C080E001C081E0E5
|
||||||
|
:10F89000CDB7DEB7ECE08AC3A8E2B0E0E1E5FCEF6B
|
||||||
|
:10F8A00065C37C0110920C0110920B01009709F4C2
|
||||||
|
:10F8B000F8C0E3DD80FDF7C06E010894C11CD11CC7
|
||||||
|
:10F8C000C60140E050E0BA019FDF8130C9F4C601B3
|
||||||
|
:10F8D00040E050E0BA012EEB31E000E110E06ADEDA
|
||||||
|
:10F8E000882309F0E2C08D81882309F4E0C089846F
|
||||||
|
:10F8F0009A84AB84BC84C601B501A40185DF03C032
|
||||||
|
:10F90000882499245401833009F4CFC0882309F056
|
||||||
|
:10F91000CEC06E010894C11CD11CC601B501A40162
|
||||||
|
:10F920002DE030E004E210E045DE882309F0BDC0A0
|
||||||
|
:10F93000D60119966D917C911A9780E090E061153F
|
||||||
|
:10F9400071058105910521F4688D798D8A8D9B8DD6
|
||||||
|
:10F950002C8130E040E050E0C6D26DA37EA38FA39F
|
||||||
|
:10F9600098A7F6014180528066247724480C591CE0
|
||||||
|
:10F970006A1C7B1CD7011A964D925D926D927C9207
|
||||||
|
:10F980001D97E9811296EC93D60114964D915C91E6
|
||||||
|
:10F990001597D70115965C934E931497D60116963A
|
||||||
|
:10F9A0006D917C91179780E090E06115710581055C
|
||||||
|
:10F9B000910521F46C897D898E899F8904E0569593
|
||||||
|
:10F9C00047950A95E1F74A01AA24BB24D60111966E
|
||||||
|
:10F9D0000D911C91129720E030E0601B710B820B9F
|
||||||
|
:10F9E000930B2DA13EA14FA158A5621B730B840B55
|
||||||
|
:10F9F000950B681979098A099B092E2F30E040E0A0
|
||||||
|
:10FA000050E090D22E5F3F4F4F4F5F4FD701169679
|
||||||
|
:10FA10002D933D934D935C931997273FBFE03B0790
|
||||||
|
:10FA2000B0E04B07B0E05B0708F441C0273FEFEFC1
|
||||||
|
:10FA30003E07E0E04E07E0E05E0710F482E001C020
|
||||||
|
:10FA400083E0D7018C93833029F488A199A1AAA1DE
|
||||||
|
:10FA5000BBA108C08DA19EA1AFA1B8A5840D951D25
|
||||||
|
:10FA6000A61DB71DF70186879787A08BB18B480C21
|
||||||
|
:10FA7000591C6A1C7B1C2DA13EA14FA158A5420E0A
|
||||||
|
:10FA8000531E641E751ED70152964D925D926D9263
|
||||||
|
:10FA90007C92559711961C921197F0920C01E0926E
|
||||||
|
:10FAA0000B0180E005C082E003C081E001C087E077
|
||||||
|
:10FAB000A896E0E177C2ACE3B0E0E0E6FDEF54C227
|
||||||
|
:10FAC000C0900B01D0900C01C114D10409F446C1BF
|
||||||
|
:10FAD000F60111829E012F5F3F4F388B2F877C01EB
|
||||||
|
:10FAE000FC01208101962032D1F32F3209F47C01F0
|
||||||
|
:10FAF000198A1A8A1B8A1C8AF7018081813240F494
|
||||||
|
:10FB0000CE010D96D5DD1D8E882309F4F7C029C1DD
|
||||||
|
:10FB100090E2892E8DE0482E512C4C0E5D1EBDE1E9
|
||||||
|
:10FB20006B2E712C6C0E7D1EA8E22A2E312C2C0E11
|
||||||
|
:10FB30003D1EEF85F889DF01CF010B9601C08D9244
|
||||||
|
:10FB4000A817B907E1F790E0992428E0D701A90D9B
|
||||||
|
:10FB5000B11D8C9193948132C0F08F32B1F08E320E
|
||||||
|
:10FB600011F0921738F0283081F48E3271F498E059
|
||||||
|
:10FB70002BE0ECCF382F31563A3108F48052DF01B8
|
||||||
|
:10FB8000A90FB11D8C939F5FE1CF91E0813208F006
|
||||||
|
:10FB900090E09387C2018CDD882309F086C0498DEF
|
||||||
|
:10FBA0005A8D6B8D7C8D2D853E852F703070F5E0E4
|
||||||
|
:10FBB000220F331FFA95E1F7C30100E210E0FADCEF
|
||||||
|
:10FBC000882309F0D1C08D8D882309F4CFC088A582
|
||||||
|
:10FBD00083FD0BC0F301AF85B889E215F30509F485
|
||||||
|
:10FBE0006EC091918D919817C1F3A0900B01B090C8
|
||||||
|
:10FBF0000C010D851E850F5F1F4F09F4B7C0898D5D
|
||||||
|
:10FC00009A8DAB8DBC8D0097A105B10509F4AEC0EE
|
||||||
|
:10FC100098012F7030702115310509F043C001960D
|
||||||
|
:10FC2000A11DB11D898F9A8FAB8FBC8F6D897E8985
|
||||||
|
:10FC30008F89988D611571058105910541F4F50154
|
||||||
|
:10FC4000848195810817190708F090C02BC0F50131
|
||||||
|
:10FC5000228130E021503040A801E4E056954795DC
|
||||||
|
:10FC6000EA95E1F72423352321153105D9F460DD28
|
||||||
|
:10FC7000623071058105910508F476C0F501268191
|
||||||
|
:10FC8000378140855185621773078407950708F00F
|
||||||
|
:10FC90006DC06D8B7E8B8F8B988FDBDC698F7A8F3D
|
||||||
|
:10FCA0008B8F9C8F1E870D877ACF833009F059C0C8
|
||||||
|
:10FCB000EF85F8899385992309F45AC052C0EF85DE
|
||||||
|
:10FCC000F88983858823D1F488A584FF51C0E90C85
|
||||||
|
:10FCD000F11CF30184899589A0E0B0E0DC0199274B
|
||||||
|
:10FCE0008827228D338D40E050E0822B932BA42B6C
|
||||||
|
:10FCF000B52B898B9A8BAB8BBC8B1BCF8D8D8823BF
|
||||||
|
:10FD000079F188A584FD2CC0BE01635E7F4FFB01A5
|
||||||
|
:10FD100084899589A0E0B0E0DC0199278827228DAD
|
||||||
|
:10FD2000338D40E050E0822B932BA42BB52BF601B2
|
||||||
|
:10FD3000868F978FA0A3B1A3FB01848D958DA68D8F
|
||||||
|
:10FD4000B78DF601828F938FA48FB58F168A178A8D
|
||||||
|
:10FD5000108E118E81E0818380E003C086E001C0B7
|
||||||
|
:10FD600083E0EC96E2E11CC181E0FBCF83E0A0CF11
|
||||||
|
:10FD700084E0F7CFA0E0B0E0EFEBFEEFF7C03C018E
|
||||||
|
:10FD80007B014A01C0910B01D0910C01FA01118253
|
||||||
|
:10FD90001082209709F4A0C0898180FF9FC08A8DBE
|
||||||
|
:10FDA0009B8DAC8DBD8D2E893F89488D598D821BD1
|
||||||
|
:10FDB000930BA40BB50B9B0140E050E08217930717
|
||||||
|
:10FDC000A407B50708F47C015301412C72E0572EBB
|
||||||
|
:10FDD0007AC08E899F89A88DB98D9C01AD01317043
|
||||||
|
:10FDE000407050702115310541055105C1F59C0148
|
||||||
|
:10FDF000AD0169E056954795379527956A95D1F7F6
|
||||||
|
:10FE0000CA80CA94C222C1F40097A105B10529F4A1
|
||||||
|
:10FE10006E8D7F8D88A199A105C06AA17BA18CA15F
|
||||||
|
:10FE20009DA186DC623071058105910508F451C001
|
||||||
|
:10FE30006AA37BA38CA39DA36AA17BA18CA19DA196
|
||||||
|
:10FE400008DC611571058105910509F442C06C0D4E
|
||||||
|
:10FE5000711D811D911D6EA37FA388A799A72E896F
|
||||||
|
:10FE60003F893170C201821B930B67018E159F057C
|
||||||
|
:10FE700008F46C016114710419F480E090E001C091
|
||||||
|
:10FE8000C5014EA15FA168A579A5860193DB8823F2
|
||||||
|
:10FE900001F5960140E050E08E899F89A88DB98DCB
|
||||||
|
:10FEA000820F931FA41FB51F8E8B9F8BA88FB98FB6
|
||||||
|
:10FEB000AC0CBD1CEC18FD08F401808191818C0D07
|
||||||
|
:10FEC0009D1D91838083E114F10409F082CF80E0CD
|
||||||
|
:10FED00006C0198281E003C086E001C085E0CDB78D
|
||||||
|
:10FEE000DEB7E0E15FC0629FD001739FF001829FA7
|
||||||
|
:10FEF000E00DF11D649FE00DF11D929FF00D839FB9
|
||||||
|
:10FF0000F00D749FF00D659FF00D9927729FB00D55
|
||||||
|
:10FF1000E11DF91F639FB00DE11DF91FBD01CF0168
|
||||||
|
:10FF200011240895A1E21A2EAA1BBB1BFD010DC0CE
|
||||||
|
:10FF3000AA1FBB1FEE1FFF1FA217B307E407F50799
|
||||||
|
:10FF400020F0A21BB30BE40BF50B661F771F881F75
|
||||||
|
:10FF5000991F1A9469F760957095809590959B010B
|
||||||
|
:10FF6000AC01BD01CF0108952F923F924F925F9255
|
||||||
|
:10FF70006F927F928F929F92AF92BF92CF92DF92B9
|
||||||
|
:10FF8000EF92FF920F931F93CF93DF93CDB7DEB71E
|
||||||
|
:10FF9000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2
|
||||||
|
:10FFA0002A88398848885F846E847D848C849B8409
|
||||||
|
:10FFB000AA84B984C884DF80EE80FD800C811B8117
|
||||||
|
:10FFC000AA81B981CE0FD11D0FB6F894DEBF0FBE46
|
||||||
|
:10FFD000CDBFED010895DC0101C06D93415050404B
|
||||||
|
:08FFE000E0F70895F894FFCF4B
|
||||||
|
:0AFFE80066656D752E62696E0000FB
|
||||||
|
:040000031000F000F9
|
||||||
|
:00000001FF
|
14
arduino/bootldr/bootldr/Release/makedep.mk
Executable file
14
arduino/bootldr/bootldr/Release/makedep.mk
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
################################################################################
|
||||||
|
# Automatically-generated file. Do not edit or delete the file
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
asmfunc.S
|
||||||
|
|
||||||
|
lcd.c
|
||||||
|
|
||||||
|
main.c
|
||||||
|
|
||||||
|
mmc.c
|
||||||
|
|
||||||
|
pff.c
|
||||||
|
|
212
arduino/bootldr/bootldr/asmfunc.S
Executable file
212
arduino/bootldr/bootldr/asmfunc.S
Executable file
|
@ -0,0 +1,212 @@
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; MMC hardware controls and Flash controls (C)ChaN, 2010
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Hardware dependent macros to be modified
|
||||||
|
|
||||||
|
#define DDR_CS _SFR_IO_ADDR(DDRB), 4 // MMC CS pin (DDR, PORT)
|
||||||
|
#define PORT_CS _SFR_IO_ADDR(PORTB), 4
|
||||||
|
|
||||||
|
#define DDR_CK _SFR_IO_ADDR(DDRB), 7 // MMC SCLK pin (DDR, PORT)
|
||||||
|
#define PORT_CK _SFR_IO_ADDR(PORTB), 7
|
||||||
|
|
||||||
|
#define DDR_DI _SFR_IO_ADDR(DDRB), 5 // MMC DI pin (DDR, PORT)
|
||||||
|
#define PORT_DI _SFR_IO_ADDR(PORTB), 5
|
||||||
|
|
||||||
|
#define PIN_DO _SFR_IO_ADDR(PINB), 6 // MMC DO pin (PIN, PORT)
|
||||||
|
#define PORT_DO _SFR_IO_ADDR(PORTB), 6
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
.nolist
|
||||||
|
#include <avr/io.h>
|
||||||
|
.list
|
||||||
|
.text
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Initialize MMC port
|
||||||
|
;
|
||||||
|
; void init_spi (void);
|
||||||
|
|
||||||
|
.global init_spi
|
||||||
|
.func init_spi
|
||||||
|
init_spi:
|
||||||
|
sbi DDR_CS ; CS: output
|
||||||
|
sbi DDR_DI ; DI: output
|
||||||
|
sbi DDR_CK ; SCLK: output
|
||||||
|
sbi PORT_DO ; DO: pull-up
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Delay 100 microseconds
|
||||||
|
;
|
||||||
|
; void dly_us (UINT n);
|
||||||
|
|
||||||
|
.global dly_100us
|
||||||
|
.func dly_100us
|
||||||
|
dly_100us:
|
||||||
|
ldi r24, lo8(16000000 / 100000) ;(F_CPU / 100000) /* Loop counter */
|
||||||
|
1: sbiw r30, 1 /* 10 clocks per loop */
|
||||||
|
sbiw r30, 1
|
||||||
|
sbiw r30, 1
|
||||||
|
nop
|
||||||
|
dec r24
|
||||||
|
brne 1b
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Select MMC
|
||||||
|
;
|
||||||
|
; void select (void);
|
||||||
|
|
||||||
|
.global select
|
||||||
|
.func select
|
||||||
|
select:
|
||||||
|
rcall deselect
|
||||||
|
cbi PORT_CS
|
||||||
|
rjmp rcv_spi
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Deselect MMC
|
||||||
|
;
|
||||||
|
; void deselect (void);
|
||||||
|
|
||||||
|
.global deselect
|
||||||
|
.func deselect
|
||||||
|
deselect:
|
||||||
|
sbi PORT_CS
|
||||||
|
; Goto next function
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Receive a byte
|
||||||
|
;
|
||||||
|
; BYTE rcv_spi (void);
|
||||||
|
|
||||||
|
.global rcv_spi
|
||||||
|
.func rcv_spi
|
||||||
|
rcv_spi:
|
||||||
|
ldi r24, 0xFF ; Send 0xFF to receive data
|
||||||
|
; Goto next function
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------;
|
||||||
|
; Transmit a byte
|
||||||
|
;
|
||||||
|
; void xmit_spi (BYTE);
|
||||||
|
|
||||||
|
.global xmit_spi
|
||||||
|
.func xmit_spi
|
||||||
|
xmit_spi:
|
||||||
|
ldi r25, 8
|
||||||
|
1: sbrc r24, 7 ; DI = Bit to sent
|
||||||
|
sbi PORT_DI ;
|
||||||
|
sbrs r24, 7 ;
|
||||||
|
cbi PORT_DI ; /
|
||||||
|
lsl r24 ; Get DO from MMC
|
||||||
|
sbic PIN_DO ;
|
||||||
|
inc r24 ; /
|
||||||
|
sbi PORT_CK ; A positive pulse to SCLK
|
||||||
|
cbi PORT_CK ; /
|
||||||
|
dec r25 ; Repeat 8 times
|
||||||
|
brne 1b ; /
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------
|
||||||
|
; Erase a flash page
|
||||||
|
;
|
||||||
|
; void flash_erase (DWORD flash_addr);
|
||||||
|
|
||||||
|
.global flash_erase
|
||||||
|
.func flash_erase
|
||||||
|
flash_erase:
|
||||||
|
|
||||||
|
movw ZL, r22
|
||||||
|
#if FLASHEND >= 0x10000
|
||||||
|
out _SFR_IO_ADDR(RAMPZ), r24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; Initiate erase operation
|
||||||
|
ldi r24, 0b00000011
|
||||||
|
sts _SFR_MEM_ADDR(SPMCSR), r24
|
||||||
|
spm
|
||||||
|
|
||||||
|
; Wait for end of erase operation
|
||||||
|
1: lds r24, _SFR_MEM_ADDR(SPMCSR)
|
||||||
|
sbrc r24, 0
|
||||||
|
rjmp 1b
|
||||||
|
|
||||||
|
; Re-enable read access to the flash
|
||||||
|
ldi r24, 0b00010001
|
||||||
|
sts _SFR_MEM_ADDR(SPMCSR), r24
|
||||||
|
spm
|
||||||
|
|
||||||
|
9: ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------
|
||||||
|
; Write a flash page
|
||||||
|
;
|
||||||
|
; void flash_write (DWORD flash_addr, const BYTE* data);
|
||||||
|
|
||||||
|
.global flash_write
|
||||||
|
.func flash_write
|
||||||
|
flash_write:
|
||||||
|
push r0
|
||||||
|
push r1
|
||||||
|
|
||||||
|
#if FLASHEND >= 0x10000
|
||||||
|
out _SFR_IO_ADDR(RAMPZ), r24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; Fill page buffer
|
||||||
|
movw ZL, r22
|
||||||
|
movw XL, r20
|
||||||
|
ldi r25, lo8(SPM_PAGESIZE/2)
|
||||||
|
1: ld r0, X+
|
||||||
|
ld r1, X+
|
||||||
|
ldi r24, 0b00000001
|
||||||
|
sts _SFR_MEM_ADDR(SPMCSR), r24
|
||||||
|
spm
|
||||||
|
adiw ZL, 2
|
||||||
|
dec r25
|
||||||
|
brne 1b
|
||||||
|
|
||||||
|
; Initiate write operation
|
||||||
|
movw ZL, r22
|
||||||
|
ldi r24, 0b00000101
|
||||||
|
sts _SFR_MEM_ADDR(SPMCSR), r24
|
||||||
|
spm
|
||||||
|
|
||||||
|
; Wait for end of write operation
|
||||||
|
2: lds r24, _SFR_MEM_ADDR(SPMCSR)
|
||||||
|
sbrc r24, 0
|
||||||
|
rjmp 2b
|
||||||
|
|
||||||
|
; Re-enable read access to the flash
|
||||||
|
ldi r24, 0b00010001
|
||||||
|
sts _SFR_MEM_ADDR(SPMCSR), r24
|
||||||
|
spm
|
||||||
|
|
||||||
|
9: pop r1
|
||||||
|
pop r0
|
||||||
|
ret
|
||||||
|
.endfunc
|
20
arduino/bootldr/bootldr/bootldr.c
Executable file
20
arduino/bootldr/bootldr/bootldr.c
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* bootldr.c
|
||||||
|
*
|
||||||
|
* Created: 10/6/2013 12:43:37 PM
|
||||||
|
* Author: chamberlin
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#ifdef USE_BOOTLDR_MAIN
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
//TODO:: Please write your application code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
109
arduino/bootldr/bootldr/bootldr.cproj
Executable file
109
arduino/bootldr/bootldr/bootldr.cproj
Executable file
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectVersion>5.1</ProjectVersion>
|
||||||
|
<ToolchainName>com.Atmel.AVRGCC8</ToolchainName>
|
||||||
|
<ProjectGuid>{4bf88424-65a0-49e2-90b5-584b8fb3e794}</ProjectGuid>
|
||||||
|
<avrdevice>ATmega1284P</avrdevice>
|
||||||
|
<avrdeviceseries>none</avrdeviceseries>
|
||||||
|
<OutputType>Executable</OutputType>
|
||||||
|
<Language>C</Language>
|
||||||
|
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
|
||||||
|
<OutputFileExtension>.elf</OutputFileExtension>
|
||||||
|
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
|
||||||
|
<AssemblyName>bootldr</AssemblyName>
|
||||||
|
<Name>bootldr</Name>
|
||||||
|
<RootNamespace>bootldr</RootNamespace>
|
||||||
|
<ToolchainFlavour>Native</ToolchainFlavour>
|
||||||
|
<AsfVersion>2.11.1</AsfVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<ToolchainSettings>
|
||||||
|
<AvrGcc>
|
||||||
|
<avrgcc.compiler.general.SubroutinesFunctionPrologues>True</avrgcc.compiler.general.SubroutinesFunctionPrologues>
|
||||||
|
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||||
|
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||||
|
<avrgcc.compiler.symbols.DefSymbols>
|
||||||
|
<ListValues>
|
||||||
|
<Value>F_CPU=20000000</Value>
|
||||||
|
<Value>BOOT_ADR=0x1F000</Value>
|
||||||
|
</ListValues>
|
||||||
|
</avrgcc.compiler.symbols.DefSymbols>
|
||||||
|
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
|
||||||
|
<avrgcc.compiler.optimization.OtherFlags>-fdata-sections</avrgcc.compiler.optimization.OtherFlags>
|
||||||
|
<avrgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>True</avrgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>
|
||||||
|
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||||
|
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||||
|
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||||
|
<avrgcc.linker.libraries.Libraries>
|
||||||
|
<ListValues>
|
||||||
|
<Value>m</Value>
|
||||||
|
</ListValues>
|
||||||
|
</avrgcc.linker.libraries.Libraries>
|
||||||
|
<avrgcc.linker.optimization.GarbageCollectUnusedSections>True</avrgcc.linker.optimization.GarbageCollectUnusedSections>
|
||||||
|
<avrgcc.linker.optimization.RelaxBranches>True</avrgcc.linker.optimization.RelaxBranches>
|
||||||
|
<avrgcc.linker.memorysettings.Flash>
|
||||||
|
<ListValues>
|
||||||
|
<Value>.text=0xF800</Value>
|
||||||
|
</ListValues>
|
||||||
|
</avrgcc.linker.memorysettings.Flash>
|
||||||
|
<avrgcc.assembler.symbols.DefSymbols>
|
||||||
|
<ListValues>
|
||||||
|
<Value>F_CPU=20000000</Value>
|
||||||
|
<Value>BOOT_ADR=0x1F000</Value>
|
||||||
|
</ListValues>
|
||||||
|
</avrgcc.assembler.symbols.DefSymbols>
|
||||||
|
</AvrGcc>
|
||||||
|
</ToolchainSettings>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<ToolchainSettings>
|
||||||
|
<AvrGcc>
|
||||||
|
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||||
|
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||||
|
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
|
||||||
|
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||||
|
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
|
||||||
|
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
|
||||||
|
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||||
|
<avrgcc.assembler.debugging.DebugLevel>Default (-g2)</avrgcc.assembler.debugging.DebugLevel>
|
||||||
|
<avrgcc.linker.libraries.Libraries>
|
||||||
|
<ListValues>
|
||||||
|
<Value>m</Value>
|
||||||
|
</ListValues>
|
||||||
|
</avrgcc.linker.libraries.Libraries>
|
||||||
|
</AvrGcc>
|
||||||
|
</ToolchainSettings>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="asmfunc.S">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="diskio.h">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="integer.h">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="lcd.c">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="lcd.h">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="main.c">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="mmc.c">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="pff.c">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="pff.h">
|
||||||
|
<SubType>compile</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
|
||||||
|
</Project>
|
41
arduino/bootldr/bootldr/diskio.h
Executable file
41
arduino/bootldr/bootldr/diskio.h
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
/*-----------------------------------------------------------------------
|
||||||
|
/ PFF - Low level disk interface modlue include file (C)ChaN, 2009
|
||||||
|
/-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _DISKIO
|
||||||
|
|
||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Status of Disk Functions */
|
||||||
|
typedef BYTE DSTATUS;
|
||||||
|
|
||||||
|
|
||||||
|
/* Results of Disk Functions */
|
||||||
|
typedef enum {
|
||||||
|
RES_OK = 0, /* 0: Function succeeded */
|
||||||
|
RES_ERROR, /* 1: Disk error */
|
||||||
|
RES_NOTRDY, /* 2: Not ready */
|
||||||
|
RES_PARERR /* 3: Invalid parameter */
|
||||||
|
} DRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------*/
|
||||||
|
/* Prototypes for disk control functions */
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (void);
|
||||||
|
DRESULT disk_readp (BYTE*, DWORD, WORD, WORD);
|
||||||
|
DRESULT disk_writep (const BYTE*, DWORD);
|
||||||
|
|
||||||
|
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||||
|
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||||
|
|
||||||
|
/* Card type flags (CardType) */
|
||||||
|
#define CT_MMC 0x01 /* MMC ver 3 */
|
||||||
|
#define CT_SD1 0x02 /* SD ver 1 */
|
||||||
|
#define CT_SD2 0x04 /* SD ver 2 */
|
||||||
|
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
|
||||||
|
#define CT_BLOCK 0x08 /* Block addressing */
|
||||||
|
|
||||||
|
#define _DISKIO
|
||||||
|
#endif
|
37
arduino/bootldr/bootldr/integer.h
Executable file
37
arduino/bootldr/bootldr/integer.h
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
/*-------------------------------------------*/
|
||||||
|
/* Integer type definitions for FatFs module */
|
||||||
|
/*-------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _INTEGER
|
||||||
|
#define _INTEGER
|
||||||
|
|
||||||
|
#ifdef _WIN32 /* FatFs development platform */
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
#else /* Embedded platform */
|
||||||
|
|
||||||
|
/* These types must be 16-bit, 32-bit or larger integer */
|
||||||
|
typedef int INT;
|
||||||
|
typedef unsigned int UINT;
|
||||||
|
|
||||||
|
/* These types must be 8-bit integer */
|
||||||
|
typedef char CHAR;
|
||||||
|
typedef unsigned char UCHAR;
|
||||||
|
typedef unsigned char BYTE;
|
||||||
|
|
||||||
|
/* These types must be 16-bit integer */
|
||||||
|
typedef short SHORT;
|
||||||
|
typedef unsigned short USHORT;
|
||||||
|
typedef unsigned short WORD;
|
||||||
|
typedef unsigned short WCHAR;
|
||||||
|
|
||||||
|
/* These types must be 32-bit integer */
|
||||||
|
typedef long LONG;
|
||||||
|
typedef unsigned long ULONG;
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
149
arduino/bootldr/bootldr/lcd.c
Executable file
149
arduino/bootldr/bootldr/lcd.c
Executable file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void init_spi (void); /* Initialize SPI port (asmfunc.S) */
|
||||||
|
void deselect (void); /* Select MMC (asmfunc.S) */
|
||||||
|
void select (void); /* Deselect MMC (asmfunc.S) */
|
||||||
|
void xmit_spi (uint8_t d); /* Send a byte to the MMC (asmfunc.S) */
|
||||||
|
void dly_100us (void); /* Delay 100 microseconds (asmfunc.S) */
|
||||||
|
|
||||||
|
extern const uint8_t tiny_font[][3] PROGMEM;
|
||||||
|
const uint8_t tiny_font[][3] = {
|
||||||
|
{0x1e,0x05,0x1e}, // 41 A
|
||||||
|
{0x1f,0x15,0x0a}, // 42 B
|
||||||
|
{0x0e,0x11,0x11}, // 43 C
|
||||||
|
{0x1f,0x11,0x0e}, // 44 D
|
||||||
|
{0x1f,0x15,0x15}, // 45 E
|
||||||
|
{0x1f,0x05,0x05}, // 46 F
|
||||||
|
{0x0e,0x15,0x1d}, // 47 G
|
||||||
|
{0x1f,0x04,0x1f}, // 48 H
|
||||||
|
{0x11,0x1f,0x11}, // 49 I
|
||||||
|
{0x08,0x10,0x0f}, // 4a J
|
||||||
|
{0x1f,0x04,0x1b}, // 4b K
|
||||||
|
{0x1f,0x10,0x10}, // 4c L
|
||||||
|
{0x1f,0x06,0x1f}, // 4d M
|
||||||
|
{0x1f,0x0e,0x1f}, // 4e N
|
||||||
|
{0x0e,0x11,0x0e}, // 4f O
|
||||||
|
{0x1f,0x05,0x02}, // 50 P
|
||||||
|
{0x00,0x10,0x00}, // 51 . (not Q)
|
||||||
|
{0x1f,0x0d,0x16}, // 52 R
|
||||||
|
{0x12,0x15,0x09}, // 53 S
|
||||||
|
{0x01,0x1f,0x01}, // 54 T
|
||||||
|
{0x0f,0x10,0x1f}, // 55 U
|
||||||
|
{0x07,0x18,0x07}, // 56 V
|
||||||
|
{0x1f,0x0c,0x1f}, // 57 W
|
||||||
|
{0x00,0x00,0x00}, // 58 space (not X)
|
||||||
|
{0x03,0x1c,0x03}, // 59 Y
|
||||||
|
{0x00,0x0a,0x00} // 5a : (not Z)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LCD_DDR DDRB
|
||||||
|
#define LCD_PORT PORTB
|
||||||
|
#define LCD_RESET_PIN_NUMBER 0
|
||||||
|
#define LCD_CS_PIN_NUMBER 2
|
||||||
|
#define LCD_DC_DDR DDRD
|
||||||
|
#define LCD_DC_PORT PORTD
|
||||||
|
#define LCD_DC_PIN_NUMBER 6
|
||||||
|
|
||||||
|
void LcdCommand()
|
||||||
|
{
|
||||||
|
LCD_DC_PORT &= ~(1<<LCD_DC_PIN_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdData()
|
||||||
|
{
|
||||||
|
LCD_DC_PORT |= (1<<LCD_DC_PIN_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdWrite(uint8_t data)
|
||||||
|
{
|
||||||
|
deselect(); // make sure the SD card is not selected
|
||||||
|
|
||||||
|
LCD_PORT &= ~(1<<LCD_CS_PIN_NUMBER);
|
||||||
|
|
||||||
|
xmit_spi(data);
|
||||||
|
|
||||||
|
LCD_PORT |= (1<<LCD_CS_PIN_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdGoto(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
LcdCommand();
|
||||||
|
LcdWrite(0x80 | x);
|
||||||
|
LcdWrite(0x40 | y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdClear(void)
|
||||||
|
{
|
||||||
|
LcdData();
|
||||||
|
for (uint16_t index = 0; index < 84 * 6; index++)
|
||||||
|
{
|
||||||
|
LcdWrite(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdString(const char *s)
|
||||||
|
{
|
||||||
|
LcdData();
|
||||||
|
|
||||||
|
uint8_t c;
|
||||||
|
while ((c = pgm_read_byte_far(s)))
|
||||||
|
{
|
||||||
|
unsigned short charbase = (c - 0x41) * 3;
|
||||||
|
s++;
|
||||||
|
|
||||||
|
for (uint8_t index = 0; index < 3; index++)
|
||||||
|
{
|
||||||
|
// need to use pgm_read_byte_far on Atmegas with more than 64K Flash
|
||||||
|
uint8_t pixels = pgm_read_byte_far((unsigned char*)tiny_font + charbase + index);
|
||||||
|
pixels = pixels << 1;
|
||||||
|
LcdWrite(pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
LcdWrite(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdInit()
|
||||||
|
{
|
||||||
|
// set LCD pin directions
|
||||||
|
LCD_DDR |= (1<<LCD_RESET_PIN_NUMBER);
|
||||||
|
LCD_DDR |= (1<<LCD_CS_PIN_NUMBER);
|
||||||
|
LCD_DC_DDR |= (1<<LCD_DC_PIN_NUMBER);
|
||||||
|
|
||||||
|
init_spi();
|
||||||
|
|
||||||
|
// toggle RST low to reset; CS low so it'll listen to us
|
||||||
|
LCD_PORT &= ~(1<<LCD_CS_PIN_NUMBER);
|
||||||
|
|
||||||
|
LCD_PORT |= (1<<LCD_RESET_PIN_NUMBER);
|
||||||
|
for (uint8_t n = 200; n; n--) dly_100us();
|
||||||
|
LCD_PORT &= ~(1<<LCD_RESET_PIN_NUMBER);
|
||||||
|
for (uint8_t n = 200; n; n--) dly_100us();
|
||||||
|
LCD_PORT |= (1<<LCD_RESET_PIN_NUMBER);
|
||||||
|
for (uint8_t n = 200; n; n--) dly_100us();
|
||||||
|
|
||||||
|
LcdCommand();
|
||||||
|
LcdWrite(0x21); // LCD Extended Commands.
|
||||||
|
LcdWrite(0xBF); // Set LCD Vop (Contrast).
|
||||||
|
LcdWrite(0x14); // LCD bias mode
|
||||||
|
LcdWrite(0x20);
|
||||||
|
LcdWrite(0x0C); // LCD in normal mode. 0x0d for inverse
|
||||||
|
|
||||||
|
LcdGoto(0,0);
|
||||||
|
LcdClear();
|
||||||
|
}
|
20
arduino/bootldr/bootldr/lcd.h
Executable file
20
arduino/bootldr/bootldr/lcd.h
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void LcdCommand(void);
|
||||||
|
void LcdData(void);
|
||||||
|
void LcdWrite(uint8_t data);
|
||||||
|
void LcdGoto(uint8_t x, uint8_t y);
|
||||||
|
void LcdClear(void);
|
||||||
|
void LcdString(const char *s);
|
||||||
|
void LcdInit(void);
|
126
arduino/bootldr/bootldr/main.c
Executable file
126
arduino/bootldr/bootldr/main.c
Executable file
|
@ -0,0 +1,126 @@
|
||||||
|
/*-------------------------------------------------------------------------/
|
||||||
|
/ Stand-alone MMC boot loader R0.01
|
||||||
|
/--------------------------------------------------------------------------/
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2010, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * This software is a free software and there is NO WARRANTY.
|
||||||
|
/ * No restriction on use. You can use, modify and redistribute it for
|
||||||
|
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/
|
||||||
|
/--------------------------------------------------------------------------/
|
||||||
|
/ Dec 6, 2010 R0.01 First release
|
||||||
|
/--------------------------------------------------------------------------/
|
||||||
|
/ This is a stand-alone MMC/SD boot loader for megaAVRs. It requires a 4KB
|
||||||
|
/ boot section for code, four GPIO pins for MMC/SD as shown in sch.jpg and
|
||||||
|
/ nothing else. To port the boot loader into your project, follow the
|
||||||
|
/ instruction sdescribed below.
|
||||||
|
/
|
||||||
|
/ 1. Setup the hardware. Attach a memory card socket to the any GPIO port
|
||||||
|
/ where you like. Select boot size at least 4KB for the boot loader with
|
||||||
|
/ BOOTSZ fuses and enable boot loader with BOOTRST fuse.
|
||||||
|
/
|
||||||
|
/ 2. Setup the software. Change the four port definitions in the asmfunc.S.
|
||||||
|
/ Change MCU_TARGET, BOOT_ADR and MCU_FREQ in the Makefile. The BOOT_ADR
|
||||||
|
/ is a BYTE address of boot section in the flash. Build the boot loader
|
||||||
|
/ and write it to the device with a programmer.
|
||||||
|
/
|
||||||
|
/ 3. Build the application program and output it in binary form instead of
|
||||||
|
/ hex format. Rename the file "app.bin" and put it into the memory card.
|
||||||
|
/
|
||||||
|
/ 4. Insert the card and turn the target power on. When the boot loader found
|
||||||
|
/ the application file, the file is written into the flash memory prior to
|
||||||
|
/ start the application program. On-board LED lights (if exist) during
|
||||||
|
/ the flash programming operation.
|
||||||
|
/
|
||||||
|
/--------------------------------------------------------------------------/
|
||||||
|
/ Modified by Steve Chamberlin for Floppy Emu, October 2013
|
||||||
|
/-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "pff.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
|
||||||
|
void flash_erase (DWORD); /* Erase a flash page (asmfunc.S) */
|
||||||
|
void flash_write (DWORD, const BYTE*); /* Program a flash page (asmfunc.S) */
|
||||||
|
|
||||||
|
FATFS Fatfs; /* Petit-FatFs work area */
|
||||||
|
BYTE Buff[SPM_PAGESIZE]; /* Page data buffer */
|
||||||
|
|
||||||
|
#define BUTTON_PORT PORTD
|
||||||
|
#define BUTTON_PIN PIND
|
||||||
|
#define SELECT_BUTTON_PIN 4
|
||||||
|
#define PREV_BUTTON_PIN 1
|
||||||
|
#define NEXT_BUTTON_PIN 2
|
||||||
|
|
||||||
|
#define LED_DDR DDRB
|
||||||
|
#define LED_PORT PORTB
|
||||||
|
#define LED_PIN_NUMBER 3
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
DWORD fa; /* Flash address */
|
||||||
|
WORD br; /* Bytes read */
|
||||||
|
|
||||||
|
// enable the pull-up resistor for the user buttons
|
||||||
|
BUTTON_PORT |= (1<<SELECT_BUTTON_PIN);
|
||||||
|
BUTTON_PORT |= (1<<PREV_BUTTON_PIN);
|
||||||
|
BUTTON_PORT |= (1<<NEXT_BUTTON_PIN);
|
||||||
|
|
||||||
|
_delay_ms(10);
|
||||||
|
|
||||||
|
// if PREV and SELECT are pressed, try to perform an application update
|
||||||
|
if (bit_is_clear(BUTTON_PIN, PREV_BUTTON_PIN) &&
|
||||||
|
bit_is_clear(BUTTON_PIN, SELECT_BUTTON_PIN))
|
||||||
|
{
|
||||||
|
// set LED as output
|
||||||
|
LED_DDR |= (1<<LED_PIN_NUMBER);
|
||||||
|
|
||||||
|
LcdInit();
|
||||||
|
LcdString(PSTR("FLOPPYXEMUXBOOTLOADER"));
|
||||||
|
LcdGoto(0,2);
|
||||||
|
|
||||||
|
pf_mount(&Fatfs); /* Initialize file system */
|
||||||
|
if (pf_open("femu.bin") == FR_OK) /* Open application file */
|
||||||
|
{
|
||||||
|
LcdString(PSTR("FLASHINGXFEMUQBINXQQQ"));
|
||||||
|
|
||||||
|
for (fa = 0; fa < BOOT_ADR; fa += SPM_PAGESIZE) /* Update all application pages */
|
||||||
|
{
|
||||||
|
flash_erase(fa); /* Erase a page */
|
||||||
|
memset(Buff, 0xFF, SPM_PAGESIZE); /* Clear buffer */
|
||||||
|
pf_read(Buff, SPM_PAGESIZE, &br); /* Load a page data */
|
||||||
|
if (br) flash_write(fa, Buff); /* Write it if the data is available */
|
||||||
|
|
||||||
|
// blink the LED while writing
|
||||||
|
LED_PORT ^= (1<<LED_PIN_NUMBER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// couldn't open the application file
|
||||||
|
LcdString(PSTR("FEMUQBINXNOTXFOUND"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for all buttons to be released
|
||||||
|
while (bit_is_clear(BUTTON_PIN, PREV_BUTTON_PIN) ||
|
||||||
|
bit_is_clear(BUTTON_PIN, SELECT_BUTTON_PIN) ||
|
||||||
|
bit_is_clear(BUTTON_PIN, NEXT_BUTTON_PIN))
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pgm_read_word(0) != 0xFFFF) /* Start application if exist */
|
||||||
|
((void(*)(void))0)();
|
||||||
|
|
||||||
|
/* No application, Halt. */
|
||||||
|
LcdInit();
|
||||||
|
LcdGoto(0,0);
|
||||||
|
LcdString(PSTR("ERRORZXFLASHXISXEMPTY"));
|
||||||
|
for (;;) ;
|
||||||
|
}
|
||||||
|
|
203
arduino/bootldr/bootldr/mmc.c
Executable file
203
arduino/bootldr/bootldr/mmc.c
Executable file
|
@ -0,0 +1,203 @@
|
||||||
|
/*-----------------------------------------------------------------------/
|
||||||
|
/ PFF - Generic low level disk control module (C)ChaN, 2010
|
||||||
|
/------------------------------------------------------------------------/
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2010, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * This software is a free software and there is NO WARRANTY.
|
||||||
|
/ * No restriction on use. You can use, modify and redistribute it for
|
||||||
|
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/
|
||||||
|
/------------------------------------------------------------------------/
|
||||||
|
/* Dec 6, 2010 First release
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pff.h"
|
||||||
|
#include "diskio.h"
|
||||||
|
|
||||||
|
void init_spi (void); /* Initialize SPI port (asmfunc.S) */
|
||||||
|
void deselect (void); /* Select MMC (asmfunc.S) */
|
||||||
|
void select (void); /* Deselect MMC (asmfunc.S) */
|
||||||
|
void xmit_spi (BYTE d); /* Send a byte to the MMC (asmfunc.S) */
|
||||||
|
BYTE rcv_spi (void); /* Send a 0xFF to the MMC and get the received byte (asmfunc.S) */
|
||||||
|
void dly_100us (void); /* Delay 100 microseconds (asmfunc.S) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Module Private Functions
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Definitions for MMC/SDC command */
|
||||||
|
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
|
||||||
|
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
|
||||||
|
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
|
||||||
|
#define CMD8 (0x40+8) /* SEND_IF_COND */
|
||||||
|
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
|
||||||
|
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
|
||||||
|
#define CMD24 (0x40+24) /* WRITE_BLOCK */
|
||||||
|
#define CMD55 (0x40+55) /* APP_CMD */
|
||||||
|
#define CMD58 (0x40+58) /* READ_OCR */
|
||||||
|
|
||||||
|
|
||||||
|
/* Card type flags (CardType) */
|
||||||
|
#define CT_MMC 0x01 /* MMC ver 3 */
|
||||||
|
#define CT_SD1 0x02 /* SD ver 1 */
|
||||||
|
#define CT_SD2 0x04 /* SD ver 2 */
|
||||||
|
#define CT_BLOCK 0x08 /* Block addressing */
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE CardType;
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Send a command packet to MMC */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE send_cmd (
|
||||||
|
BYTE cmd, /* 1st byte (Start + Index) */
|
||||||
|
DWORD arg /* Argument (32 bits) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BYTE n, res;
|
||||||
|
|
||||||
|
|
||||||
|
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
||||||
|
cmd &= 0x7F;
|
||||||
|
res = send_cmd(CMD55, 0);
|
||||||
|
if (res > 1) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the card */
|
||||||
|
select();
|
||||||
|
|
||||||
|
/* Send a command packet */
|
||||||
|
xmit_spi(cmd); /* Start + Command index */
|
||||||
|
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||||
|
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||||
|
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||||
|
xmit_spi((BYTE)arg); /* Argument[7..0] */
|
||||||
|
n = 0x01; /* Dummy CRC + Stop */
|
||||||
|
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
||||||
|
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
||||||
|
xmit_spi(n);
|
||||||
|
|
||||||
|
/* Receive a command response */
|
||||||
|
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||||
|
do {
|
||||||
|
res = rcv_spi();
|
||||||
|
} while ((res & 0x80) && --n);
|
||||||
|
|
||||||
|
return res; /* Return with the response value */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Public Functions
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Initialize Disk Drive */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (void)
|
||||||
|
{
|
||||||
|
BYTE n, cmd, ty, ocr[4];
|
||||||
|
UINT tmr;
|
||||||
|
|
||||||
|
|
||||||
|
init_spi(); /* Initialize ports to control MMC */
|
||||||
|
for (n = 100; n; n--) dly_100us(); /* 10ms delay */
|
||||||
|
for (n = 10; n; n--) deselect(); /* 80 Dummy clocks with CS=H */
|
||||||
|
|
||||||
|
ty = 0;
|
||||||
|
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||||
|
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */
|
||||||
|
for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); /* Get trailing return value of R7 resp */
|
||||||
|
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||||
|
for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
||||||
|
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
||||||
|
for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
|
||||||
|
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* SDv1 or MMCv3 */
|
||||||
|
if (send_cmd(ACMD41, 0) <= 1) {
|
||||||
|
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
|
||||||
|
} else {
|
||||||
|
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
|
||||||
|
}
|
||||||
|
for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /* Wait for leaving idle state */
|
||||||
|
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
||||||
|
ty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CardType = ty;
|
||||||
|
deselect();
|
||||||
|
|
||||||
|
return ty ? 0 : STA_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read partial sector */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_readp (
|
||||||
|
BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
|
||||||
|
DWORD lba, /* Sector number (LBA) */
|
||||||
|
WORD ofs, /* Byte offset to read from (0..511) */
|
||||||
|
WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
BYTE rc;
|
||||||
|
WORD bc;
|
||||||
|
|
||||||
|
|
||||||
|
if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */
|
||||||
|
|
||||||
|
res = RES_ERROR;
|
||||||
|
if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */
|
||||||
|
|
||||||
|
bc = 40000;
|
||||||
|
do { /* Wait for data packet */
|
||||||
|
rc = rcv_spi();
|
||||||
|
} while (rc == 0xFF && --bc);
|
||||||
|
|
||||||
|
if (rc == 0xFE) { /* A data packet arrived */
|
||||||
|
bc = 514 - ofs - cnt;
|
||||||
|
|
||||||
|
/* Skip leading bytes */
|
||||||
|
if (ofs) {
|
||||||
|
do rcv_spi(); while (--ofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive a part of the sector */
|
||||||
|
do {
|
||||||
|
*buff++ = rcv_spi();
|
||||||
|
} while (--cnt);
|
||||||
|
|
||||||
|
/* Skip trailing bytes and CRC */
|
||||||
|
do rcv_spi(); while (--bc);
|
||||||
|
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deselect();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1114
arduino/bootldr/bootldr/pff.c
Executable file
1114
arduino/bootldr/bootldr/pff.c
Executable file
File diff suppressed because it is too large
Load Diff
192
arduino/bootldr/bootldr/pff.h
Executable file
192
arduino/bootldr/bootldr/pff.h
Executable file
|
@ -0,0 +1,192 @@
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Petit FatFs - FAT file system module include file R0.02a (C)ChaN, 2010
|
||||||
|
/----------------------------------------------------------------------------/
|
||||||
|
/ Petit FatFs module is an open source software to implement FAT file system to
|
||||||
|
/ small embedded systems. This is a free software and is opened for education,
|
||||||
|
/ research and commercial developments under license policy of following trems.
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2010, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * The Petit FatFs module is a free software and there is NO WARRANTY.
|
||||||
|
/ * No restriction on use. You can use, modify and redistribute it for
|
||||||
|
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Petit FatFs Configuration Options
|
||||||
|
/
|
||||||
|
/ CAUTION! Do not forget to make clean the project after any changes to
|
||||||
|
/ the configuration options.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
#ifndef _FATFS
|
||||||
|
#define _FATFS
|
||||||
|
|
||||||
|
#define _USE_READ 1 /* 1:Enable pf_read() */
|
||||||
|
|
||||||
|
#define _USE_DIR 0 /* 1:Enable pf_opendir() and pf_readdir() */
|
||||||
|
|
||||||
|
#define _USE_LSEEK 0 /* 1:Enable pf_lseek() */
|
||||||
|
|
||||||
|
#define _USE_WRITE 0 /* 1:Enable pf_write() */
|
||||||
|
|
||||||
|
#define _FS_FAT12 0 /* 1:Enable FAT12 support */
|
||||||
|
#define _FS_FAT32 1 /* 1:Enable FAT32 support */
|
||||||
|
|
||||||
|
|
||||||
|
#define _CODE_PAGE 1
|
||||||
|
/* Defines which code page is used for path name. Supported code pages are:
|
||||||
|
/ 932, 936, 949, 950, 437, 720, 737, 775, 850, 852, 855, 857, 858, 862, 866,
|
||||||
|
/ 874, 1250, 1251, 1252, 1253, 1254, 1255, 1257, 1258 and 1 (ASCII only).
|
||||||
|
/ SBCS code pages except for 1 requiers a case conversion table. This
|
||||||
|
/ might occupy 128 bytes on the RAM on some platforms, e.g. avr-gcc. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _WORD_ACCESS 1
|
||||||
|
/* The _WORD_ACCESS option defines which access method is used to the word
|
||||||
|
/ data in the FAT structure.
|
||||||
|
/
|
||||||
|
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||||
|
/ 1: Word access. Do not choose this unless following condition is met.
|
||||||
|
/
|
||||||
|
/ When the byte order on the memory is big-endian or address miss-aligned
|
||||||
|
/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
|
||||||
|
/ If it is not the case, the value can also be set to 1 to improve the
|
||||||
|
/ performance and code efficiency. */
|
||||||
|
|
||||||
|
|
||||||
|
/* End of configuration options. Do not change followings without care. */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if _FS_FAT32
|
||||||
|
#define CLUST DWORD
|
||||||
|
#else
|
||||||
|
#define CLUST WORD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* File system object structure */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE fs_type; /* FAT sub type */
|
||||||
|
BYTE flag; /* File status flags */
|
||||||
|
BYTE csize; /* Number of sectors per cluster */
|
||||||
|
BYTE pad1;
|
||||||
|
WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */
|
||||||
|
CLUST n_fatent; /* Number of FAT entries (= number of clusters + 2) */
|
||||||
|
DWORD fatbase; /* FAT start sector */
|
||||||
|
DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */
|
||||||
|
DWORD database; /* Data start sector */
|
||||||
|
DWORD fptr; /* File R/W pointer */
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
CLUST org_clust; /* File start cluster */
|
||||||
|
CLUST curr_clust; /* File current cluster */
|
||||||
|
DWORD dsect; /* File current data sector */
|
||||||
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Directory object structure */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WORD index; /* Current read/write index number */
|
||||||
|
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||||
|
CLUST sclust; /* Table start cluster (0:Static table) */
|
||||||
|
CLUST clust; /* Current cluster */
|
||||||
|
DWORD sect; /* Current sector */
|
||||||
|
} DIR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File status structure */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
WORD fdate; /* Last modified date */
|
||||||
|
WORD ftime; /* Last modified time */
|
||||||
|
BYTE fattrib; /* Attribute */
|
||||||
|
char fname[13]; /* File name */
|
||||||
|
} FILINFO;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File function return code (FRESULT) */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FR_OK = 0, /* 0 */
|
||||||
|
FR_DISK_ERR, /* 1 */
|
||||||
|
FR_NOT_READY, /* 2 */
|
||||||
|
FR_NO_FILE, /* 3 */
|
||||||
|
FR_NO_PATH, /* 4 */
|
||||||
|
FR_NOT_OPENED, /* 5 */
|
||||||
|
FR_NOT_ENABLED, /* 6 */
|
||||||
|
FR_NO_FILESYSTEM /* 7 */
|
||||||
|
} FRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Petit FatFs module application interface */
|
||||||
|
|
||||||
|
FRESULT pf_mount (FATFS*); /* Mount/Unmount a logical drive */
|
||||||
|
FRESULT pf_open (const char*); /* Open a file */
|
||||||
|
FRESULT pf_read (void*, WORD, WORD*); /* Read data from the open file */
|
||||||
|
FRESULT pf_write (const void*, WORD, WORD*); /* Write data to the open file */
|
||||||
|
FRESULT pf_lseek (DWORD); /* Move file pointer of the open file */
|
||||||
|
FRESULT pf_opendir (DIR*, const char*); /* Open a directory */
|
||||||
|
FRESULT pf_readdir (DIR*, FILINFO*); /* Read a directory item from the open directory */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
/* File status flag (FATFS.flag) */
|
||||||
|
|
||||||
|
#define FA_OPENED 0x01
|
||||||
|
#define FA_WPRT 0x02
|
||||||
|
#define FA__WIP 0x40
|
||||||
|
|
||||||
|
|
||||||
|
/* FAT sub type (FATFS.fs_type) */
|
||||||
|
|
||||||
|
#define FS_FAT12 1
|
||||||
|
#define FS_FAT16 2
|
||||||
|
#define FS_FAT32 3
|
||||||
|
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry */
|
||||||
|
|
||||||
|
#define AM_RDO 0x01 /* Read only */
|
||||||
|
#define AM_HID 0x02 /* Hidden */
|
||||||
|
#define AM_SYS 0x04 /* System */
|
||||||
|
#define AM_VOL 0x08 /* Volume label */
|
||||||
|
#define AM_LFN 0x0F /* LFN entry */
|
||||||
|
#define AM_DIR 0x10 /* Directory */
|
||||||
|
#define AM_ARC 0x20 /* Archive */
|
||||||
|
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------*/
|
||||||
|
/* Multi-byte word access macros */
|
||||||
|
|
||||||
|
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||||
|
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||||
|
#else /* Use byte-by-byte access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||||
|
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _FATFS */
|
32
arduino/bootldr/how to configure bootloader.txt
Executable file
32
arduino/bootldr/how to configure bootloader.txt
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
1. In the application project, modify the "memory settings" linker option. In the FLASH segment add:
|
||||||
|
.bootldrinfo=0xF7FC (for atmega with 128K Flash), or
|
||||||
|
.bootldrinfo=0x37FC (for atmega with 32K Flash)
|
||||||
|
It should be 8 bytes (4 words) before the start of the bootloader area.
|
||||||
|
|
||||||
|
2. Change the application version number as desired.
|
||||||
|
|
||||||
|
3. Rebuild the application to generate a new .hex file
|
||||||
|
|
||||||
|
4. In the bootloader project, modify the "memory settings" linker option. In the FLASH segment add:
|
||||||
|
.text=0xF800 (for atmega with 128K Flash), or
|
||||||
|
.text=0x3800 (for atmega with 32K Flash)
|
||||||
|
It should be the start of the bootloader area in words. These numbers assume a 4K bootloader.
|
||||||
|
|
||||||
|
5. Modify the "Symbols" compiler and assembler options. Change
|
||||||
|
.text=0x1F000 (for atmega with 128K Flash), or
|
||||||
|
.text=0x7000 (for atmega with 32K Flash)
|
||||||
|
It should be the start of the bootloader area in bytes. These numbers assume a 4K bootloader.
|
||||||
|
|
||||||
|
6. Rebuild the bootloader project to generate a new .hex file
|
||||||
|
|
||||||
|
7. Append the bootloader to the application .hex file. You can do this in a text editor, after
|
||||||
|
deleting the line :00000001FF at the end of the application section, or using srec_cat:
|
||||||
|
srec_cat application.hex -intel bootloader.hex -intel -o merged.hex -intel
|
||||||
|
|
||||||
|
8. Program the merged .hex file to the board, just like you would for any other .hex
|
||||||
|
|
||||||
|
9. Connect to the board with the ISP programmer. Set the BOOTSZ fuse to 2048W (for 4K bootloader)
|
||||||
|
and BOOTRST fuse to on/true.
|
||||||
|
|
||||||
|
10. To generate the .bin file used by the bootloader to flash new code updates, use
|
||||||
|
avr-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature application.elf application.bin
|
BIN
arduino/eagle/floppyemu 1.1.1/board-layout.png
Executable file
BIN
arduino/eagle/floppyemu 1.1.1/board-layout.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
BIN
arduino/eagle/floppyemu 1.1.1/board-schematic.png
Executable file
BIN
arduino/eagle/floppyemu 1.1.1/board-schematic.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
4669
arduino/eagle/floppyemu 1.1.1/floppyemu.brd
Executable file
4669
arduino/eagle/floppyemu 1.1.1/floppyemu.brd
Executable file
File diff suppressed because it is too large
Load Diff
7254
arduino/eagle/floppyemu 1.1.1/floppyemu.sch
Executable file
7254
arduino/eagle/floppyemu 1.1.1/floppyemu.sch
Executable file
File diff suppressed because it is too large
Load Diff
BIN
arduino/eagle/floppyemu 1.1.1/gerbers.zip
Executable file
BIN
arduino/eagle/floppyemu 1.1.1/gerbers.zip
Executable file
Binary file not shown.
33
arduino/eagle/floppyemu 1.1.1/parts-1.1.txt
Executable file
33
arduino/eagle/floppyemu 1.1.1/parts-1.1.txt
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
ICs:
|
||||||
|
XC9572XL, 44-pin TQFP package = http://search.digikey.com/us/en/products/XC9572XL-10VQG44C/122-1448-ND/966629?wt.z_cid=ref_octopart_dkc_buynow
|
||||||
|
ATMega1284P, 44-pin TQFP package = http://search.digikey.com/us/en/products/ATMEGA1284P-AU/ATMEGA1284P-AU-ND/1914519
|
||||||
|
74LVC244A level converter, 20-pin SSOP package = http://search.digikey.com/us/en/products/74LVC244ADB,112/568-1582-5-ND/763186
|
||||||
|
800mA 1117 3.3V regulator, SOT223 package = http://search.digikey.com/us/en/products/LD1117S33TR/497-1242-1-ND/586242
|
||||||
|
20 MHz 8pF SMD crystal, NX5032 package = http://search.digikey.com/us/en/products/NX5032GA-20.000000MHZ-LN-CD-1/644-1039-1-ND/1128911
|
||||||
|
|
||||||
|
Connectors:
|
||||||
|
DB-19 connector, male solder type = http://www.iec-usa.com/cgi-bin/iec/fullpic?G2FS4qvh;DB19MS;41
|
||||||
|
IDC20 connector = http://search.digikey.com/us/en/products/SBH11-PBPC-D10-ST-BK/S9172-ND/1990065
|
||||||
|
AVR ISP connector (2x3 IDC) = http://search.digikey.com/us/en/products/75869-131LF/609-2845-ND/1302569
|
||||||
|
8-pin male 0.1 inch header
|
||||||
|
2-pin male 0.1 inch header
|
||||||
|
8-pin female 0.1 inch header
|
||||||
|
2-pin female 0.1 inch header
|
||||||
|
|
||||||
|
Passives:
|
||||||
|
10x 0.1uF capacitors, 0805 package
|
||||||
|
1x 33uF tantalum cap, 0805 package
|
||||||
|
2x 18pF caps, 0805 package
|
||||||
|
3x 220 ohm resistors, 0805 package
|
||||||
|
1x 10K ohm resistor, 0805 package
|
||||||
|
|
||||||
|
Miscellaneous:
|
||||||
|
Nokia 5110 graphical LCD = https://www.sparkfun.com/products/10168
|
||||||
|
2x LEDs, 0805 package = http://search.digikey.com/us/en/products/APT2012SGC/754-1131-1-ND/1747848
|
||||||
|
4x B3FS tactile switch, SMD = http://search.digikey.com/scripts/dksearch/dksus.dll?pname&WT.z_cid=ref_octopart_dkc_buynow&site=us&lang=en&name=SW1141-ND
|
||||||
|
TE 2041021-4 SD card holder = http://search.digikey.com/us/en/products/2041021-4/A101492CT-ND/2571152
|
||||||
|
|
||||||
|
Tools:
|
||||||
|
AVRISP mkII AVR programmer (or equivalent) = http://www.digikey.com/product-detail/en/ATAVRISP2/ATAVRISP2-ND/898891?WT.mc_id=PLA_898891&gclid=CO_xwcjWnbQCFYp_QgodXX0AUQ
|
||||||
|
SD or SDHC card
|
||||||
|
|
BIN
arduino/firmware/femu.bin
Executable file
BIN
arduino/firmware/femu.bin
Executable file
Binary file not shown.
BIN
arduino/firmware/firmware.xvf
Executable file
BIN
arduino/firmware/firmware.xvf
Executable file
Binary file not shown.
1983
arduino/firmware/floppyemu.hex
Executable file
1983
arduino/firmware/floppyemu.hex
Executable file
File diff suppressed because it is too large
Load Diff
1123
arduino/firmware/merged.hex
Executable file
1123
arduino/firmware/merged.hex
Executable file
File diff suppressed because it is too large
Load Diff
24
arduino/firmware/readme.txt
Executable file
24
arduino/firmware/readme.txt
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
To update the Xilinx CPLD firmware:
|
||||||
|
|
||||||
|
1. Copy firmware.xvf to the root directory of your SD card, and insert it into Floppy Emu.
|
||||||
|
2. Hold down the PREV and NEXT buttons.
|
||||||
|
3. Press and release the RESET button.
|
||||||
|
4. Follow the on-screen prompts.
|
||||||
|
|
||||||
|
|
||||||
|
To update the microcontroller application software:
|
||||||
|
|
||||||
|
If you have the SD bootloader already installed:
|
||||||
|
1. Copy femu.bin to the root directory of your SD card, and insert it into Floppy Emu.
|
||||||
|
2. Hold down the PREV and SELECT buttons.
|
||||||
|
3. Press and release the RESET button.
|
||||||
|
4. Follow the on-screen prompts.
|
||||||
|
|
||||||
|
If you don't have the SD bootloader installed:
|
||||||
|
1. Use your AVR ISP programmer to flash floppyemu.hex to the microcontroller.
|
||||||
|
|
||||||
|
If you want to install the SD bootloader:
|
||||||
|
1. Use your AVR ISP programmer to flash merged.hex to the microcontroller.
|
||||||
|
2. Use the ISP programmer to set the BOOTRST fuse to 1 (on), and the BOOTSZ fuse to 2048W_F800. (Fuses should be Extended: 0xFF, High: 0xDA, Low: 0xBF)
|
||||||
|
|
||||||
|
|
212
arduino/floppyemu/Release/Makefile
Executable file
212
arduino/floppyemu/Release/Makefile
Executable file
|
@ -0,0 +1,212 @@
|
||||||
|
################################################################################
|
||||||
|
# Automatically-generated file. Do not edit!
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
SHELL := /bin/csh
|
||||||
|
RM := rm -rf
|
||||||
|
|
||||||
|
USER_OBJS :=
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
PROJ :=
|
||||||
|
|
||||||
|
O_SRCS :=
|
||||||
|
C_SRCS :=
|
||||||
|
S_SRCS :=
|
||||||
|
S_UPPER_SRCS :=
|
||||||
|
OBJ_SRCS :=
|
||||||
|
ASM_SRCS :=
|
||||||
|
PREPROCESSING_SRCS :=
|
||||||
|
OBJS :=
|
||||||
|
OBJS_AS_ARGS :=
|
||||||
|
C_DEPS :=
|
||||||
|
C_DEPS_AS_ARGS :=
|
||||||
|
EXECUTABLES :=
|
||||||
|
OUTPUT_FILE_PATH :=
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS :=
|
||||||
|
AVR_APP_PATH :=$$$AVR_APP_PATH$$$
|
||||||
|
QUOTE := "
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
OUTPUT_FILE_DEP:=
|
||||||
|
|
||||||
|
# Every subdirectory with source files must be described here
|
||||||
|
SUBDIRS :=
|
||||||
|
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
C_SRCS += \
|
||||||
|
../cardtest.cpp \
|
||||||
|
../diskmenu.cpp \
|
||||||
|
../floppyemu.cpp \
|
||||||
|
../millitimer.cpp \
|
||||||
|
../noklcd.cpp \
|
||||||
|
../SdFat/Sd2Card.cpp \
|
||||||
|
../SdFat/SdBaseFile.cpp \
|
||||||
|
../SdFat/SdFat.cpp \
|
||||||
|
../SdFat/SdVolume.cpp \
|
||||||
|
../xsvf/lenval.cpp \
|
||||||
|
../xsvf/micro.cpp \
|
||||||
|
../xsvf/ports.cpp
|
||||||
|
|
||||||
|
|
||||||
|
PREPROCESSING_SRCS +=
|
||||||
|
|
||||||
|
|
||||||
|
ASM_SRCS +=
|
||||||
|
|
||||||
|
|
||||||
|
OBJS += \
|
||||||
|
cardtest.o \
|
||||||
|
diskmenu.o \
|
||||||
|
floppyemu.o \
|
||||||
|
millitimer.o \
|
||||||
|
noklcd.o \
|
||||||
|
Sd2Card.o \
|
||||||
|
SdBaseFile.o \
|
||||||
|
SdFat.o \
|
||||||
|
SdVolume.o \
|
||||||
|
lenval.o \
|
||||||
|
micro.o \
|
||||||
|
ports.o
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_AS_ARGS += \
|
||||||
|
cardtest.o \
|
||||||
|
diskmenu.o \
|
||||||
|
floppyemu.o \
|
||||||
|
millitimer.o \
|
||||||
|
noklcd.o \
|
||||||
|
Sd2Card.o \
|
||||||
|
SdBaseFile.o \
|
||||||
|
SdFat.o \
|
||||||
|
SdVolume.o \
|
||||||
|
lenval.o \
|
||||||
|
micro.o \
|
||||||
|
ports.o
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS += \
|
||||||
|
cardtest.d \
|
||||||
|
diskmenu.d \
|
||||||
|
floppyemu.d \
|
||||||
|
millitimer.d \
|
||||||
|
noklcd.d \
|
||||||
|
Sd2Card.d \
|
||||||
|
SdBaseFile.d \
|
||||||
|
SdFat.d \
|
||||||
|
SdVolume.d \
|
||||||
|
lenval.d \
|
||||||
|
micro.d \
|
||||||
|
ports.d
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS_AS_ARGS += \
|
||||||
|
cardtest.d \
|
||||||
|
diskmenu.d \
|
||||||
|
floppyemu.d \
|
||||||
|
millitimer.d \
|
||||||
|
noklcd.d \
|
||||||
|
Sd2Card.d \
|
||||||
|
SdBaseFile.d \
|
||||||
|
SdFat.d \
|
||||||
|
SdVolume.d \
|
||||||
|
lenval.d \
|
||||||
|
micro.d \
|
||||||
|
ports.d
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH +=floppyemu.elf
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS +=floppyemu.elf
|
||||||
|
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
|
||||||
|
OUTPUT_FILE_DEP:= ./makedep.mk
|
||||||
|
|
||||||
|
# AVR32/GNU C Compiler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
./%.o: .././%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
./%.o: ../SdFat/%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
./%.o: ../xsvf/%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Preprocessing Assembler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Assembler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
ifneq ($(strip $(C_DEPS)),)
|
||||||
|
-include $(C_DEPS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
|
||||||
|
# All Target
|
||||||
|
all: $(OUTPUT_FILE_PATH) $(ADDITIONAL_DEPENDENCIES)
|
||||||
|
|
||||||
|
$(OUTPUT_FILE_PATH): $(OBJS) $(USER_OBJS) $(OUTPUT_FILE_DEP)
|
||||||
|
@echo Building target: $@
|
||||||
|
@echo Invoking: AVR8/GNU C++ Linker
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="floppyemu.map" -Wl,-lm -Wl,--gc-sections -mrelax -Wl,-section-start=.bootldrinfo=0x1eff8 -mmcu=atmega1284p
|
||||||
|
@echo Finished building target: $@
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "floppyemu.hex"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O binary -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "femu.bin"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "floppyemu.elf" "floppyemu.eep" || exit 0
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objdump.exe" -h -S "floppyemu.elf" > "floppyemu.lss"
|
||||||
|
srec_cat "floppyemu.hex" -intel "..\bootldr\bootldr\Release\bootldr.hex" -intel -o "merged.hex" -intel
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-size.exe" -C --mcu=atmega1284p "floppyemu.elf"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Other Targets
|
||||||
|
clean:
|
||||||
|
-$(RM) $(OBJS_AS_ARGS)$(C_DEPS_AS_ARGS) $(EXECUTABLES)
|
||||||
|
rm -rf "floppyemu.hex" "floppyemu.lss" "floppyemu.eep" "floppyemu.map"
|
||||||
|
|
212
arduino/floppyemu/Release/Makefile~
Executable file
212
arduino/floppyemu/Release/Makefile~
Executable file
|
@ -0,0 +1,212 @@
|
||||||
|
################################################################################
|
||||||
|
# Automatically-generated file. Do not edit!
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
SHELL := cmd.exe
|
||||||
|
RM := rm -rf
|
||||||
|
|
||||||
|
USER_OBJS :=
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
PROJ :=
|
||||||
|
|
||||||
|
O_SRCS :=
|
||||||
|
C_SRCS :=
|
||||||
|
S_SRCS :=
|
||||||
|
S_UPPER_SRCS :=
|
||||||
|
OBJ_SRCS :=
|
||||||
|
ASM_SRCS :=
|
||||||
|
PREPROCESSING_SRCS :=
|
||||||
|
OBJS :=
|
||||||
|
OBJS_AS_ARGS :=
|
||||||
|
C_DEPS :=
|
||||||
|
C_DEPS_AS_ARGS :=
|
||||||
|
EXECUTABLES :=
|
||||||
|
OUTPUT_FILE_PATH :=
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS :=
|
||||||
|
AVR_APP_PATH :=$$$AVR_APP_PATH$$$
|
||||||
|
QUOTE := "
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
OUTPUT_FILE_DEP:=
|
||||||
|
|
||||||
|
# Every subdirectory with source files must be described here
|
||||||
|
SUBDIRS :=
|
||||||
|
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
C_SRCS += \
|
||||||
|
../cardtest.cpp \
|
||||||
|
../diskmenu.cpp \
|
||||||
|
../floppyemu.cpp \
|
||||||
|
../millitimer.cpp \
|
||||||
|
../noklcd.cpp \
|
||||||
|
../SdFat/Sd2Card.cpp \
|
||||||
|
../SdFat/SdBaseFile.cpp \
|
||||||
|
../SdFat/SdFat.cpp \
|
||||||
|
../SdFat/SdVolume.cpp \
|
||||||
|
../xsvf/lenval.cpp \
|
||||||
|
../xsvf/micro.cpp \
|
||||||
|
../xsvf/ports.cpp
|
||||||
|
|
||||||
|
|
||||||
|
PREPROCESSING_SRCS +=
|
||||||
|
|
||||||
|
|
||||||
|
ASM_SRCS +=
|
||||||
|
|
||||||
|
|
||||||
|
OBJS += \
|
||||||
|
cardtest.o \
|
||||||
|
diskmenu.o \
|
||||||
|
floppyemu.o \
|
||||||
|
millitimer.o \
|
||||||
|
noklcd.o \
|
||||||
|
Sd2Card.o \
|
||||||
|
SdBaseFile.o \
|
||||||
|
SdFat.o \
|
||||||
|
SdVolume.o \
|
||||||
|
lenval.o \
|
||||||
|
micro.o \
|
||||||
|
ports.o
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_AS_ARGS += \
|
||||||
|
cardtest.o \
|
||||||
|
diskmenu.o \
|
||||||
|
floppyemu.o \
|
||||||
|
millitimer.o \
|
||||||
|
noklcd.o \
|
||||||
|
Sd2Card.o \
|
||||||
|
SdBaseFile.o \
|
||||||
|
SdFat.o \
|
||||||
|
SdVolume.o \
|
||||||
|
lenval.o \
|
||||||
|
micro.o \
|
||||||
|
ports.o
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS += \
|
||||||
|
cardtest.d \
|
||||||
|
diskmenu.d \
|
||||||
|
floppyemu.d \
|
||||||
|
millitimer.d \
|
||||||
|
noklcd.d \
|
||||||
|
Sd2Card.d \
|
||||||
|
SdBaseFile.d \
|
||||||
|
SdFat.d \
|
||||||
|
SdVolume.d \
|
||||||
|
lenval.d \
|
||||||
|
micro.d \
|
||||||
|
ports.d
|
||||||
|
|
||||||
|
|
||||||
|
C_DEPS_AS_ARGS += \
|
||||||
|
cardtest.d \
|
||||||
|
diskmenu.d \
|
||||||
|
floppyemu.d \
|
||||||
|
millitimer.d \
|
||||||
|
noklcd.d \
|
||||||
|
Sd2Card.d \
|
||||||
|
SdBaseFile.d \
|
||||||
|
SdFat.d \
|
||||||
|
SdVolume.d \
|
||||||
|
lenval.d \
|
||||||
|
micro.d \
|
||||||
|
ports.d
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH +=floppyemu.elf
|
||||||
|
|
||||||
|
OUTPUT_FILE_PATH_AS_ARGS +=floppyemu.elf
|
||||||
|
|
||||||
|
ADDITIONAL_DEPENDENCIES:=
|
||||||
|
|
||||||
|
OUTPUT_FILE_DEP:= ./makedep.mk
|
||||||
|
|
||||||
|
# AVR32/GNU C Compiler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
./%.o: .././%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
./%.o: ../SdFat/%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
./%.o: ../xsvf/%.cpp
|
||||||
|
@echo Building file: $<
|
||||||
|
@echo Invoking: AVR8/GNU C++ Compiler
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<"
|
||||||
|
@echo Finished building: $<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Preprocessing Assembler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# AVR32/GNU Assembler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
ifneq ($(strip $(C_DEPS)),)
|
||||||
|
-include $(C_DEPS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Add inputs and outputs from these tool invocations to the build variables
|
||||||
|
|
||||||
|
# All Target
|
||||||
|
all: $(OUTPUT_FILE_PATH) $(ADDITIONAL_DEPENDENCIES)
|
||||||
|
|
||||||
|
$(OUTPUT_FILE_PATH): $(OBJS) $(USER_OBJS) $(OUTPUT_FILE_DEP)
|
||||||
|
@echo Building target: $@
|
||||||
|
@echo Invoking: AVR8/GNU C++ Linker
|
||||||
|
$(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="floppyemu.map" -Wl,-lm -Wl,--gc-sections -mrelax -Wl,-section-start=.bootldrinfo=0x1eff8 -mmcu=atmega1284p
|
||||||
|
@echo Finished building target: $@
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "floppyemu.hex"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O binary -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "femu.bin"
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "floppyemu.elf" "floppyemu.eep" || exit 0
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objdump.exe" -h -S "floppyemu.elf" > "floppyemu.lss"
|
||||||
|
srec_cat "floppyemu.hex" -intel "..\bootldr\bootldr\Release\bootldr.hex" -intel -o "merged.hex" -intel
|
||||||
|
"C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-size.exe" -C --mcu=atmega1284p "floppyemu.elf"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Other Targets
|
||||||
|
clean:
|
||||||
|
-$(RM) $(OBJS_AS_ARGS)$(C_DEPS_AS_ARGS) $(EXECUTABLES)
|
||||||
|
rm -rf "floppyemu.hex" "floppyemu.lss" "floppyemu.eep" "floppyemu.map"
|
||||||
|
|
BIN
arduino/floppyemu/Release/femu.bin
Executable file
BIN
arduino/floppyemu/Release/femu.bin
Executable file
Binary file not shown.
1983
arduino/floppyemu/Release/floppyemu.hex
Executable file
1983
arduino/floppyemu/Release/floppyemu.hex
Executable file
File diff suppressed because it is too large
Load Diff
26
arduino/floppyemu/Release/makedep.mk
Executable file
26
arduino/floppyemu/Release/makedep.mk
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
################################################################################
|
||||||
|
# Automatically-generated file. Do not edit or delete the file
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
diskmenu.cpp
|
||||||
|
|
||||||
|
floppyemu.cpp
|
||||||
|
|
||||||
|
millitimer.cpp
|
||||||
|
|
||||||
|
noklcd.cpp
|
||||||
|
|
||||||
|
SdFat\Sd2Card.cpp
|
||||||
|
|
||||||
|
SdFat\SdBaseFile.cpp
|
||||||
|
|
||||||
|
SdFat\SdFat.cpp
|
||||||
|
|
||||||
|
SdFat\SdVolume.cpp
|
||||||
|
|
||||||
|
xsvf\lenval.cpp
|
||||||
|
|
||||||
|
xsvf\micro.cpp
|
||||||
|
|
||||||
|
xsvf\ports.cpp
|
||||||
|
|
1123
arduino/floppyemu/Release/merged.hex
Executable file
1123
arduino/floppyemu/Release/merged.hex
Executable file
File diff suppressed because it is too large
Load Diff
665
arduino/floppyemu/SdFat/Sd2Card.cpp
Executable file
665
arduino/floppyemu/SdFat/Sd2Card.cpp
Executable file
|
@ -0,0 +1,665 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino Sd2Card Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino Sd2Card Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SDCARD_CS_PORT PORTB
|
||||||
|
#define SDCARD_CS_DDR DDRB
|
||||||
|
#define SDCARD_CS_PIN 4
|
||||||
|
|
||||||
|
#define SDCARD_CLK_PORT B
|
||||||
|
#define SDCARD_CLK_DDR DDRB
|
||||||
|
#define SDCARD_CLK_PIN 7
|
||||||
|
|
||||||
|
#define SDCARD_MOSI_PORT B
|
||||||
|
#define SDCARD_MOSI_DDR DDRB
|
||||||
|
#define SDCARD_MOSI_PIN 5
|
||||||
|
|
||||||
|
#define SDCARD_MISO_PORT B
|
||||||
|
#define SDCARD_MISO_DDR DDRB
|
||||||
|
#define SDCARD_MISO_PIN 6
|
||||||
|
|
||||||
|
|
||||||
|
#include <Sd2Card.h>
|
||||||
|
#include "../millitimer.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
// functions for hardware SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// make sure SPCR rate is in expected bits
|
||||||
|
#if (SPR0 != 0 || SPR1 != 1)
|
||||||
|
#error unexpected SPCR bits
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* Initialize hardware SPI
|
||||||
|
* Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
|
||||||
|
*/
|
||||||
|
static void spiInit(uint8_t spiRate) {
|
||||||
|
// See avr processor documentation
|
||||||
|
SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1);
|
||||||
|
SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI receive a byte */
|
||||||
|
static uint8_t spiRec() {
|
||||||
|
SPDR = 0XFF;
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
return SPDR;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI read data - only one call so force inline */
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void spiRead(uint8_t* buf, uint16_t nbyte) {
|
||||||
|
if (nbyte-- == 0) return;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
for (uint16_t i = 0; i < nbyte; i++) {
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
buf[i] = SPDR;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
}
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
buf[nbyte] = SPDR;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI send a byte */
|
||||||
|
static void spiSend(uint8_t b) {
|
||||||
|
SPDR = b;
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI send block - only one call so force inline */
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void spiSendBlock(uint8_t token, const uint8_t* buf) {
|
||||||
|
SPDR = token;
|
||||||
|
for (uint16_t i = 0; i < 512; i += 2) {
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
SPDR = buf[i];
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
SPDR = buf[i + 1];
|
||||||
|
}
|
||||||
|
while (!(SPSR & (1 << SPIF)));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#else // SOFTWARE_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** nop to tune soft SPI timing */
|
||||||
|
#define nop asm volatile ("nop\n\t")
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI receive byte */
|
||||||
|
static uint8_t spiRec() {
|
||||||
|
uint8_t data = 0;
|
||||||
|
// no interrupts during byte receive - about 8 us
|
||||||
|
cli();
|
||||||
|
// output pin high - like sending 0XFF
|
||||||
|
fastDigitalWrite(SPI_MOSI_PIN, HIGH);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||||
|
|
||||||
|
// adjust so SCK is nice
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
|
||||||
|
data <<= 1;
|
||||||
|
|
||||||
|
if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
}
|
||||||
|
// enable interrupts
|
||||||
|
sei();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI read data */
|
||||||
|
static void spiRead(uint8_t* buf, uint16_t nbyte) {
|
||||||
|
for (uint16_t i = 0; i < nbyte; i++) {
|
||||||
|
buf[i] = spiRec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI send byte */
|
||||||
|
static void spiSend(uint8_t data) {
|
||||||
|
// no interrupts during byte send - about 8 us
|
||||||
|
cli();
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
|
||||||
|
|
||||||
|
data <<= 1;
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||||
|
}
|
||||||
|
// hold SCK high for a few ns
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
// enable interrupts
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI send block */
|
||||||
|
void spiSendBlock(uint8_t token, const uint8_t* buf) {
|
||||||
|
spiSend(token);
|
||||||
|
for (uint16_t i = 0; i < 512; i++) {
|
||||||
|
spiSend(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send command and return error code. Return zero for OK
|
||||||
|
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||||
|
// select card
|
||||||
|
chipSelectLow();
|
||||||
|
|
||||||
|
// wait up to 300 ms if busy
|
||||||
|
waitNotBusy(300);
|
||||||
|
|
||||||
|
// send command
|
||||||
|
spiSend(cmd | 0x40);
|
||||||
|
|
||||||
|
// send argument
|
||||||
|
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
||||||
|
|
||||||
|
// send CRC
|
||||||
|
uint8_t crc = 0XFF;
|
||||||
|
if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
|
||||||
|
if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
|
||||||
|
spiSend(crc);
|
||||||
|
|
||||||
|
// skip stuff byte for stop read
|
||||||
|
if (cmd == CMD12) spiRec();
|
||||||
|
|
||||||
|
// wait for response
|
||||||
|
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Determine the size of an SD flash memory card.
|
||||||
|
*
|
||||||
|
* \return The number of 512 byte data blocks in the card
|
||||||
|
* or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
uint32_t Sd2Card::cardSize() {
|
||||||
|
csd_t csd;
|
||||||
|
if (!readCSD(&csd)) return 0;
|
||||||
|
if (csd.v1.csd_ver == 0) {
|
||||||
|
uint8_t read_bl_len = csd.v1.read_bl_len;
|
||||||
|
uint16_t c_size = (csd.v1.c_size_high << 10)
|
||||||
|
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
|
||||||
|
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
|
||||||
|
| csd.v1.c_size_mult_low;
|
||||||
|
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
||||||
|
} else if (csd.v2.csd_ver == 1) {
|
||||||
|
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
|
||||||
|
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
|
||||||
|
return (c_size + 1) << 10;
|
||||||
|
} else {
|
||||||
|
error(SD_CARD_ERROR_BAD_CSD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void Sd2Card::chipSelectHigh() {
|
||||||
|
SDCARD_CS_PORT |= (1<<SDCARD_CS_PIN);
|
||||||
|
//digitalWrite(chipSelectPin_, HIGH);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void Sd2Card::chipSelectLow() {
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
spiInit(spiRate_);
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
SDCARD_CS_PORT &= ~(1<<SDCARD_CS_PIN);
|
||||||
|
//digitalWrite(chipSelectPin_, LOW);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Erase a range of blocks.
|
||||||
|
*
|
||||||
|
* \param[in] firstBlock The address of the first block in the range.
|
||||||
|
* \param[in] lastBlock The address of the last block in the range.
|
||||||
|
*
|
||||||
|
* \note This function requests the SD card to do a flash erase for a
|
||||||
|
* range of blocks. The data on the card after an erase operation is
|
||||||
|
* either 0 or 1, depends on the card vendor. The card must support
|
||||||
|
* single block erase.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||||
|
csd_t csd;
|
||||||
|
if (!readCSD(&csd)) goto fail;
|
||||||
|
// check for single block erase
|
||||||
|
if (!csd.v1.erase_blk_en) {
|
||||||
|
// erase size mask
|
||||||
|
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
|
||||||
|
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
|
||||||
|
// error card can't erase specified area
|
||||||
|
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type_ != SD_CARD_TYPE_SDHC) {
|
||||||
|
firstBlock <<= 9;
|
||||||
|
lastBlock <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD32, firstBlock)
|
||||||
|
|| cardCommand(CMD33, lastBlock)
|
||||||
|
|| cardCommand(CMD38, 0)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Determine if card supports single block erase.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned if single block erase is supported.
|
||||||
|
* The value zero, false, is returned if single block erase is not supported.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::eraseSingleBlockEnable() {
|
||||||
|
csd_t csd;
|
||||||
|
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Initialize an SD flash memory card.
|
||||||
|
*
|
||||||
|
* \param[in] sckRateID SPI clock rate selector. See setSckRate().
|
||||||
|
* \param[in] chipSelectPin SD chip select pin number.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure. The reason for failure
|
||||||
|
* can be determined by calling errorCode() and errorData().
|
||||||
|
*/
|
||||||
|
bool Sd2Card::init(uint8_t sckRateID) {
|
||||||
|
errorCode_ = type_ = 0;
|
||||||
|
// 16-bit init start time allows over a minute
|
||||||
|
uint16_t t0 = (uint16_t)millis();
|
||||||
|
uint32_t arg;
|
||||||
|
|
||||||
|
// set pin modes
|
||||||
|
SDCARD_CS_DDR |= (1<<SDCARD_CS_PIN);
|
||||||
|
//pinMode(chipSelectPin_, OUTPUT);
|
||||||
|
chipSelectHigh();
|
||||||
|
SDCARD_MISO_DDR &= ~(1<<SDCARD_MISO_PIN);
|
||||||
|
//pinMode(SPI_MISO_PIN, INPUT);
|
||||||
|
SDCARD_MOSI_DDR |= (1<<SDCARD_MOSI_PIN);
|
||||||
|
//pinMode(SPI_MOSI_PIN, OUTPUT);
|
||||||
|
SDCARD_CLK_DDR |= (1<<SDCARD_CLK_PIN);
|
||||||
|
//pinMode(SPI_SCK_PIN, OUTPUT);
|
||||||
|
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
// SS must be in output mode even it is not chip select
|
||||||
|
SDCARD_CS_DDR |= (1<<SDCARD_CS_PIN);
|
||||||
|
//pinMode(SS_PIN, OUTPUT);
|
||||||
|
// set SS high - may be chip select for another SPI device
|
||||||
|
#if SET_SPI_SS_HIGH
|
||||||
|
SDCARD_CS_PORT |= (1<<SDCARD_CS_PIN);
|
||||||
|
//digitalWrite(SS_PIN, HIGH);
|
||||||
|
#endif // SET_SPI_SS_HIGH
|
||||||
|
// set SCK rate for initialization commands
|
||||||
|
spiRate_ = SPI_SD_INIT_RATE;
|
||||||
|
spiInit(spiRate_);
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
|
||||||
|
// must supply min of 74 clock cycles with CS high.
|
||||||
|
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
|
||||||
|
|
||||||
|
// command to go idle in SPI mode
|
||||||
|
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
|
||||||
|
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_CMD0);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check SD version
|
||||||
|
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
||||||
|
type(SD_CARD_TYPE_SD1);
|
||||||
|
} else {
|
||||||
|
// only need last byte of r7 response
|
||||||
|
for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
|
||||||
|
if (status_ != 0XAA) {
|
||||||
|
error(SD_CARD_ERROR_CMD8);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
type(SD_CARD_TYPE_SD2);
|
||||||
|
}
|
||||||
|
// initialize card and send host supports SDHC if SD2
|
||||||
|
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
||||||
|
|
||||||
|
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
||||||
|
// check for timeout
|
||||||
|
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_ACMD41);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if SD2 read OCR register to check for SDHC card
|
||||||
|
if (type() == SD_CARD_TYPE_SD2) {
|
||||||
|
if (cardCommand(CMD58, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD58);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
|
||||||
|
// discard rest of ocr - contains allowed voltage range
|
||||||
|
for (uint8_t i = 0; i < 3; i++) spiRec();
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
return setSckRate(sckRateID);
|
||||||
|
#else // SOFTWARE_SPI
|
||||||
|
return true;
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||||
|
if (cardCommand(CMD17, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD17);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return readData(dst, 512);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Read one data block in a multiple block read sequence
|
||||||
|
*
|
||||||
|
* \param[in] dst Pointer to the location for the data to be read.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::readData(uint8_t *dst) {
|
||||||
|
chipSelectLow();
|
||||||
|
return readData(dst, 512);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
||||||
|
// wait for start block token
|
||||||
|
uint16_t t0 = millis();
|
||||||
|
while ((status_ = spiRec()) == 0XFF) {
|
||||||
|
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_READ_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status_ != DATA_START_BLOCK) {
|
||||||
|
error(SD_CARD_ERROR_READ);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// transfer data
|
||||||
|
spiRead(dst, count);
|
||||||
|
|
||||||
|
// discard CRC
|
||||||
|
spiRec();
|
||||||
|
spiRec();
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** read CID or CSR register */
|
||||||
|
bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
||||||
|
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||||
|
if (cardCommand(cmd, 0)) {
|
||||||
|
error(SD_CARD_ERROR_READ_REG);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return readData(dst, 16);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Start a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Address of first block in sequence.
|
||||||
|
*
|
||||||
|
* \note This function is used with readData() and readStop() for optimized
|
||||||
|
* multiple block reads. SPI chipSelect must be low for the entire sequence.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::readStart(uint32_t blockNumber) {
|
||||||
|
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||||
|
if (cardCommand(CMD18, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD18);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** End a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::readStop() {
|
||||||
|
chipSelectLow();
|
||||||
|
if (cardCommand(CMD12, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD12);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set the SPI clock rate.
|
||||||
|
*
|
||||||
|
* \param[in] sckRateID A value in the range [0, 6].
|
||||||
|
*
|
||||||
|
* The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
|
||||||
|
* SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
|
||||||
|
* for \a scsRateID = 6.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and the value zero,
|
||||||
|
* false, is returned for an invalid value of \a sckRateID.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::setSckRate(uint8_t sckRateID) {
|
||||||
|
if (sckRateID > 6) {
|
||||||
|
error(SD_CARD_ERROR_SCK_RATE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spiRate_ = sckRateID;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// wait for card to go not busy
|
||||||
|
bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
|
||||||
|
uint16_t t0 = millis();
|
||||||
|
while (spiRec() != 0XFF) {
|
||||||
|
if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||||
|
if (cardCommand(CMD24, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD24);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!writeData(DATA_START_BLOCK, src)) goto fail;
|
||||||
|
|
||||||
|
// wait for flash programming to complete
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// response is r2 so get and check two bytes for nonzero
|
||||||
|
if (cardCommand(CMD13, 0) || spiRec()) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Write one data block in a multiple block write sequence
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::writeData(const uint8_t* src) {
|
||||||
|
chipSelectLow();
|
||||||
|
// wait for previous write to finish
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
||||||
|
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send one block of data for write block or write multiple blocks
|
||||||
|
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
||||||
|
spiSendBlock(token, src);
|
||||||
|
|
||||||
|
spiSend(0xff); // dummy crc
|
||||||
|
spiSend(0xff); // dummy crc
|
||||||
|
|
||||||
|
status_ = spiRec();
|
||||||
|
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||||
|
error(SD_CARD_ERROR_WRITE);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Start a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Address of first block in sequence.
|
||||||
|
* \param[in] eraseCount The number of blocks to be pre-erased.
|
||||||
|
*
|
||||||
|
* \note This function is used with writeData() and writeStop()
|
||||||
|
* for optimized multiple block writes.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||||
|
// send pre-erase count
|
||||||
|
if (cardAcmd(ACMD23, eraseCount)) {
|
||||||
|
error(SD_CARD_ERROR_ACMD23);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||||
|
if (cardCommand(CMD25, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD25);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** End a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool Sd2Card::writeStop() {
|
||||||
|
chipSelectLow();
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
||||||
|
spiSend(STOP_TRAN_TOKEN);
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
error(SD_CARD_ERROR_STOP_TRAN);
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
207
arduino/floppyemu/SdFat/Sd2Card.h
Executable file
207
arduino/floppyemu/SdFat/Sd2Card.h
Executable file
|
@ -0,0 +1,207 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino Sd2Card Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino Sd2Card Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef Sd2Card_h
|
||||||
|
#define Sd2Card_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief Sd2Card class for V2 SD/SDHC cards
|
||||||
|
*/
|
||||||
|
#include <SdFatConfig.h>
|
||||||
|
//#include <Sd2PinMap.h>
|
||||||
|
#include <SdInfo.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
|
||||||
|
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_FULL_SPEED = 0;
|
||||||
|
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_HALF_SPEED = 1;
|
||||||
|
/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_QUARTER_SPEED = 2;
|
||||||
|
/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_EIGHTH_SPEED = 3;
|
||||||
|
/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_SIXTEENTH_SPEED = 4;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** init timeout ms */
|
||||||
|
uint16_t const SD_INIT_TIMEOUT = 2000;
|
||||||
|
/** erase timeout ms */
|
||||||
|
uint16_t const SD_ERASE_TIMEOUT = 10000;
|
||||||
|
/** read timeout ms */
|
||||||
|
uint16_t const SD_READ_TIMEOUT = 300;
|
||||||
|
/** write time out ms */
|
||||||
|
uint16_t const SD_WRITE_TIMEOUT = 600;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card errors
|
||||||
|
/** timeout error for command CMD0 (initialize card in SPI mode) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
|
||||||
|
/** CMD8 was not accepted - not a valid SD card*/
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
|
||||||
|
/** card returned an error response for CMD12 (write stop) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
|
||||||
|
/** card returned an error response for CMD17 (read block) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
|
||||||
|
/** card returned an error response for CMD18 (read multiple block) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
|
||||||
|
/** card returned an error response for CMD24 (write block) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
|
||||||
|
/** WRITE_MULTIPLE_BLOCKS command failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
|
||||||
|
/** card returned an error response for CMD58 (read OCR) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
|
||||||
|
/** SET_WR_BLK_ERASE_COUNT failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
|
||||||
|
/** ACMD41 initialization process timeout */
|
||||||
|
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
|
||||||
|
/** card returned a bad CSR version field */
|
||||||
|
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
|
||||||
|
/** erase block group command failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
|
||||||
|
/** card not capable of single block erase */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
|
||||||
|
/** Erase sequence timed out */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
|
||||||
|
/** card returned an error token instead of read data */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ = 0XF;
|
||||||
|
/** read CID or CSD failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
|
||||||
|
/** timeout while waiting for start of read data */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
|
||||||
|
/** card did not accept STOP_TRAN_TOKEN */
|
||||||
|
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
|
||||||
|
/** card returned an error token as a response to a write operation */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
|
||||||
|
/** attempt to write protected block zero */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
|
||||||
|
/** card did not go ready for a multiple block write */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
|
||||||
|
/** card returned an error to a CMD13 status check after a write */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
|
||||||
|
/** timeout occurred during write programming */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
|
||||||
|
/** incorrect rate selected */
|
||||||
|
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
|
||||||
|
/** init() not called */
|
||||||
|
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// card types
|
||||||
|
/** Standard capacity V1 SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SD1 = 1;
|
||||||
|
/** Standard capacity V2 SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SD2 = 2;
|
||||||
|
/** High Capacity SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SDHC = 3;
|
||||||
|
/**
|
||||||
|
* define SOFTWARE_SPI to use bit-bang SPI
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
|
||||||
|
#define SOFTWARE_SPI
|
||||||
|
#elif USE_SOFTWARE_SPI
|
||||||
|
#define SOFTWARE_SPI
|
||||||
|
#endif // MEGA_SOFT_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Sd2Card
|
||||||
|
* \brief Raw access to SD and SDHC flash memory cards.
|
||||||
|
*/
|
||||||
|
class Sd2Card {
|
||||||
|
public:
|
||||||
|
/** Construct an instance of Sd2Card. */
|
||||||
|
Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
|
||||||
|
uint32_t cardSize();
|
||||||
|
bool erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||||
|
bool eraseSingleBlockEnable();
|
||||||
|
/**
|
||||||
|
* Set SD error code.
|
||||||
|
* \param[in] code value for error code.
|
||||||
|
*/
|
||||||
|
void error(uint8_t code) {errorCode_ = code;}
|
||||||
|
/**
|
||||||
|
* \return error code for last error. See Sd2Card.h for a list of error codes.
|
||||||
|
*/
|
||||||
|
int errorCode() const {return errorCode_;}
|
||||||
|
/** \return error data for last error. */
|
||||||
|
int errorData() const {return status_;}
|
||||||
|
/**
|
||||||
|
* Initialize an SD flash memory card with default clock rate and chip
|
||||||
|
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool init(uint8_t sckRateID = SPI_FULL_SPEED);
|
||||||
|
bool readBlock(uint32_t block, uint8_t* dst);
|
||||||
|
/**
|
||||||
|
* Read a card's CID register. The CID contains card identification
|
||||||
|
* information such as Manufacturer ID, Product name, Product serial
|
||||||
|
* number and Manufacturing date.
|
||||||
|
*
|
||||||
|
* \param[out] cid pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCID(cid_t* cid) {
|
||||||
|
return readRegister(CMD10, cid);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||||
|
* provides information regarding access to the card's contents.
|
||||||
|
*
|
||||||
|
* \param[out] csd pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCSD(csd_t* csd) {
|
||||||
|
return readRegister(CMD9, csd);
|
||||||
|
}
|
||||||
|
bool readData(uint8_t *dst);
|
||||||
|
bool readStart(uint32_t blockNumber);
|
||||||
|
bool readStop();
|
||||||
|
bool setSckRate(uint8_t sckRateID);
|
||||||
|
/** Return the card type: SD V1, SD V2 or SDHC
|
||||||
|
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
|
||||||
|
*/
|
||||||
|
int type() const {return type_;}
|
||||||
|
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
|
||||||
|
bool writeData(const uint8_t* src);
|
||||||
|
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||||
|
bool writeStop();
|
||||||
|
private:
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint8_t errorCode_;
|
||||||
|
uint8_t spiRate_;
|
||||||
|
uint8_t status_;
|
||||||
|
uint8_t type_;
|
||||||
|
// private functions
|
||||||
|
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||||
|
cardCommand(CMD55, 0);
|
||||||
|
return cardCommand(cmd, arg);
|
||||||
|
}
|
||||||
|
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||||
|
|
||||||
|
bool readData(uint8_t* dst, uint16_t count);
|
||||||
|
bool readRegister(uint8_t cmd, void* buf);
|
||||||
|
void chipSelectHigh();
|
||||||
|
void chipSelectLow();
|
||||||
|
void type(uint8_t value) {type_ = value;}
|
||||||
|
bool waitNotBusy(uint16_t timeoutMillis);
|
||||||
|
bool writeData(uint8_t token, const uint8_t* src);
|
||||||
|
};
|
||||||
|
#endif // Sd2Card_h
|
1824
arduino/floppyemu/SdFat/SdBaseFile.cpp
Executable file
1824
arduino/floppyemu/SdFat/SdBaseFile.cpp
Executable file
File diff suppressed because it is too large
Load Diff
492
arduino/floppyemu/SdFat/SdBaseFile.h
Executable file
492
arduino/floppyemu/SdFat/SdBaseFile.h
Executable file
|
@ -0,0 +1,492 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdBaseFile_h
|
||||||
|
#define SdBaseFile_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SdBaseFile class
|
||||||
|
*/
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <SdFatConfig.h>
|
||||||
|
#include <SdVolume.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct fpos_t
|
||||||
|
* \brief internal type for istream
|
||||||
|
* do not use in user apps
|
||||||
|
*/
|
||||||
|
struct fpos_t {
|
||||||
|
/** stream position */
|
||||||
|
uint32_t position;
|
||||||
|
/** cluster for position */
|
||||||
|
uint32_t cluster;
|
||||||
|
fpos_t() : position(0), cluster(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// use the gnu style oflag in open()
|
||||||
|
/** open() oflag for reading */
|
||||||
|
uint8_t const O_READ = 0X01;
|
||||||
|
/** open() oflag - same as O_IN */
|
||||||
|
uint8_t const O_RDONLY = O_READ;
|
||||||
|
/** open() oflag for write */
|
||||||
|
uint8_t const O_WRITE = 0X02;
|
||||||
|
/** open() oflag - same as O_WRITE */
|
||||||
|
uint8_t const O_WRONLY = O_WRITE;
|
||||||
|
/** open() oflag for reading and writing */
|
||||||
|
uint8_t const O_RDWR = (O_READ | O_WRITE);
|
||||||
|
/** open() oflag mask for access modes */
|
||||||
|
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
|
||||||
|
/** The file offset shall be set to the end of the file prior to each write. */
|
||||||
|
uint8_t const O_APPEND = 0X04;
|
||||||
|
/** synchronous writes - call sync() after each write */
|
||||||
|
uint8_t const O_SYNC = 0X08;
|
||||||
|
/** truncate the file to zero length */
|
||||||
|
uint8_t const O_TRUNC = 0X10;
|
||||||
|
/** set the initial position at the end of the file */
|
||||||
|
uint8_t const O_AT_END = 0X20;
|
||||||
|
/** create the file if nonexistent */
|
||||||
|
uint8_t const O_CREAT = 0X40;
|
||||||
|
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||||
|
uint8_t const O_EXCL = 0X80;
|
||||||
|
|
||||||
|
// SdBaseFile class static and const definitions
|
||||||
|
// flags for ls()
|
||||||
|
/** ls() flag to print modify date */
|
||||||
|
uint8_t const LS_DATE = 1;
|
||||||
|
/** ls() flag to print file size */
|
||||||
|
uint8_t const LS_SIZE = 2;
|
||||||
|
/** ls() flag for recursive list of subdirectories */
|
||||||
|
uint8_t const LS_R = 4;
|
||||||
|
|
||||||
|
|
||||||
|
// flags for timestamp
|
||||||
|
/** set the file's last access date */
|
||||||
|
uint8_t const T_ACCESS = 1;
|
||||||
|
/** set the file's creation date and time */
|
||||||
|
uint8_t const T_CREATE = 2;
|
||||||
|
/** Set the file's write date and time */
|
||||||
|
uint8_t const T_WRITE = 4;
|
||||||
|
// values for type_
|
||||||
|
/** This file has not been opened. */
|
||||||
|
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
|
||||||
|
/** A normal file */
|
||||||
|
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
|
||||||
|
/** A FAT12 or FAT16 root directory */
|
||||||
|
uint8_t const FAT_FILE_TYPE_ROOT_FIXED = 2;
|
||||||
|
/** A FAT32 root directory */
|
||||||
|
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
|
||||||
|
/** A subdirectory file*/
|
||||||
|
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
|
||||||
|
/** Test value for directory type */
|
||||||
|
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED;
|
||||||
|
|
||||||
|
/** date field for FAT directory entry
|
||||||
|
* \param[in] year [1980,2107]
|
||||||
|
* \param[in] month [1,12]
|
||||||
|
* \param[in] day [1,31]
|
||||||
|
*
|
||||||
|
* \return Packed date for dir_t entry.
|
||||||
|
*/
|
||||||
|
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
|
||||||
|
return (year - 1980) << 9 | month << 5 | day;
|
||||||
|
}
|
||||||
|
/** year part of FAT directory date field
|
||||||
|
* \param[in] fatDate Date in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted year [1980,2107]
|
||||||
|
*/
|
||||||
|
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
|
||||||
|
return 1980 + (fatDate >> 9);
|
||||||
|
}
|
||||||
|
/** month part of FAT directory date field
|
||||||
|
* \param[in] fatDate Date in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted month [1,12]
|
||||||
|
*/
|
||||||
|
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
|
||||||
|
return (fatDate >> 5) & 0XF;
|
||||||
|
}
|
||||||
|
/** day part of FAT directory date field
|
||||||
|
* \param[in] fatDate Date in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted day [1,31]
|
||||||
|
*/
|
||||||
|
static inline uint8_t FAT_DAY(uint16_t fatDate) {
|
||||||
|
return fatDate & 0X1F;
|
||||||
|
}
|
||||||
|
/** time field for FAT directory entry
|
||||||
|
* \param[in] hour [0,23]
|
||||||
|
* \param[in] minute [0,59]
|
||||||
|
* \param[in] second [0,59]
|
||||||
|
*
|
||||||
|
* \return Packed time for dir_t entry.
|
||||||
|
*/
|
||||||
|
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||||
|
return hour << 11 | minute << 5 | second >> 1;
|
||||||
|
}
|
||||||
|
/** hour part of FAT directory time field
|
||||||
|
* \param[in] fatTime Time in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted hour [0,23]
|
||||||
|
*/
|
||||||
|
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
|
||||||
|
return fatTime >> 11;
|
||||||
|
}
|
||||||
|
/** minute part of FAT directory time field
|
||||||
|
* \param[in] fatTime Time in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted minute [0,59]
|
||||||
|
*/
|
||||||
|
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
|
||||||
|
return(fatTime >> 5) & 0X3F;
|
||||||
|
}
|
||||||
|
/** second part of FAT directory time field
|
||||||
|
* Note second/2 is stored in packed time.
|
||||||
|
*
|
||||||
|
* \param[in] fatTime Time in packed dir format.
|
||||||
|
*
|
||||||
|
* \return Extracted second [0,58]
|
||||||
|
*/
|
||||||
|
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
|
||||||
|
return 2*(fatTime & 0X1F);
|
||||||
|
}
|
||||||
|
/** Default date for file timestamps is 1 Jan 2000 */
|
||||||
|
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||||
|
/** Default time for file timestamp is 1 am */
|
||||||
|
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdBaseFile
|
||||||
|
* \brief Base class for SdFile with Print and C++ streams.
|
||||||
|
*/
|
||||||
|
class SdBaseFile {
|
||||||
|
public:
|
||||||
|
/** Create an instance. */
|
||||||
|
SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {}
|
||||||
|
SdBaseFile(const char* path, uint8_t oflag);
|
||||||
|
~SdBaseFile() { if(isOpen()) close(); }
|
||||||
|
/**
|
||||||
|
* writeError is set to true if an error occurs during a write().
|
||||||
|
* Set writeError to false before calling print() and/or write() and check
|
||||||
|
* for true after calls to print() and/or write().
|
||||||
|
*/
|
||||||
|
bool writeError;
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// helpers for stream classes
|
||||||
|
/** get position for streams
|
||||||
|
* \param[out] pos struct to receive position
|
||||||
|
*/
|
||||||
|
void getpos(fpos_t* pos);
|
||||||
|
/** set position for streams
|
||||||
|
* \param[out] pos struct with value for new position
|
||||||
|
*/
|
||||||
|
void setpos(fpos_t* pos);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool close();
|
||||||
|
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||||
|
bool createContiguous(SdBaseFile* dirFile,
|
||||||
|
const char* path, uint32_t size);
|
||||||
|
/** \return The current cluster number for a file or directory. */
|
||||||
|
uint32_t curCluster() const {return curCluster_;}
|
||||||
|
/** \return The current position for a file or directory. */
|
||||||
|
uint32_t curPosition() const {return curPosition_;}
|
||||||
|
/** \return Current working directory */
|
||||||
|
static SdBaseFile* cwd() {return cwd_;}
|
||||||
|
/** Set the date/time callback function
|
||||||
|
*
|
||||||
|
* \param[in] dateTime The user's call back function. The callback
|
||||||
|
* function is of the form:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* void dateTime(uint16_t* date, uint16_t* time) {
|
||||||
|
* uint16_t year;
|
||||||
|
* uint8_t month, day, hour, minute, second;
|
||||||
|
*
|
||||||
|
* // User gets date and time from GPS or real-time clock here
|
||||||
|
*
|
||||||
|
* // return date using FAT_DATE macro to format fields
|
||||||
|
* *date = FAT_DATE(year, month, day);
|
||||||
|
*
|
||||||
|
* // return time using FAT_TIME macro to format fields
|
||||||
|
* *time = FAT_TIME(hour, minute, second);
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* Sets the function that is called when a file is created or when
|
||||||
|
* a file's directory entry is modified by sync(). All timestamps,
|
||||||
|
* access, creation, and modify, are set when a file is created.
|
||||||
|
* sync() maintains the last access date and last modify date/time.
|
||||||
|
*
|
||||||
|
* See the timestamp() function.
|
||||||
|
*/
|
||||||
|
static void dateTimeCallback(
|
||||||
|
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||||
|
dateTime_ = dateTime;
|
||||||
|
}
|
||||||
|
/** Cancel the date/time callback function. */
|
||||||
|
static void dateTimeCallbackCancel() {dateTime_ = 0;}
|
||||||
|
bool dirEntry(dir_t* dir);
|
||||||
|
static void dirName(const dir_t& dir, char* name);
|
||||||
|
bool exists(const char* name);
|
||||||
|
int16_t fgets(char* str, int16_t num, char* delim = 0);
|
||||||
|
/** \return The total number of bytes in a file or directory. */
|
||||||
|
uint32_t fileSize() const {return fileSize_;}
|
||||||
|
/** \return The first cluster number for a file or directory. */
|
||||||
|
uint32_t firstCluster() const {return firstCluster_;}
|
||||||
|
bool getFilename(char* name);
|
||||||
|
/** \return True if this is a directory else false. */
|
||||||
|
bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
|
||||||
|
/** \return True if this is a normal file else false. */
|
||||||
|
bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;}
|
||||||
|
/** \return True if this is an open file/directory else false. */
|
||||||
|
bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;}
|
||||||
|
/** \return True if this is a subdirectory else false. */
|
||||||
|
bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;}
|
||||||
|
/** \return True if this is the root directory. */
|
||||||
|
bool isRoot() const {
|
||||||
|
return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32;
|
||||||
|
}
|
||||||
|
#if ARDUINO
|
||||||
|
void ls(Print* pr, uint8_t flags = 0, uint8_t indent = 0);
|
||||||
|
void ls(uint8_t flags = 0);
|
||||||
|
#endif
|
||||||
|
bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true);
|
||||||
|
// alias for backward compactability
|
||||||
|
bool makeDir(SdBaseFile* dir, const char* path) {
|
||||||
|
return mkdir(dir, path, false);
|
||||||
|
}
|
||||||
|
bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
|
||||||
|
bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
|
||||||
|
bool open(const char* path, uint8_t oflag = O_READ);
|
||||||
|
bool openNext(SdBaseFile* dirFile, uint8_t oflag);
|
||||||
|
bool openRoot(SdVolume* vol);
|
||||||
|
int peek();
|
||||||
|
#if ARDUINO
|
||||||
|
static void printFatDate(uint16_t fatDate);
|
||||||
|
static void printFatDate(Print* pr, uint16_t fatDate);
|
||||||
|
static void printFatTime(uint16_t fatTime);
|
||||||
|
static void printFatTime(Print* pr, uint16_t fatTime);
|
||||||
|
bool printName();
|
||||||
|
#endif
|
||||||
|
int16_t read();
|
||||||
|
int16_t read(void* buf, uint16_t nbyte);
|
||||||
|
int8_t readDir(dir_t* dir);
|
||||||
|
static bool remove(SdBaseFile* dirFile, const char* path);
|
||||||
|
bool remove();
|
||||||
|
/** Set the file's current position to zero. */
|
||||||
|
void rewind() {seekSet(0);}
|
||||||
|
bool rename(SdBaseFile* dirFile, const char* newPath);
|
||||||
|
bool rmdir();
|
||||||
|
// for backward compatibility
|
||||||
|
bool rmDir() {return rmdir();}
|
||||||
|
bool rmRfStar();
|
||||||
|
/** Set the files position to current position + \a pos. See seekSet().
|
||||||
|
* \param[in] offset The new position in bytes from the current position.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool seekCur(int32_t offset) {
|
||||||
|
return seekSet(curPosition_ + offset);
|
||||||
|
}
|
||||||
|
/** Set the files position to end-of-file + \a offset. See seekSet().
|
||||||
|
* \param[in] offset The new position in bytes from end-of-file.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool seekEnd(int32_t offset = 0) {return seekSet(fileSize_ + offset);}
|
||||||
|
bool seekSet(uint32_t pos);
|
||||||
|
bool sync();
|
||||||
|
bool timestamp(SdBaseFile* file);
|
||||||
|
bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||||
|
uint8_t hour, uint8_t minute, uint8_t second);
|
||||||
|
/** Type of file. You should use isFile() or isDir() instead of type()
|
||||||
|
* if possible.
|
||||||
|
*
|
||||||
|
* \return The file or directory type.
|
||||||
|
*/
|
||||||
|
uint8_t type() const {return type_;}
|
||||||
|
bool truncate(uint32_t size);
|
||||||
|
/** \return SdVolume that contains this file. */
|
||||||
|
SdVolume* volume() const {return vol_;}
|
||||||
|
int16_t write(const void* buf, uint16_t nbyte);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
private:
|
||||||
|
// allow SdFat to set cwd_
|
||||||
|
friend class SdFat;
|
||||||
|
// global pointer to cwd dir
|
||||||
|
static SdBaseFile* cwd_;
|
||||||
|
// data time callback function
|
||||||
|
static void (*dateTime_)(uint16_t* date, uint16_t* time);
|
||||||
|
// bits defined in flags_
|
||||||
|
// should be 0X0F
|
||||||
|
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
|
||||||
|
// sync of directory entry required
|
||||||
|
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
|
||||||
|
|
||||||
|
// private data
|
||||||
|
uint8_t flags_; // See above for definition of flags_ bits
|
||||||
|
uint8_t fstate_; // error and eof indicator
|
||||||
|
uint8_t type_; // type of file see above for values
|
||||||
|
uint32_t curCluster_; // cluster for current file position
|
||||||
|
uint32_t curPosition_; // current file position in bytes from beginning
|
||||||
|
uint32_t dirBlock_; // block for this files directory entry
|
||||||
|
uint8_t dirIndex_; // index of directory entry in dirBlock
|
||||||
|
uint32_t fileSize_; // file size in bytes
|
||||||
|
uint32_t firstCluster_; // first cluster of file
|
||||||
|
SdVolume* vol_; // volume where file is located
|
||||||
|
|
||||||
|
/** experimental don't use */
|
||||||
|
bool openParent(SdBaseFile* dir);
|
||||||
|
// private functions
|
||||||
|
bool addCluster();
|
||||||
|
bool addDirCluster();
|
||||||
|
dir_t* cacheDirEntry(uint8_t action);
|
||||||
|
#if ARDUINO
|
||||||
|
int8_t lsPrintNext(Print *pr, uint8_t flags, uint8_t indent);
|
||||||
|
#endif
|
||||||
|
static bool make83Name(const char* str, uint8_t* name, const char** ptr);
|
||||||
|
bool mkdir(SdBaseFile* parent, const uint8_t dname[11]);
|
||||||
|
bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag);
|
||||||
|
bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||||
|
dir_t* readDirCache();
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// to be deleted
|
||||||
|
static void printDirName(const dir_t& dir,
|
||||||
|
uint8_t width, bool printSlash);
|
||||||
|
#if ARDUINO
|
||||||
|
static void printDirName(Print* pr, const dir_t& dir,
|
||||||
|
uint8_t width, bool printSlash);
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||||
|
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
|
||||||
|
public:
|
||||||
|
/** \deprecated Use:
|
||||||
|
* bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||||
|
* \param[out] bgnBlock the first block address for the file.
|
||||||
|
* \param[out] endBlock the last block address for the file.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
|
||||||
|
return contiguousRange(&bgnBlock, &endBlock);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
* bool createContiguous(SdBaseFile* dirFile,
|
||||||
|
* const char* path, uint32_t size)
|
||||||
|
* \param[in] dirFile The directory where the file will be created.
|
||||||
|
* \param[in] path A path with a valid DOS 8.3 file name.
|
||||||
|
* \param[in] size The desired file size.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool createContiguous(SdBaseFile& dirFile, // NOLINT
|
||||||
|
const char* path, uint32_t size) {
|
||||||
|
return createContiguous(&dirFile, path, size);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
* static void dateTimeCallback(
|
||||||
|
* void (*dateTime)(uint16_t* date, uint16_t* time));
|
||||||
|
* \param[in] dateTime The user's call back function.
|
||||||
|
*/
|
||||||
|
static void dateTimeCallback(
|
||||||
|
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
|
||||||
|
oldDateTime_ = dateTime;
|
||||||
|
dateTime_ = dateTime ? oldToNew : 0;
|
||||||
|
}
|
||||||
|
/** \deprecated Use: bool dirEntry(dir_t* dir);
|
||||||
|
* \param[out] dir Location for return of the file's directory entry.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
|
||||||
|
/** \deprecated Use:
|
||||||
|
* bool mkdir(SdBaseFile* dir, const char* path);
|
||||||
|
* \param[in] dir An open SdFat instance for the directory that will contain
|
||||||
|
* the new directory.
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the new directory.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT
|
||||||
|
return mkdir(&dir, path);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
* bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
|
||||||
|
* \param[in] dirFile An open SdFat instance for the directory containing the
|
||||||
|
* file to be opened.
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||||
|
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool open(SdBaseFile& dirFile, // NOLINT
|
||||||
|
const char* path, uint8_t oflag) {
|
||||||
|
return open(&dirFile, path, oflag);
|
||||||
|
}
|
||||||
|
/** \deprecated Do not use in new apps
|
||||||
|
* \param[in] dirFile An open SdFat instance for the directory containing the
|
||||||
|
* file to be opened.
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool open(SdBaseFile& dirFile, const char* path) { // NOLINT
|
||||||
|
return open(dirFile, path, O_RDWR);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
* bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
|
||||||
|
* \param[in] dirFile An open SdFat instance for the directory.
|
||||||
|
* \param[in] index The \a index of the directory entry for the file to be
|
||||||
|
* opened. The value for \a index is (directory file position)/32.
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||||
|
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
|
||||||
|
return open(&dirFile, index, oflag);
|
||||||
|
}
|
||||||
|
/** \deprecated Use: bool openRoot(SdVolume* vol);
|
||||||
|
* \param[in] vol The FAT volume containing the root directory to be opened.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
|
||||||
|
/** \deprecated Use: int8_t readDir(dir_t* dir);
|
||||||
|
* \param[out] dir The dir_t struct that will receive the data.
|
||||||
|
* \return bytes read for success zero for eof or -1 for failure.
|
||||||
|
*/
|
||||||
|
int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
|
||||||
|
/** \deprecated Use:
|
||||||
|
* static uint8_t remove(SdBaseFile* dirFile, const char* path);
|
||||||
|
* \param[in] dirFile The directory that contains the file.
|
||||||
|
* \param[in] path The name of the file to be removed.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT
|
||||||
|
return remove(&dirFile, path);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// rest are private
|
||||||
|
private:
|
||||||
|
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
|
||||||
|
static void oldToNew(uint16_t* date, uint16_t* time) {
|
||||||
|
uint16_t d;
|
||||||
|
uint16_t t;
|
||||||
|
oldDateTime_(d, t);
|
||||||
|
*date = d;
|
||||||
|
*time = t;
|
||||||
|
}
|
||||||
|
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SdBaseFile_h
|
332
arduino/floppyemu/SdFat/SdFat.cpp
Executable file
332
arduino/floppyemu/SdFat/SdFat.cpp
Executable file
|
@ -0,0 +1,332 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
//#include <SdFatUtil.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Change a volume's working directory to root
|
||||||
|
*
|
||||||
|
* Changes the volume's working directory to the SD's root directory.
|
||||||
|
* Optionally set the current working directory to the volume's
|
||||||
|
* working directory.
|
||||||
|
*
|
||||||
|
* \param[in] set_cwd Set the current working directory to this volume's
|
||||||
|
* working directory if true.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::chdir(bool set_cwd) {
|
||||||
|
if (set_cwd) SdBaseFile::cwd_ = &vwd_;
|
||||||
|
vwd_.close();
|
||||||
|
return vwd_.openRoot(&vol_);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Change a volume's working directory
|
||||||
|
*
|
||||||
|
* Changes the volume working directory to the \a path subdirectory.
|
||||||
|
* Optionally set the current working directory to the volume's
|
||||||
|
* working directory.
|
||||||
|
*
|
||||||
|
* Example: If the volume's working directory is "/DIR", chdir("SUB")
|
||||||
|
* will change the volume's working directory from "/DIR" to "/DIR/SUB".
|
||||||
|
*
|
||||||
|
* If path is "/", the volume's working directory will be changed to the
|
||||||
|
* root directory
|
||||||
|
*
|
||||||
|
* \param[in] path The name of the subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] set_cwd Set the current working directory to this volume's
|
||||||
|
* working directory if true.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::chdir(const char *path, bool set_cwd) {
|
||||||
|
SdBaseFile dir;
|
||||||
|
if (path[0] == '/' && path[1] == '\0') return chdir(set_cwd);
|
||||||
|
if (!dir.open(&vwd_, path, O_READ)) goto fail;
|
||||||
|
if (!dir.isDir()) goto fail;
|
||||||
|
vwd_ = dir;
|
||||||
|
if (set_cwd) SdBaseFile::cwd_ = &vwd_;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set the current working directory to a volume's working directory.
|
||||||
|
*
|
||||||
|
* This is useful with multiple SD cards.
|
||||||
|
*
|
||||||
|
* The current working directory is changed to this volume's working directory.
|
||||||
|
*
|
||||||
|
* This is like the Windows/DOS \<drive letter>: command.
|
||||||
|
*/
|
||||||
|
void SdFat::chvol() {
|
||||||
|
SdBaseFile::cwd_ = &vwd_;
|
||||||
|
}
|
||||||
|
#if ARDUINO
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print any SD error code and halt. */
|
||||||
|
void SdFat::errorHalt() {
|
||||||
|
errorPrint();
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print msg, any SD error code, and halt.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void SdFat::errorHalt(char const* msg) {
|
||||||
|
errorPrint(msg);
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print msg, any SD error code, and halt.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message in program space (flash memory) to print.
|
||||||
|
*/
|
||||||
|
void SdFat::errorHalt_P(PGM_P msg) {
|
||||||
|
errorPrint_P(msg);
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print any SD error code. */
|
||||||
|
void SdFat::errorPrint() {
|
||||||
|
if (!card_.errorCode()) return;
|
||||||
|
PgmPrint("SD errorCode: 0X");
|
||||||
|
Serial.println(card_.errorCode(), HEX);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void SdFat::errorPrint(char const* msg) {
|
||||||
|
PgmPrint("error: ");
|
||||||
|
Serial.println(msg);
|
||||||
|
errorPrint();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message in program space (flash memory) to print.
|
||||||
|
*/
|
||||||
|
void SdFat::errorPrint_P(PGM_P msg) {
|
||||||
|
PgmPrint("error: ");
|
||||||
|
SerialPrintln_P(msg);
|
||||||
|
errorPrint();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Test for the existence of a file.
|
||||||
|
*
|
||||||
|
* \param[in] name Name of the file to be tested for.
|
||||||
|
*
|
||||||
|
* \return true if the file exists else false.
|
||||||
|
*/
|
||||||
|
bool SdFat::exists(const char* name) {
|
||||||
|
return vwd_.exists(name);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Initialize an SdFat object.
|
||||||
|
*
|
||||||
|
* Initializes the SD card, SD volume, and root directory.
|
||||||
|
*
|
||||||
|
* \param[in] sckRateID value for SPI SCK rate. See Sd2Card::init().
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::init(uint8_t sckRateID) {
|
||||||
|
return card_.init(sckRateID) && vol_.init(&card_) && chdir(1);
|
||||||
|
}
|
||||||
|
#if ARDUINO
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** %Print error details and halt after SdFat::init() fails. */
|
||||||
|
void SdFat::initErrorHalt() {
|
||||||
|
initErrorPrint();
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**Print message, error details, and halt after SdFat::init() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void SdFat::initErrorHalt(char const *msg) {
|
||||||
|
Serial.println(msg);
|
||||||
|
initErrorHalt();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**Print message, error details, and halt after SdFat::init() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message in program space (flash memory) to print.
|
||||||
|
*/
|
||||||
|
void SdFat::initErrorHalt_P(PGM_P msg) {
|
||||||
|
SerialPrintln_P(msg);
|
||||||
|
initErrorHalt();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Print error details after SdFat::init() fails. */
|
||||||
|
void SdFat::initErrorPrint() {
|
||||||
|
if (card_.errorCode()) {
|
||||||
|
PgmPrintln("Can't access SD card. Do not reformat.");
|
||||||
|
if (card_.errorCode() == SD_CARD_ERROR_CMD0) {
|
||||||
|
PgmPrintln("No card, wrong chip select pin, or SPI problem?");
|
||||||
|
}
|
||||||
|
errorPrint();
|
||||||
|
} else if (vol_.fatType() == 0) {
|
||||||
|
PgmPrintln("Invalid format, reformat SD.");
|
||||||
|
} else if (!vwd_.isOpen()) {
|
||||||
|
PgmPrintln("Can't open root directory.");
|
||||||
|
} else {
|
||||||
|
PgmPrintln("No error found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**Print message and error details and halt after SdFat::init() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void SdFat::initErrorPrint(char const *msg) {
|
||||||
|
Serial.println(msg);
|
||||||
|
initErrorPrint();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**Print message and error details after SdFat::init() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message in program space (flash memory) to print.
|
||||||
|
*/
|
||||||
|
void SdFat::initErrorPrint_P(PGM_P msg) {
|
||||||
|
SerialPrintln_P(msg);
|
||||||
|
initErrorHalt();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** List the directory contents of the volume working directory to Serial.
|
||||||
|
*
|
||||||
|
* \param[in] flags The inclusive OR of
|
||||||
|
*
|
||||||
|
* LS_DATE - %Print file modification date
|
||||||
|
*
|
||||||
|
* LS_SIZE - %Print file size.
|
||||||
|
*
|
||||||
|
* LS_R - Recursive list of subdirectories.
|
||||||
|
*/
|
||||||
|
void SdFat::ls(uint8_t flags) {
|
||||||
|
vwd_.ls(&Serial, flags);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** List the directory contents of the volume working directory to Serial.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print stream for list.
|
||||||
|
*
|
||||||
|
* \param[in] flags The inclusive OR of
|
||||||
|
*
|
||||||
|
* LS_DATE - %Print file modification date
|
||||||
|
*
|
||||||
|
* LS_SIZE - %Print file size.
|
||||||
|
*
|
||||||
|
* LS_R - Recursive list of subdirectories.
|
||||||
|
*/
|
||||||
|
void SdFat::ls(Print* pr, uint8_t flags) {
|
||||||
|
vwd_.ls(pr, flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Make a subdirectory in the volume working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] pFlag Create missing parent directories if true.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::mkdir(const char* path, bool pFlag) {
|
||||||
|
SdBaseFile sub;
|
||||||
|
return sub.mkdir(&vwd_, path, pFlag);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Remove a file from the volume working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::remove(const char* path) {
|
||||||
|
return SdBaseFile::remove(&vwd_, path);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Rename a file or subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||||
|
*
|
||||||
|
* \param[in] newPath New path name of the file or subdirectory.
|
||||||
|
*
|
||||||
|
* The \a newPath object must not exist before the rename call.
|
||||||
|
*
|
||||||
|
* The file to be renamed must not be open. The directory entry may be
|
||||||
|
* moved and file system corruption could occur if the file is accessed by
|
||||||
|
* a file object that was opened before the rename() call.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::rename(const char *oldPath, const char *newPath) {
|
||||||
|
SdBaseFile file;
|
||||||
|
if (!file.open(oldPath, O_READ)) return false;
|
||||||
|
return file.rename(&vwd_, newPath);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Remove a subdirectory from the volume's working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||||
|
*
|
||||||
|
* The subdirectory file will be removed only if it is empty.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
bool SdFat::rmdir(const char* path) {
|
||||||
|
SdBaseFile sub;
|
||||||
|
if (!sub.open(path, O_READ)) return false;
|
||||||
|
return sub.rmdir();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Truncate a file to a specified length. The current file position
|
||||||
|
* will be maintained if it is less than or equal to \a length otherwise
|
||||||
|
* it will be set to end of file.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||||
|
* \param[in] length The desired length for the file.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure.
|
||||||
|
* Reasons for failure include file is read only, file is a directory,
|
||||||
|
* \a length is greater than the current file size or an I/O error occurs.
|
||||||
|
*/
|
||||||
|
bool SdFat::truncate(const char* path, uint32_t length) {
|
||||||
|
SdBaseFile file;
|
||||||
|
if (!file.open(path, O_WRITE)) return false;
|
||||||
|
return file.truncate(length);
|
||||||
|
}
|
80
arduino/floppyemu/SdFat/SdFat.h
Executable file
80
arduino/floppyemu/SdFat/SdFat.h
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdFat_h
|
||||||
|
#define SdFat_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SdFat class
|
||||||
|
*/
|
||||||
|
//#include <SdFile.h>
|
||||||
|
//#include <SdStream.h>
|
||||||
|
//#include <ArduinoStream.h>
|
||||||
|
#include <SdBaseFile.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SdFat version YYYYMMDD */
|
||||||
|
#define SD_FAT_VERSION 20110902
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdFat
|
||||||
|
* \brief Integration class for the %SdFat library.
|
||||||
|
*/
|
||||||
|
class SdFat {
|
||||||
|
public:
|
||||||
|
SdFat() {}
|
||||||
|
/** \return a pointer to the Sd2Card object. */
|
||||||
|
Sd2Card* card() {return &card_;}
|
||||||
|
bool chdir(bool set_cwd = false);
|
||||||
|
bool chdir(const char* path, bool set_cwd = false);
|
||||||
|
void chvol();
|
||||||
|
#if ARDUINO
|
||||||
|
void errorHalt();
|
||||||
|
void errorHalt_P(PGM_P msg);
|
||||||
|
void errorHalt(char const *msg);
|
||||||
|
void errorPrint();
|
||||||
|
void errorPrint_P(PGM_P msg);
|
||||||
|
void errorPrint(char const *msg);
|
||||||
|
#endif
|
||||||
|
bool exists(const char* name);
|
||||||
|
bool init(uint8_t sckRateID = SPI_FULL_SPEED);
|
||||||
|
#if ARDUINO
|
||||||
|
void initErrorHalt();
|
||||||
|
void initErrorHalt(char const *msg);
|
||||||
|
void initErrorHalt_P(PGM_P msg);
|
||||||
|
void initErrorPrint();
|
||||||
|
void initErrorPrint(char const *msg);
|
||||||
|
void initErrorPrint_P(PGM_P msg);
|
||||||
|
void ls(uint8_t flags = 0);
|
||||||
|
void ls(Print* pr, uint8_t flags = 0);
|
||||||
|
#endif
|
||||||
|
bool mkdir(const char* path, bool pFlag = true);
|
||||||
|
bool remove(const char* path);
|
||||||
|
bool rename(const char *oldPath, const char *newPath);
|
||||||
|
bool rmdir(const char* path);
|
||||||
|
bool truncate(const char* path, uint32_t length);
|
||||||
|
/** \return a pointer to the SdVolume object. */
|
||||||
|
SdVolume* vol() {return &vol_;}
|
||||||
|
/** \return a pointer to the volume working directory. */
|
||||||
|
SdBaseFile* vwd() {return &vwd_;}
|
||||||
|
private:
|
||||||
|
Sd2Card card_;
|
||||||
|
SdVolume vol_;
|
||||||
|
SdBaseFile vwd_;
|
||||||
|
};
|
||||||
|
#endif // SdFat_h
|
108
arduino/floppyemu/SdFat/SdFatConfig.h
Executable file
108
arduino/floppyemu/SdFat/SdFatConfig.h
Executable file
|
@ -0,0 +1,108 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief configuration definitions
|
||||||
|
*/
|
||||||
|
#ifndef SdFatConfig_h
|
||||||
|
#define SdFatConfig_h
|
||||||
|
#include <stdint.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
|
||||||
|
*
|
||||||
|
* Using multiple cards costs 400 - 500 bytes of flash.
|
||||||
|
*
|
||||||
|
* Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
|
||||||
|
*/
|
||||||
|
#define USE_MULTIPLE_CARDS 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
|
||||||
|
*
|
||||||
|
* The standard for iostreams is to call flush. This is very costly for
|
||||||
|
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
|
||||||
|
*
|
||||||
|
* SdFat has a single 512 byte buffer for SD I/O so it must write the current
|
||||||
|
* data block to the SD, read the directory block from the SD, update the
|
||||||
|
* directory entry, write the directory block to the SD and read the data
|
||||||
|
* block back into the buffer.
|
||||||
|
*
|
||||||
|
* The SD flash memory controller is not designed for this many rewrites
|
||||||
|
* so performance may be reduced by more than a factor of 100.
|
||||||
|
*
|
||||||
|
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
|
||||||
|
* all data to be written to the SD.
|
||||||
|
*/
|
||||||
|
#define ENDL_CALLS_FLUSH 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Allow use of deprecated functions if ALLOW_DEPRECATED_FUNCTIONS is nonzero
|
||||||
|
*/
|
||||||
|
#define ALLOW_DEPRECATED_FUNCTIONS 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Allow FAT12 volumes if FAT12_SUPPORT is nonzero.
|
||||||
|
* FAT12 has not been well tested.
|
||||||
|
*/
|
||||||
|
#define FAT12_SUPPORT 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* SPI init rate for SD initialization commands. Must be 5 (F_CPU/64)
|
||||||
|
* or 6 (F_CPU/128).
|
||||||
|
*/
|
||||||
|
#define SPI_SD_INIT_RATE 5
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set the SS pin high for hardware SPI. If SS is chip select for another SPI
|
||||||
|
* device this will disable that device during the SD init phase.
|
||||||
|
*/
|
||||||
|
#define SET_SPI_SS_HIGH 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Define MEGA_SOFT_SPI nonzero to use software SPI on Mega Arduinos.
|
||||||
|
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||||
|
*
|
||||||
|
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||||
|
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||||
|
* but many SD cards will fail with GPS Shield V1.0.
|
||||||
|
*/
|
||||||
|
#define MEGA_SOFT_SPI 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_SOFTWARE_SPI nonzero to always use software SPI.
|
||||||
|
*/
|
||||||
|
#define USE_SOFTWARE_SPI 0
|
||||||
|
// define software SPI pins so Mega can use unmodified 168/328 shields
|
||||||
|
/** Software SPI chip select pin for the SD */
|
||||||
|
uint8_t const SOFT_SPI_CS_PIN = 10;
|
||||||
|
/** Software SPI Master Out Slave In pin */
|
||||||
|
uint8_t const SOFT_SPI_MOSI_PIN = 11;
|
||||||
|
/** Software SPI Master In Slave Out pin */
|
||||||
|
uint8_t const SOFT_SPI_MISO_PIN = 12;
|
||||||
|
/** Software SPI Clock pin */
|
||||||
|
uint8_t const SOFT_SPI_SCK_PIN = 13;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* The __cxa_pure_virtual function is an error handler that is invoked when
|
||||||
|
* a pure virtual function is called.
|
||||||
|
*/
|
||||||
|
#define USE_CXA_PURE_VIRTUAL 1
|
||||||
|
#endif // SdFatConfig_h
|
604
arduino/floppyemu/SdFat/SdFatStructs.h
Executable file
604
arduino/floppyemu/SdFat/SdFatStructs.h
Executable file
|
@ -0,0 +1,604 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdFatStructs_h
|
||||||
|
#define SdFatStructs_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief FAT file structures
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* mostly from Microsoft document fatgen103.doc
|
||||||
|
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Value for byte 510 of boot block or MBR */
|
||||||
|
uint8_t const BOOTSIG0 = 0X55;
|
||||||
|
/** Value for byte 511 of boot block or MBR */
|
||||||
|
uint8_t const BOOTSIG1 = 0XAA;
|
||||||
|
/** Value for bootSignature field int FAT/FAT32 boot sector */
|
||||||
|
uint8_t const EXTENDED_BOOT_SIG = 0X29;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct partitionTable
|
||||||
|
* \brief MBR partition table entry
|
||||||
|
*
|
||||||
|
* A partition table entry for a MBR formatted storage device.
|
||||||
|
* The MBR partition table has four entries.
|
||||||
|
*/
|
||||||
|
struct partitionTable {
|
||||||
|
/**
|
||||||
|
* Boot Indicator . Indicates whether the volume is the active
|
||||||
|
* partition. Legal values include: 0X00. Do not use for booting.
|
||||||
|
* 0X80 Active partition.
|
||||||
|
*/
|
||||||
|
uint8_t boot;
|
||||||
|
/**
|
||||||
|
* Head part of Cylinder-head-sector address of the first block in
|
||||||
|
* the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginHead;
|
||||||
|
/**
|
||||||
|
* Sector part of Cylinder-head-sector address of the first block in
|
||||||
|
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned beginSector : 6;
|
||||||
|
/** High bits cylinder for first block in partition. */
|
||||||
|
unsigned beginCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
* Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||||
|
* are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginCylinderLow;
|
||||||
|
/**
|
||||||
|
* Partition type. See defines that begin with PART_TYPE_ for
|
||||||
|
* some Microsoft partition types.
|
||||||
|
*/
|
||||||
|
uint8_t type;
|
||||||
|
/**
|
||||||
|
* head part of cylinder-head-sector address of the last sector in the
|
||||||
|
* partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endHead;
|
||||||
|
/**
|
||||||
|
* Sector part of cylinder-head-sector address of the last sector in
|
||||||
|
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned endSector : 6;
|
||||||
|
/** High bits of end cylinder */
|
||||||
|
unsigned endCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
* Combine endCylinderLow with endCylinderHigh. Legal values
|
||||||
|
* are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endCylinderLow;
|
||||||
|
/** Logical block address of the first block in the partition. */
|
||||||
|
uint32_t firstSector;
|
||||||
|
/** Length of the partition, in blocks. */
|
||||||
|
uint32_t totalSectors;
|
||||||
|
};
|
||||||
|
/** Type name for partitionTable */
|
||||||
|
typedef struct partitionTable part_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct masterBootRecord
|
||||||
|
*
|
||||||
|
* \brief Master Boot Record
|
||||||
|
*
|
||||||
|
* The first block of a storage device that is formatted with a MBR.
|
||||||
|
*/
|
||||||
|
struct masterBootRecord {
|
||||||
|
/** Code Area for master boot program. */
|
||||||
|
uint8_t codeArea[440];
|
||||||
|
/** Optional Windows NT disk signature. May contain boot code. */
|
||||||
|
uint32_t diskSignature;
|
||||||
|
/** Usually zero but may be more boot code. */
|
||||||
|
uint16_t usuallyZero;
|
||||||
|
/** Partition tables. */
|
||||||
|
part_t part[4];
|
||||||
|
/** First MBR signature byte. Must be 0X55 */
|
||||||
|
uint8_t mbrSig0;
|
||||||
|
/** Second MBR signature byte. Must be 0XAA */
|
||||||
|
uint8_t mbrSig1;
|
||||||
|
};
|
||||||
|
/** Type name for masterBootRecord */
|
||||||
|
typedef struct masterBootRecord mbr_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct fat_boot
|
||||||
|
*
|
||||||
|
* \brief Boot sector for a FAT12/FAT16 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat_boot {
|
||||||
|
/**
|
||||||
|
* The first three bytes of the boot sector must be valid,
|
||||||
|
* executable x 86-based CPU instructions. This includes a
|
||||||
|
* jump instruction that skips the next nonexecutable bytes.
|
||||||
|
*/
|
||||||
|
uint8_t jump[3];
|
||||||
|
/**
|
||||||
|
* This is typically a string of characters that identifies
|
||||||
|
* the operating system that formatted the volume.
|
||||||
|
*/
|
||||||
|
char oemId[8];
|
||||||
|
/**
|
||||||
|
* The size of a hardware sector. Valid decimal values for this
|
||||||
|
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||||
|
* the United States, the value of this field is 512.
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
* Number of sectors per allocation unit. This value must be a
|
||||||
|
* power of 2 that is greater than 0. The legal values are
|
||||||
|
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
* The number of sectors preceding the start of the first FAT,
|
||||||
|
* including the boot sector. The value of this field is always 1.
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/**
|
||||||
|
* The number of copies of the FAT on the volume.
|
||||||
|
* The value of this field is always 2.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||||
|
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||||
|
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||||
|
* value should always specify a count that when multiplied by 32
|
||||||
|
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||||
|
* use the value 512.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
* This field is the old 16-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||||
|
* must be nonzero. For FAT32 volumes, this field must be 0. For
|
||||||
|
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||||
|
* totalSectors32 is 0 if the total sector count fits
|
||||||
|
* (is less than 0x10000).
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
* This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
* no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||||
|
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||||
|
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
* contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
* Count of hidden sectors preceding the partition that contains this
|
||||||
|
* FAT volume. This field is generally only relevant for media
|
||||||
|
* visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
* This field is the new 32-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then
|
||||||
|
* totalSectors16 must be nonzero.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
* Related to the BIOS physical drive number. Floppy drives are
|
||||||
|
* identified as 0x00 and physical hard disks are identified as
|
||||||
|
* 0x80, regardless of the number of physical disk drives.
|
||||||
|
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||||
|
* call to specify the device to access. The value is only
|
||||||
|
* relevant if the device is a boot device.
|
||||||
|
*/
|
||||||
|
uint8_t driveNumber;
|
||||||
|
/** used by Windows NT - should be zero for FAT */
|
||||||
|
uint8_t reserved1;
|
||||||
|
/** 0X29 if next three fields are valid */
|
||||||
|
uint8_t bootSignature;
|
||||||
|
/**
|
||||||
|
* A random serial number created when formatting a disk,
|
||||||
|
* which helps to distinguish between disks.
|
||||||
|
* Usually generated by combining date and time.
|
||||||
|
*/
|
||||||
|
uint32_t volumeSerialNumber;
|
||||||
|
/**
|
||||||
|
* A field once used to store the volume label. The volume label
|
||||||
|
* is now stored as a special file in the root directory.
|
||||||
|
*/
|
||||||
|
char volumeLabel[11];
|
||||||
|
/**
|
||||||
|
* A field with a value of either FAT, FAT12 or FAT16,
|
||||||
|
* depending on the disk format.
|
||||||
|
*/
|
||||||
|
char fileSystemType[8];
|
||||||
|
/** X86 boot code */
|
||||||
|
uint8_t bootCode[448];
|
||||||
|
/** must be 0X55 */
|
||||||
|
uint8_t bootSectorSig0;
|
||||||
|
/** must be 0XAA */
|
||||||
|
uint8_t bootSectorSig1;
|
||||||
|
};
|
||||||
|
/** Type name for FAT Boot Sector */
|
||||||
|
typedef struct fat_boot fat_boot_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct fat32_boot
|
||||||
|
*
|
||||||
|
* \brief Boot sector for a FAT32 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat32_boot {
|
||||||
|
/**
|
||||||
|
* The first three bytes of the boot sector must be valid,
|
||||||
|
* executable x 86-based CPU instructions. This includes a
|
||||||
|
* jump instruction that skips the next nonexecutable bytes.
|
||||||
|
*/
|
||||||
|
uint8_t jump[3];
|
||||||
|
/**
|
||||||
|
* This is typically a string of characters that identifies
|
||||||
|
* the operating system that formatted the volume.
|
||||||
|
*/
|
||||||
|
char oemId[8];
|
||||||
|
/**
|
||||||
|
* The size of a hardware sector. Valid decimal values for this
|
||||||
|
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||||
|
* the United States, the value of this field is 512.
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
* Number of sectors per allocation unit. This value must be a
|
||||||
|
* power of 2 that is greater than 0. The legal values are
|
||||||
|
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
* The number of sectors preceding the start of the first FAT,
|
||||||
|
* including the boot sector. Must not be zero
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/**
|
||||||
|
* The number of copies of the FAT on the volume.
|
||||||
|
* The value of this field is always 2.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
* For FAT32 volumes, this field must be 0.
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
* This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
* no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||||
|
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
* contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
* Count of hidden sectors preceding the partition that contains this
|
||||||
|
* FAT volume. This field is generally only relevant for media
|
||||||
|
* visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
* Contains the total number of sectors in the FAT32 volume.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||||
|
*/
|
||||||
|
uint32_t sectorsPerFat32;
|
||||||
|
/**
|
||||||
|
* This field is only defined for FAT32 media and does not exist on
|
||||||
|
* FAT12 and FAT16 media.
|
||||||
|
* Bits 0-3 -- Zero-based number of active FAT.
|
||||||
|
* Only valid if mirroring is disabled.
|
||||||
|
* Bits 4-6 -- Reserved.
|
||||||
|
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||||
|
* -- 1 means only one FAT is active; it is the one referenced
|
||||||
|
* in bits 0-3.
|
||||||
|
* Bits 8-15 -- Reserved.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Flags;
|
||||||
|
/**
|
||||||
|
* FAT32 version. High byte is major revision number.
|
||||||
|
* Low byte is minor revision number. Only 0.0 define.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Version;
|
||||||
|
/**
|
||||||
|
* Cluster number of the first cluster of the root directory for FAT32.
|
||||||
|
* This usually 2 but not required to be 2.
|
||||||
|
*/
|
||||||
|
uint32_t fat32RootCluster;
|
||||||
|
/**
|
||||||
|
* Sector number of FSINFO structure in the reserved area of the
|
||||||
|
* FAT32 volume. Usually 1.
|
||||||
|
*/
|
||||||
|
uint16_t fat32FSInfo;
|
||||||
|
/**
|
||||||
|
* If nonzero, indicates the sector number in the reserved area
|
||||||
|
* of the volume of a copy of the boot record. Usually 6.
|
||||||
|
* No value other than 6 is recommended.
|
||||||
|
*/
|
||||||
|
uint16_t fat32BackBootBlock;
|
||||||
|
/**
|
||||||
|
* Reserved for future expansion. Code that formats FAT32 volumes
|
||||||
|
* should always set all of the bytes of this field to 0.
|
||||||
|
*/
|
||||||
|
uint8_t fat32Reserved[12];
|
||||||
|
/**
|
||||||
|
* Related to the BIOS physical drive number. Floppy drives are
|
||||||
|
* identified as 0x00 and physical hard disks are identified as
|
||||||
|
* 0x80, regardless of the number of physical disk drives.
|
||||||
|
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||||
|
* call to specify the device to access. The value is only
|
||||||
|
* relevant if the device is a boot device.
|
||||||
|
*/
|
||||||
|
uint8_t driveNumber;
|
||||||
|
/** used by Windows NT - should be zero for FAT */
|
||||||
|
uint8_t reserved1;
|
||||||
|
/** 0X29 if next three fields are valid */
|
||||||
|
uint8_t bootSignature;
|
||||||
|
/**
|
||||||
|
* A random serial number created when formatting a disk,
|
||||||
|
* which helps to distinguish between disks.
|
||||||
|
* Usually generated by combining date and time.
|
||||||
|
*/
|
||||||
|
uint32_t volumeSerialNumber;
|
||||||
|
/**
|
||||||
|
* A field once used to store the volume label. The volume label
|
||||||
|
* is now stored as a special file in the root directory.
|
||||||
|
*/
|
||||||
|
char volumeLabel[11];
|
||||||
|
/**
|
||||||
|
* A text field with a value of FAT32.
|
||||||
|
*/
|
||||||
|
char fileSystemType[8];
|
||||||
|
/** X86 boot code */
|
||||||
|
uint8_t bootCode[420];
|
||||||
|
/** must be 0X55 */
|
||||||
|
uint8_t bootSectorSig0;
|
||||||
|
/** must be 0XAA */
|
||||||
|
uint8_t bootSectorSig1;
|
||||||
|
};
|
||||||
|
/** Type name for FAT32 Boot Sector */
|
||||||
|
typedef struct fat32_boot fat32_boot_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Lead signature for a FSINFO sector */
|
||||||
|
uint32_t const FSINFO_LEAD_SIG = 0x41615252;
|
||||||
|
/** Struct signature for a FSINFO sector */
|
||||||
|
uint32_t const FSINFO_STRUCT_SIG = 0x61417272;
|
||||||
|
/**
|
||||||
|
* \struct fat32_fsinfo
|
||||||
|
*
|
||||||
|
* \brief FSINFO sector for a FAT32 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat32_fsinfo {
|
||||||
|
/** must be 0X52, 0X52, 0X61, 0X41 */
|
||||||
|
uint32_t leadSignature;
|
||||||
|
/** must be zero */
|
||||||
|
uint8_t reserved1[480];
|
||||||
|
/** must be 0X72, 0X72, 0X41, 0X61 */
|
||||||
|
uint32_t structSignature;
|
||||||
|
/**
|
||||||
|
* Contains the last known free cluster count on the volume.
|
||||||
|
* If the value is 0xFFFFFFFF, then the free count is unknown
|
||||||
|
* and must be computed. Any other value can be used, but is
|
||||||
|
* not necessarily correct. It should be range checked at least
|
||||||
|
* to make sure it is <= volume cluster count.
|
||||||
|
*/
|
||||||
|
uint32_t freeCount;
|
||||||
|
/**
|
||||||
|
* This is a hint for the FAT driver. It indicates the cluster
|
||||||
|
* number at which the driver should start looking for free clusters.
|
||||||
|
* If the value is 0xFFFFFFFF, then there is no hint and the driver
|
||||||
|
* should start looking at cluster 2.
|
||||||
|
*/
|
||||||
|
uint32_t nextFree;
|
||||||
|
/** must be zero */
|
||||||
|
uint8_t reserved2[12];
|
||||||
|
/** must be 0X00, 0X00, 0X55, 0XAA */
|
||||||
|
uint8_t tailSignature[4];
|
||||||
|
};
|
||||||
|
/** Type name for FAT32 FSINFO Sector */
|
||||||
|
typedef struct fat32_fsinfo fat32_fsinfo_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// End Of Chain values for FAT entries
|
||||||
|
/** FAT12 end of chain value used by Microsoft. */
|
||||||
|
uint16_t const FAT12EOC = 0XFFF;
|
||||||
|
/** Minimum value for FAT12 EOC. Use to test for EOC. */
|
||||||
|
uint16_t const FAT12EOC_MIN = 0XFF8;
|
||||||
|
/** FAT16 end of chain value used by Microsoft. */
|
||||||
|
uint16_t const FAT16EOC = 0XFFFF;
|
||||||
|
/** Minimum value for FAT16 EOC. Use to test for EOC. */
|
||||||
|
uint16_t const FAT16EOC_MIN = 0XFFF8;
|
||||||
|
/** FAT32 end of chain value used by Microsoft. */
|
||||||
|
uint32_t const FAT32EOC = 0X0FFFFFFF;
|
||||||
|
/** Minimum value for FAT32 EOC. Use to test for EOC. */
|
||||||
|
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
|
||||||
|
/** Mask a for FAT32 entry. Entries are 28 bits. */
|
||||||
|
uint32_t const FAT32MASK = 0X0FFFFFFF;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct directoryEntry
|
||||||
|
* \brief FAT short directory entry
|
||||||
|
*
|
||||||
|
* Short means short 8.3 name, not the entry size.
|
||||||
|
*
|
||||||
|
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||||
|
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||||
|
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||||
|
* 16-bit word):
|
||||||
|
*
|
||||||
|
* Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||||
|
* inclusive (1980-2107).
|
||||||
|
*
|
||||||
|
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||||
|
*
|
||||||
|
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||||
|
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||||
|
* 16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||||
|
*
|
||||||
|
* Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||||
|
*
|
||||||
|
* The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||||
|
*/
|
||||||
|
struct directoryEntry {
|
||||||
|
/** Short 8.3 name.
|
||||||
|
*
|
||||||
|
* The first eight bytes contain the file name with blank fill.
|
||||||
|
* The last three bytes contain the file extension with blank fill.
|
||||||
|
*/
|
||||||
|
uint8_t name[11];
|
||||||
|
/** Entry attributes.
|
||||||
|
*
|
||||||
|
* The upper two bits of the attribute byte are reserved and should
|
||||||
|
* always be set to 0 when a file is created and never modified or
|
||||||
|
* looked at after that. See defines that begin with DIR_ATT_.
|
||||||
|
*/
|
||||||
|
uint8_t attributes;
|
||||||
|
/**
|
||||||
|
* Reserved for use by Windows NT. Set value to 0 when a file is
|
||||||
|
* created and never modify or look at it after that.
|
||||||
|
*/
|
||||||
|
uint8_t reservedNT;
|
||||||
|
/**
|
||||||
|
* The granularity of the seconds part of creationTime is 2 seconds
|
||||||
|
* so this field is a count of tenths of a second and its valid
|
||||||
|
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||||
|
*/
|
||||||
|
uint8_t creationTimeTenths;
|
||||||
|
/** Time file was created. */
|
||||||
|
uint16_t creationTime;
|
||||||
|
/** Date file was created. */
|
||||||
|
uint16_t creationDate;
|
||||||
|
/**
|
||||||
|
* Last access date. Note that there is no last access time, only
|
||||||
|
* a date. This is the date of last read or write. In the case of
|
||||||
|
* a write, this should be set to the same date as lastWriteDate.
|
||||||
|
*/
|
||||||
|
uint16_t lastAccessDate;
|
||||||
|
/**
|
||||||
|
* High word of this entry's first cluster number (always 0 for a
|
||||||
|
* FAT12 or FAT16 volume).
|
||||||
|
*/
|
||||||
|
uint16_t firstClusterHigh;
|
||||||
|
/** Time of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteTime;
|
||||||
|
/** Date of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteDate;
|
||||||
|
/** Low word of this entry's first cluster number. */
|
||||||
|
uint16_t firstClusterLow;
|
||||||
|
/** 32-bit unsigned holding this file's size in bytes. */
|
||||||
|
uint32_t fileSize;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Definitions for directory entries
|
||||||
|
//
|
||||||
|
/** Type name for directoryEntry */
|
||||||
|
typedef struct directoryEntry dir_t;
|
||||||
|
/** escape for name[0] = 0XE5 */
|
||||||
|
uint8_t const DIR_NAME_0XE5 = 0X05;
|
||||||
|
/** name[0] value for entry that is free after being "deleted" */
|
||||||
|
uint8_t const DIR_NAME_DELETED = 0XE5;
|
||||||
|
/** name[0] value for entry that is free and no allocated entries follow */
|
||||||
|
uint8_t const DIR_NAME_FREE = 0X00;
|
||||||
|
/** file is read-only */
|
||||||
|
uint8_t const DIR_ATT_READ_ONLY = 0X01;
|
||||||
|
/** File should hidden in directory listings */
|
||||||
|
uint8_t const DIR_ATT_HIDDEN = 0X02;
|
||||||
|
/** Entry is for a system file */
|
||||||
|
uint8_t const DIR_ATT_SYSTEM = 0X04;
|
||||||
|
/** Directory entry contains the volume label */
|
||||||
|
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
|
||||||
|
/** Entry is for a directory */
|
||||||
|
uint8_t const DIR_ATT_DIRECTORY = 0X10;
|
||||||
|
/** Old DOS archive bit for backup support */
|
||||||
|
uint8_t const DIR_ATT_ARCHIVE = 0X20;
|
||||||
|
/** Test value for long name entry. Test is
|
||||||
|
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
|
||||||
|
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
|
||||||
|
/** Test mask for long name entry */
|
||||||
|
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
|
||||||
|
/** defined attribute bits */
|
||||||
|
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
|
||||||
|
/** Directory entry is part of a long name
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for part of a long name else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||||
|
}
|
||||||
|
/** Mask for file/subdirectory tests */
|
||||||
|
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||||
|
/** Directory entry is for a file
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a normal file else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a subdirectory
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a subdirectory else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a file or subdirectory
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a normal file or subdirectory else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||||
|
}
|
||||||
|
#endif // SdFatStructs_h
|
275
arduino/floppyemu/SdFat/SdInfo.h
Executable file
275
arduino/floppyemu/SdFat/SdInfo.h
Executable file
|
@ -0,0 +1,275 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino Sd2Card Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino Sd2Card Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdInfo_h
|
||||||
|
#define SdInfo_h
|
||||||
|
#include <stdint.h>
|
||||||
|
// Based on the document:
|
||||||
|
//
|
||||||
|
// SD Specifications
|
||||||
|
// Part 1
|
||||||
|
// Physical Layer
|
||||||
|
// Simplified Specification
|
||||||
|
// Version 3.01
|
||||||
|
// May 18, 2010
|
||||||
|
//
|
||||||
|
// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card commands
|
||||||
|
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||||
|
uint8_t const CMD0 = 0X00;
|
||||||
|
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||||
|
uint8_t const CMD8 = 0X08;
|
||||||
|
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||||
|
uint8_t const CMD9 = 0X09;
|
||||||
|
/** SEND_CID - read the card identification information (CID register) */
|
||||||
|
uint8_t const CMD10 = 0X0A;
|
||||||
|
/** STOP_TRANSMISSION - end multiple block read sequence */
|
||||||
|
uint8_t const CMD12 = 0X0C;
|
||||||
|
/** SEND_STATUS - read the card status register */
|
||||||
|
uint8_t const CMD13 = 0X0D;
|
||||||
|
/** READ_SINGLE_BLOCK - read a single data block from the card */
|
||||||
|
uint8_t const CMD17 = 0X11;
|
||||||
|
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
|
||||||
|
uint8_t const CMD18 = 0X12;
|
||||||
|
/** WRITE_BLOCK - write a single data block to the card */
|
||||||
|
uint8_t const CMD24 = 0X18;
|
||||||
|
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||||
|
uint8_t const CMD25 = 0X19;
|
||||||
|
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||||
|
uint8_t const CMD32 = 0X20;
|
||||||
|
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||||
|
range to be erased*/
|
||||||
|
uint8_t const CMD33 = 0X21;
|
||||||
|
/** ERASE - erase all previously selected blocks */
|
||||||
|
uint8_t const CMD38 = 0X26;
|
||||||
|
/** APP_CMD - escape for application specific command */
|
||||||
|
uint8_t const CMD55 = 0X37;
|
||||||
|
/** READ_OCR - read the OCR register of a card */
|
||||||
|
uint8_t const CMD58 = 0X3A;
|
||||||
|
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||||
|
pre-erased before writing */
|
||||||
|
uint8_t const ACMD23 = 0X17;
|
||||||
|
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||||
|
activates the card's initialization process */
|
||||||
|
uint8_t const ACMD41 = 0X29;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** status for card in the ready state */
|
||||||
|
uint8_t const R1_READY_STATE = 0X00;
|
||||||
|
/** status for card in the idle state */
|
||||||
|
uint8_t const R1_IDLE_STATE = 0X01;
|
||||||
|
/** status bit for illegal command */
|
||||||
|
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
|
||||||
|
/** start data token for read or write single block*/
|
||||||
|
uint8_t const DATA_START_BLOCK = 0XFE;
|
||||||
|
/** stop token for write multiple blocks*/
|
||||||
|
uint8_t const STOP_TRAN_TOKEN = 0XFD;
|
||||||
|
/** start data token for write multiple blocks*/
|
||||||
|
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||||
|
/** mask for data response tokens after a write block operation */
|
||||||
|
uint8_t const DATA_RES_MASK = 0X1F;
|
||||||
|
/** write data accepted token */
|
||||||
|
uint8_t const DATA_RES_ACCEPTED = 0X05;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Card IDentification (CID) register */
|
||||||
|
typedef struct CID {
|
||||||
|
// byte 0
|
||||||
|
/** Manufacturer ID */
|
||||||
|
unsigned char mid;
|
||||||
|
// byte 1-2
|
||||||
|
/** OEM/Application ID */
|
||||||
|
char oid[2];
|
||||||
|
// byte 3-7
|
||||||
|
/** Product name */
|
||||||
|
char pnm[5];
|
||||||
|
// byte 8
|
||||||
|
/** Product revision least significant digit */
|
||||||
|
unsigned char prv_m : 4;
|
||||||
|
/** Product revision most significant digit */
|
||||||
|
unsigned char prv_n : 4;
|
||||||
|
// byte 9-12
|
||||||
|
/** Product serial number */
|
||||||
|
uint32_t psn;
|
||||||
|
// byte 13
|
||||||
|
/** Manufacturing date year low digit */
|
||||||
|
unsigned char mdt_year_high : 4;
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved : 4;
|
||||||
|
// byte 14
|
||||||
|
/** Manufacturing date month */
|
||||||
|
unsigned char mdt_month : 4;
|
||||||
|
/** Manufacturing date year low digit */
|
||||||
|
unsigned char mdt_year_low :4;
|
||||||
|
// byte 15
|
||||||
|
/** not used always 1 */
|
||||||
|
unsigned char always1 : 1;
|
||||||
|
/** CRC7 checksum */
|
||||||
|
unsigned char crc : 7;
|
||||||
|
}cid_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** CSD for version 1.00 cards */
|
||||||
|
typedef struct CSDV1 {
|
||||||
|
// byte 0
|
||||||
|
unsigned char reserved1 : 6;
|
||||||
|
unsigned char csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
unsigned char taac;
|
||||||
|
// byte 2
|
||||||
|
unsigned char nsac;
|
||||||
|
// byte 3
|
||||||
|
unsigned char tran_speed;
|
||||||
|
// byte 4
|
||||||
|
unsigned char ccc_high;
|
||||||
|
// byte 5
|
||||||
|
unsigned char read_bl_len : 4;
|
||||||
|
unsigned char ccc_low : 4;
|
||||||
|
// byte 6
|
||||||
|
unsigned char c_size_high : 2;
|
||||||
|
unsigned char reserved2 : 2;
|
||||||
|
unsigned char dsr_imp : 1;
|
||||||
|
unsigned char read_blk_misalign :1;
|
||||||
|
unsigned char write_blk_misalign : 1;
|
||||||
|
unsigned char read_bl_partial : 1;
|
||||||
|
// byte 7
|
||||||
|
unsigned char c_size_mid;
|
||||||
|
// byte 8
|
||||||
|
unsigned char vdd_r_curr_max : 3;
|
||||||
|
unsigned char vdd_r_curr_min : 3;
|
||||||
|
unsigned char c_size_low :2;
|
||||||
|
// byte 9
|
||||||
|
unsigned char c_size_mult_high : 2;
|
||||||
|
unsigned char vdd_w_cur_max : 3;
|
||||||
|
unsigned char vdd_w_curr_min : 3;
|
||||||
|
// byte 10
|
||||||
|
unsigned char sector_size_high : 6;
|
||||||
|
unsigned char erase_blk_en : 1;
|
||||||
|
unsigned char c_size_mult_low : 1;
|
||||||
|
// byte 11
|
||||||
|
unsigned char wp_grp_size : 7;
|
||||||
|
unsigned char sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
unsigned char write_bl_len_high : 2;
|
||||||
|
unsigned char r2w_factor : 3;
|
||||||
|
unsigned char reserved3 : 2;
|
||||||
|
unsigned char wp_grp_enable : 1;
|
||||||
|
// byte 13
|
||||||
|
unsigned char reserved4 : 5;
|
||||||
|
unsigned char write_partial : 1;
|
||||||
|
unsigned char write_bl_len_low : 2;
|
||||||
|
// byte 14
|
||||||
|
unsigned char reserved5: 2;
|
||||||
|
unsigned char file_format : 2;
|
||||||
|
unsigned char tmp_write_protect : 1;
|
||||||
|
unsigned char perm_write_protect : 1;
|
||||||
|
unsigned char copy : 1;
|
||||||
|
/** Indicates the file format on the card */
|
||||||
|
unsigned char file_format_grp : 1;
|
||||||
|
// byte 15
|
||||||
|
unsigned char always1 : 1;
|
||||||
|
unsigned char crc : 7;
|
||||||
|
}csd1_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** CSD for version 2.00 cards */
|
||||||
|
typedef struct CSDV2 {
|
||||||
|
// byte 0
|
||||||
|
unsigned char reserved1 : 6;
|
||||||
|
unsigned char csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
/** fixed to 0X0E */
|
||||||
|
unsigned char taac;
|
||||||
|
// byte 2
|
||||||
|
/** fixed to 0 */
|
||||||
|
unsigned char nsac;
|
||||||
|
// byte 3
|
||||||
|
unsigned char tran_speed;
|
||||||
|
// byte 4
|
||||||
|
unsigned char ccc_high;
|
||||||
|
// byte 5
|
||||||
|
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
|
||||||
|
unsigned char read_bl_len : 4;
|
||||||
|
unsigned char ccc_low : 4;
|
||||||
|
// byte 6
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved2 : 4;
|
||||||
|
unsigned char dsr_imp : 1;
|
||||||
|
/** fixed to 0 */
|
||||||
|
unsigned char read_blk_misalign :1;
|
||||||
|
/** fixed to 0 */
|
||||||
|
unsigned char write_blk_misalign : 1;
|
||||||
|
/** fixed to 0 - no partial read */
|
||||||
|
unsigned char read_bl_partial : 1;
|
||||||
|
// byte 7
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved3 : 2;
|
||||||
|
/** high part of card size */
|
||||||
|
unsigned char c_size_high : 6;
|
||||||
|
// byte 8
|
||||||
|
/** middle part of card size */
|
||||||
|
unsigned char c_size_mid;
|
||||||
|
// byte 9
|
||||||
|
/** low part of card size */
|
||||||
|
unsigned char c_size_low;
|
||||||
|
// byte 10
|
||||||
|
/** sector size is fixed at 64 KB */
|
||||||
|
unsigned char sector_size_high : 6;
|
||||||
|
/** fixed to 1 - erase single is supported */
|
||||||
|
unsigned char erase_blk_en : 1;
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved4 : 1;
|
||||||
|
// byte 11
|
||||||
|
unsigned char wp_grp_size : 7;
|
||||||
|
/** sector size is fixed at 64 KB */
|
||||||
|
unsigned char sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
/** write_bl_len fixed for 512 byte blocks */
|
||||||
|
unsigned char write_bl_len_high : 2;
|
||||||
|
/** fixed value of 2 */
|
||||||
|
unsigned char r2w_factor : 3;
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved5 : 2;
|
||||||
|
/** fixed value of 0 - no write protect groups */
|
||||||
|
unsigned char wp_grp_enable : 1;
|
||||||
|
// byte 13
|
||||||
|
unsigned char reserved6 : 5;
|
||||||
|
/** always zero - no partial block read*/
|
||||||
|
unsigned char write_partial : 1;
|
||||||
|
/** write_bl_len fixed for 512 byte blocks */
|
||||||
|
unsigned char write_bl_len_low : 2;
|
||||||
|
// byte 14
|
||||||
|
unsigned char reserved7: 2;
|
||||||
|
/** Do not use always 0 */
|
||||||
|
unsigned char file_format : 2;
|
||||||
|
unsigned char tmp_write_protect : 1;
|
||||||
|
unsigned char perm_write_protect : 1;
|
||||||
|
unsigned char copy : 1;
|
||||||
|
/** Do not use always 0 */
|
||||||
|
unsigned char file_format_grp : 1;
|
||||||
|
// byte 15
|
||||||
|
/** not used always 1 */
|
||||||
|
unsigned char always1 : 1;
|
||||||
|
/** checksum */
|
||||||
|
unsigned char crc : 7;
|
||||||
|
}csd2_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** union of old and new style CSD register */
|
||||||
|
union csd_t {
|
||||||
|
csd1_t v1;
|
||||||
|
csd2_t v2;
|
||||||
|
};
|
||||||
|
#endif // SdInfo_h
|
401
arduino/floppyemu/SdFat/SdVolume.cpp
Executable file
401
arduino/floppyemu/SdFat/SdVolume.cpp
Executable file
|
@ -0,0 +1,401 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <SdVolume.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if !USE_MULTIPLE_CARDS
|
||||||
|
// raw block cache
|
||||||
|
uint32_t SdVolume::cacheBlockNumber_; // current block number
|
||||||
|
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
||||||
|
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
|
||||||
|
bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
|
||||||
|
uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
|
||||||
|
#endif // USE_MULTIPLE_CARDS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// find a contiguous group of clusters
|
||||||
|
bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
|
||||||
|
// start of group
|
||||||
|
uint32_t bgnCluster;
|
||||||
|
// end of group
|
||||||
|
uint32_t endCluster;
|
||||||
|
// last cluster of FAT
|
||||||
|
uint32_t fatEnd = clusterCount_ + 1;
|
||||||
|
|
||||||
|
// flag to save place to start next search
|
||||||
|
bool setStart;
|
||||||
|
|
||||||
|
// set search start cluster
|
||||||
|
if (*curCluster) {
|
||||||
|
// try to make file contiguous
|
||||||
|
bgnCluster = *curCluster + 1;
|
||||||
|
|
||||||
|
// don't save new start location
|
||||||
|
setStart = false;
|
||||||
|
} else {
|
||||||
|
// start at likely place for free cluster
|
||||||
|
bgnCluster = allocSearchStart_;
|
||||||
|
|
||||||
|
// save next search start if one cluster
|
||||||
|
setStart = count == 1;
|
||||||
|
}
|
||||||
|
// end of group
|
||||||
|
endCluster = bgnCluster;
|
||||||
|
|
||||||
|
// search the FAT for free clusters
|
||||||
|
for (uint32_t n = 0;; n++, endCluster++) {
|
||||||
|
// can't find space checked all clusters
|
||||||
|
if (n >= clusterCount_) goto fail;
|
||||||
|
|
||||||
|
// past end - start from beginning of FAT
|
||||||
|
if (endCluster > fatEnd) {
|
||||||
|
bgnCluster = endCluster = 2;
|
||||||
|
}
|
||||||
|
uint32_t f;
|
||||||
|
if (!fatGet(endCluster, &f)) goto fail;
|
||||||
|
|
||||||
|
if (f != 0) {
|
||||||
|
// cluster in use try next cluster as bgnCluster
|
||||||
|
bgnCluster = endCluster + 1;
|
||||||
|
} else if ((endCluster - bgnCluster + 1) == count) {
|
||||||
|
// done - found space
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// mark end of chain
|
||||||
|
if (!fatPutEOC(endCluster)) goto fail;
|
||||||
|
|
||||||
|
// link clusters
|
||||||
|
while (endCluster > bgnCluster) {
|
||||||
|
if (!fatPut(endCluster - 1, endCluster)) goto fail;
|
||||||
|
endCluster--;
|
||||||
|
}
|
||||||
|
if (*curCluster != 0) {
|
||||||
|
// connect chains
|
||||||
|
if (!fatPut(*curCluster, bgnCluster)) goto fail;
|
||||||
|
}
|
||||||
|
// return first cluster number to caller
|
||||||
|
*curCluster = bgnCluster;
|
||||||
|
|
||||||
|
// remember possible next free cluster
|
||||||
|
if (setStart) allocSearchStart_ = bgnCluster + 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdVolume::cacheFlush() {
|
||||||
|
if (cacheDirty_) {
|
||||||
|
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// mirror FAT tables
|
||||||
|
if (cacheMirrorBlock_) {
|
||||||
|
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
cacheMirrorBlock_ = 0;
|
||||||
|
}
|
||||||
|
cacheDirty_ = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
|
||||||
|
if (cacheBlockNumber_ != blockNumber) {
|
||||||
|
if (!cacheFlush()) goto fail;
|
||||||
|
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
|
||||||
|
cacheBlockNumber_ = blockNumber;
|
||||||
|
}
|
||||||
|
if (dirty) cacheDirty_ = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// return the size in bytes of a cluster chain
|
||||||
|
bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
|
||||||
|
uint32_t s = 0;
|
||||||
|
do {
|
||||||
|
if (!fatGet(cluster, &cluster)) goto fail;
|
||||||
|
s += 512UL << clusterSizeShift_;
|
||||||
|
} while (!isEOC(cluster));
|
||||||
|
*size = s;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Fetch a FAT entry
|
||||||
|
bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
|
||||||
|
uint32_t lba;
|
||||||
|
if (cluster > (clusterCount_ + 1)) goto fail;
|
||||||
|
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||||
|
uint16_t index = cluster;
|
||||||
|
index += index >> 1;
|
||||||
|
lba = fatStartBlock_ + (index >> 9);
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
|
||||||
|
index &= 0X1FF;
|
||||||
|
uint16_t tmp = cacheBuffer_.data[index];
|
||||||
|
index++;
|
||||||
|
if (index == 512) {
|
||||||
|
if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
tmp |= cacheBuffer_.data[index] << 8;
|
||||||
|
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
lba = fatStartBlock_ + (cluster >> 8);
|
||||||
|
} else if (fatType_ == 32) {
|
||||||
|
lba = fatStartBlock_ + (cluster >> 7);
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (lba != cacheBlockNumber_) {
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
|
||||||
|
}
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
*value = cacheBuffer_.fat16[cluster & 0XFF];
|
||||||
|
} else {
|
||||||
|
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Store a FAT entry
|
||||||
|
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||||
|
uint32_t lba;
|
||||||
|
// error if reserved cluster
|
||||||
|
if (cluster < 2) goto fail;
|
||||||
|
|
||||||
|
// error if not in FAT
|
||||||
|
if (cluster > (clusterCount_ + 1)) goto fail;
|
||||||
|
|
||||||
|
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||||
|
uint16_t index = cluster;
|
||||||
|
index += index >> 1;
|
||||||
|
lba = fatStartBlock_ + (index >> 9);
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||||
|
// mirror second FAT
|
||||||
|
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||||
|
index &= 0X1FF;
|
||||||
|
uint8_t tmp = value;
|
||||||
|
if (cluster & 1) {
|
||||||
|
tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
|
||||||
|
}
|
||||||
|
cacheBuffer_.data[index] = tmp;
|
||||||
|
index++;
|
||||||
|
if (index == 512) {
|
||||||
|
lba++;
|
||||||
|
index = 0;
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||||
|
// mirror second FAT
|
||||||
|
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||||
|
}
|
||||||
|
tmp = value >> 4;
|
||||||
|
if (!(cluster & 1)) {
|
||||||
|
tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
|
||||||
|
}
|
||||||
|
cacheBuffer_.data[index] = tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
lba = fatStartBlock_ + (cluster >> 8);
|
||||||
|
} else if (fatType_ == 32) {
|
||||||
|
lba = fatStartBlock_ + (cluster >> 7);
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||||
|
// store entry
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
cacheBuffer_.fat16[cluster & 0XFF] = value;
|
||||||
|
} else {
|
||||||
|
cacheBuffer_.fat32[cluster & 0X7F] = value;
|
||||||
|
}
|
||||||
|
// mirror second FAT
|
||||||
|
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// free a cluster chain
|
||||||
|
bool SdVolume::freeChain(uint32_t cluster) {
|
||||||
|
uint32_t next;
|
||||||
|
|
||||||
|
// clear free cluster location
|
||||||
|
allocSearchStart_ = 2;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!fatGet(cluster, &next)) goto fail;
|
||||||
|
|
||||||
|
// free cluster
|
||||||
|
if (!fatPut(cluster, 0)) goto fail;
|
||||||
|
|
||||||
|
cluster = next;
|
||||||
|
} while (!isEOC(cluster));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Volume free space in clusters.
|
||||||
|
*
|
||||||
|
* \return Count of free clusters for success or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int32_t SdVolume::freeClusterCount() {
|
||||||
|
uint32_t free = 0;
|
||||||
|
uint16_t n;
|
||||||
|
uint32_t todo = clusterCount_ + 2;
|
||||||
|
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
n = 256;
|
||||||
|
} else if (fatType_ == 32) {
|
||||||
|
n = 128;
|
||||||
|
} else {
|
||||||
|
// put FAT12 here
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
|
||||||
|
if (todo < n) n = todo;
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
if (cacheBuffer_.fat16[i] == 0) free++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
if (cacheBuffer_.fat32[i] == 0) free++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return free;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Initialize a FAT volume.
|
||||||
|
*
|
||||||
|
* \param[in] dev The SD card where the volume is located.
|
||||||
|
*
|
||||||
|
* \param[in] part The partition to be used. Legal values for \a part are
|
||||||
|
* 1-4 to use the corresponding partition on a device formatted with
|
||||||
|
* a MBR, Master Boot Record, or zero if the device is formatted as
|
||||||
|
* a super floppy with the FAT boot sector in block zero.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure. Reasons for
|
||||||
|
* failure include not finding a valid partition, not finding a valid
|
||||||
|
* FAT file system in the specified partition or an I/O error.
|
||||||
|
*/
|
||||||
|
bool SdVolume::init(Sd2Card* dev, uint8_t part) {
|
||||||
|
uint32_t totalBlocks;
|
||||||
|
uint32_t volumeStartBlock = 0;
|
||||||
|
fat32_boot_t* fbs;
|
||||||
|
|
||||||
|
sdCard_ = dev;
|
||||||
|
fatType_ = 0;
|
||||||
|
allocSearchStart_ = 2;
|
||||||
|
cacheDirty_ = 0; // cacheFlush() will write block if true
|
||||||
|
cacheMirrorBlock_ = 0;
|
||||||
|
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||||
|
|
||||||
|
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||||
|
// if part > 0 assume mbr volume with partition table
|
||||||
|
if (part) {
|
||||||
|
if (part > 4)goto fail;
|
||||||
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
|
||||||
|
part_t* p = &cacheBuffer_.mbr.part[part-1];
|
||||||
|
if ((p->boot & 0X7F) !=0 ||
|
||||||
|
p->totalSectors < 100 ||
|
||||||
|
p->firstSector == 0) {
|
||||||
|
// not a valid partition
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
volumeStartBlock = p->firstSector;
|
||||||
|
}
|
||||||
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
|
||||||
|
fbs = &cacheBuffer_.fbs32;
|
||||||
|
if (fbs->bytesPerSector != 512 ||
|
||||||
|
fbs->fatCount == 0 ||
|
||||||
|
fbs->reservedSectorCount == 0 ||
|
||||||
|
fbs->sectorsPerCluster == 0) {
|
||||||
|
// not valid FAT volume
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
fatCount_ = fbs->fatCount;
|
||||||
|
blocksPerCluster_ = fbs->sectorsPerCluster;
|
||||||
|
// determine shift that is same as multiply by blocksPerCluster_
|
||||||
|
clusterSizeShift_ = 0;
|
||||||
|
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
|
||||||
|
// error if not power of 2
|
||||||
|
if (clusterSizeShift_++ > 7) goto fail;
|
||||||
|
}
|
||||||
|
blocksPerFat_ = fbs->sectorsPerFat16 ?
|
||||||
|
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
|
||||||
|
|
||||||
|
fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
|
||||||
|
|
||||||
|
// count for FAT16 zero for FAT32
|
||||||
|
rootDirEntryCount_ = fbs->rootDirEntryCount;
|
||||||
|
|
||||||
|
// directory start for FAT16 dataStart for FAT32
|
||||||
|
rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
|
||||||
|
|
||||||
|
// data start for FAT16 and FAT32
|
||||||
|
dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
|
||||||
|
|
||||||
|
// total blocks for FAT16 or FAT32
|
||||||
|
totalBlocks = fbs->totalSectors16 ?
|
||||||
|
fbs->totalSectors16 : fbs->totalSectors32;
|
||||||
|
// total data blocks
|
||||||
|
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||||
|
|
||||||
|
// divide by cluster size to get cluster count
|
||||||
|
clusterCount_ >>= clusterSizeShift_;
|
||||||
|
|
||||||
|
// FAT type is determined by cluster count
|
||||||
|
if (clusterCount_ < 4085) {
|
||||||
|
fatType_ = 12;
|
||||||
|
if (!FAT12_SUPPORT) goto fail;
|
||||||
|
} else if (clusterCount_ < 65525) {
|
||||||
|
fatType_ = 16;
|
||||||
|
} else {
|
||||||
|
rootDirStart_ = fbs->fat32RootCluster;
|
||||||
|
fatType_ = 32;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
211
arduino/floppyemu/SdFat/SdVolume.h
Executable file
211
arduino/floppyemu/SdFat/SdVolume.h
Executable file
|
@ -0,0 +1,211 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
*
|
||||||
|
* This file is part of the Arduino SdFat Library
|
||||||
|
*
|
||||||
|
* This Library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This Library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the Arduino SdFat Library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdVolume_h
|
||||||
|
#define SdVolume_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SdVolume class
|
||||||
|
*/
|
||||||
|
#include <SdFatConfig.h>
|
||||||
|
#include <Sd2Card.h>
|
||||||
|
#include <SdFatStructs.h>
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// SdVolume class
|
||||||
|
/**
|
||||||
|
* \brief Cache for an SD data block
|
||||||
|
*/
|
||||||
|
union cache_t {
|
||||||
|
/** Used to access cached file data blocks. */
|
||||||
|
uint8_t data[512];
|
||||||
|
/** Used to access cached FAT16 entries. */
|
||||||
|
uint16_t fat16[256];
|
||||||
|
/** Used to access cached FAT32 entries. */
|
||||||
|
uint32_t fat32[128];
|
||||||
|
/** Used to access cached directory entries. */
|
||||||
|
dir_t dir[16];
|
||||||
|
/** Used to access a cached Master Boot Record. */
|
||||||
|
mbr_t mbr;
|
||||||
|
/** Used to access to a cached FAT boot sector. */
|
||||||
|
fat_boot_t fbs;
|
||||||
|
/** Used to access to a cached FAT32 boot sector. */
|
||||||
|
fat32_boot_t fbs32;
|
||||||
|
/** Used to access to a cached FAT32 FSINFO sector. */
|
||||||
|
fat32_fsinfo_t fsinfo;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdVolume
|
||||||
|
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||||
|
*/
|
||||||
|
class SdVolume {
|
||||||
|
public:
|
||||||
|
/** Create an instance of SdVolume */
|
||||||
|
SdVolume() : fatType_(0) {}
|
||||||
|
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||||
|
* recorder to do raw write to the SD card. Not for normal apps.
|
||||||
|
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
cache_t* cacheClear() {
|
||||||
|
if (!cacheFlush()) return 0;
|
||||||
|
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||||
|
return &cacheBuffer_;
|
||||||
|
}
|
||||||
|
/** Initialize a FAT volume. Try partition one first then try super
|
||||||
|
* floppy format.
|
||||||
|
*
|
||||||
|
* \param[in] dev The Sd2Card where the volume is located.
|
||||||
|
*
|
||||||
|
* \return The value one, true, is returned for success and
|
||||||
|
* the value zero, false, is returned for failure. Reasons for
|
||||||
|
* failure include not finding a valid partition, not finding a valid
|
||||||
|
* FAT file system or an I/O error.
|
||||||
|
*/
|
||||||
|
bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
|
||||||
|
bool init(Sd2Card* dev, uint8_t part);
|
||||||
|
|
||||||
|
// inline functions that return volume info
|
||||||
|
/** \return The volume's cluster size in blocks. */
|
||||||
|
uint8_t blocksPerCluster() const {return blocksPerCluster_;}
|
||||||
|
/** \return The number of blocks in one FAT. */
|
||||||
|
uint32_t blocksPerFat() const {return blocksPerFat_;}
|
||||||
|
/** \return The total number of clusters in the volume. */
|
||||||
|
uint32_t clusterCount() const {return clusterCount_;}
|
||||||
|
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||||
|
uint8_t clusterSizeShift() const {return clusterSizeShift_;}
|
||||||
|
/** \return The logical block number for the start of file data. */
|
||||||
|
uint32_t dataStartBlock() const {return dataStartBlock_;}
|
||||||
|
/** \return The number of FAT structures on the volume. */
|
||||||
|
uint8_t fatCount() const {return fatCount_;}
|
||||||
|
/** \return The logical block number for the start of the first FAT. */
|
||||||
|
uint32_t fatStartBlock() const {return fatStartBlock_;}
|
||||||
|
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||||
|
uint8_t fatType() const {return fatType_;}
|
||||||
|
int32_t freeClusterCount();
|
||||||
|
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||||
|
uint32_t rootDirEntryCount() const {return rootDirEntryCount_;}
|
||||||
|
/** \return The logical block number for the start of the root directory
|
||||||
|
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||||
|
uint32_t rootDirStart() const {return rootDirStart_;}
|
||||||
|
/** Sd2Card object for this volume
|
||||||
|
* \return pointer to Sd2Card object.
|
||||||
|
*/
|
||||||
|
Sd2Card* sdCard() {return sdCard_;}
|
||||||
|
/** Debug access to FAT table
|
||||||
|
*
|
||||||
|
* \param[in] n cluster number.
|
||||||
|
* \param[out] v value of entry
|
||||||
|
* \return true for success or false for failure
|
||||||
|
*/
|
||||||
|
bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
private:
|
||||||
|
// Allow SdBaseFile access to SdVolume private data.
|
||||||
|
friend class SdBaseFile;
|
||||||
|
|
||||||
|
// value for dirty argument in cacheRawBlock to indicate read from cache
|
||||||
|
static bool const CACHE_FOR_READ = false;
|
||||||
|
// value for dirty argument in cacheRawBlock to indicate write to cache
|
||||||
|
static bool const CACHE_FOR_WRITE = true;
|
||||||
|
|
||||||
|
#if USE_MULTIPLE_CARDS
|
||||||
|
cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||||
|
uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||||
|
Sd2Card* sdCard_; // Sd2Card object for cache
|
||||||
|
bool cacheDirty_; // cacheFlush() will write block if true
|
||||||
|
uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||||
|
#else // USE_MULTIPLE_CARDS
|
||||||
|
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||||
|
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||||
|
static Sd2Card* sdCard_; // Sd2Card object for cache
|
||||||
|
static bool cacheDirty_; // cacheFlush() will write block if true
|
||||||
|
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||||
|
#endif // USE_MULTIPLE_CARDS
|
||||||
|
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||||
|
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||||
|
uint32_t blocksPerFat_; // FAT size in blocks
|
||||||
|
uint32_t clusterCount_; // clusters in one FAT
|
||||||
|
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||||
|
uint32_t dataStartBlock_; // first data block number
|
||||||
|
uint8_t fatCount_; // number of FATs on volume
|
||||||
|
uint32_t fatStartBlock_; // start block for first FAT
|
||||||
|
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||||
|
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||||
|
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool allocContiguous(uint32_t count, uint32_t* curCluster);
|
||||||
|
uint8_t blockOfCluster(uint32_t position) const {
|
||||||
|
return (position >> 9) & (blocksPerCluster_ - 1);}
|
||||||
|
uint32_t clusterStartBlock(uint32_t cluster) const {
|
||||||
|
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
|
||||||
|
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
|
||||||
|
return clusterStartBlock(cluster) + blockOfCluster(position);}
|
||||||
|
cache_t *cache() {return &cacheBuffer_;}
|
||||||
|
uint32_t cacheBlockNumber() {return cacheBlockNumber_;}
|
||||||
|
#if USE_MULTIPLE_CARDS
|
||||||
|
bool cacheFlush();
|
||||||
|
bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||||
|
#else // USE_MULTIPLE_CARDS
|
||||||
|
static bool cacheFlush();
|
||||||
|
static bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||||
|
#endif // USE_MULTIPLE_CARDS
|
||||||
|
// used by SdBaseFile write to assign cache to SD location
|
||||||
|
void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) {
|
||||||
|
cacheDirty_ = dirty;
|
||||||
|
cacheBlockNumber_ = blockNumber;
|
||||||
|
}
|
||||||
|
void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||||
|
bool chainSize(uint32_t beginCluster, uint32_t* size);
|
||||||
|
bool fatGet(uint32_t cluster, uint32_t* value);
|
||||||
|
bool fatPut(uint32_t cluster, uint32_t value);
|
||||||
|
bool fatPutEOC(uint32_t cluster) {
|
||||||
|
return fatPut(cluster, 0x0FFFFFFF);
|
||||||
|
}
|
||||||
|
bool freeChain(uint32_t cluster);
|
||||||
|
bool isEOC(uint32_t cluster) const {
|
||||||
|
if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN;
|
||||||
|
if (fatType_ == 16) return cluster >= FAT16EOC_MIN;
|
||||||
|
return cluster >= FAT32EOC_MIN;
|
||||||
|
}
|
||||||
|
bool readBlock(uint32_t block, uint8_t* dst) {
|
||||||
|
return sdCard_->readBlock(block, dst);}
|
||||||
|
bool writeBlock(uint32_t block, const uint8_t* dst) {
|
||||||
|
return sdCard_->writeBlock(block, dst);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||||
|
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
|
||||||
|
public:
|
||||||
|
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev);
|
||||||
|
* \param[in] dev The SD card where the volume is located.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool init(Sd2Card& dev) {return init(&dev);} // NOLINT
|
||||||
|
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol);
|
||||||
|
* \param[in] dev The SD card where the volume is located.
|
||||||
|
* \param[in] part The partition to be used.
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool init(Sd2Card& dev, uint8_t part) { // NOLINT
|
||||||
|
return init(&dev, part);
|
||||||
|
}
|
||||||
|
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
};
|
||||||
|
#endif // SdVolume
|
166
arduino/floppyemu/SdFat/examples/AnalogLogger/AnalogLogger.pde
Executable file
166
arduino/floppyemu/SdFat/examples/AnalogLogger/AnalogLogger.pde
Executable file
|
@ -0,0 +1,166 @@
|
||||||
|
// A simple data logger for the Arduino analog pins with optional DS1307
|
||||||
|
// uses RTClib from https://github.com/adafruit/RTClib
|
||||||
|
#include <SdFat.h>
|
||||||
|
#include <SdFatUtil.h> // define FreeRam()
|
||||||
|
|
||||||
|
#define CHIP_SELECT SS_PIN // SD chip select pin
|
||||||
|
#define USE_DS1307 0 // set nonzero to use DS1307 RTC
|
||||||
|
#define LOG_INTERVAL 1000 // mills between entries
|
||||||
|
#define SENSOR_COUNT 3 // number of analog pins to log
|
||||||
|
#define ECHO_TO_SERIAL 1 // echo data to serial port if nonzero
|
||||||
|
#define WAIT_TO_START 1 // Wait for serial input in setup()
|
||||||
|
#define ADC_DELAY 10 // ADC delay for high impedence sensors
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// text file for logging
|
||||||
|
ofstream logfile;
|
||||||
|
|
||||||
|
// Serial print stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
// buffer to format data - makes it eaiser to echo to Serial
|
||||||
|
char buf[80];
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if SENSOR_COUNT > 6
|
||||||
|
#error SENSOR_COUNT too large
|
||||||
|
#endif // SENSOR_COUNT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash to save RAM
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if USE_DS1307
|
||||||
|
// use RTClib from Adafruit
|
||||||
|
// https://github.com/adafruit/RTClib
|
||||||
|
|
||||||
|
// The Arduino IDE has a bug that causes Wire and RTClib to be loaded even
|
||||||
|
// if USE_DS1307 is false.
|
||||||
|
|
||||||
|
#error remove this line and uncomment the next two lines.
|
||||||
|
//#include <Wire.h>
|
||||||
|
//#include <RTClib.h>
|
||||||
|
RTC_DS1307 RTC; // define the Real Time Clock object
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// call back for file timestamps
|
||||||
|
void dateTime(uint16_t* date, uint16_t* time) {
|
||||||
|
DateTime now = RTC.now();
|
||||||
|
|
||||||
|
// return date using FAT_DATE macro to format fields
|
||||||
|
*date = FAT_DATE(now.year(), now.month(), now.day());
|
||||||
|
|
||||||
|
// return time using FAT_TIME macro to format fields
|
||||||
|
*time = FAT_TIME(now.hour(), now.minute(), now.second());
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format date/time
|
||||||
|
ostream& operator << (ostream& os, DateTime& dt) {
|
||||||
|
os << dt.year() << '/' << int(dt.month()) << '/' << int(dt.day()) << ',';
|
||||||
|
os << int(dt.hour()) << ':' << setfill('0') << setw(2) << int(dt.minute());
|
||||||
|
os << ':' << setw(2) << int(dt.second()) << setfill(' ');
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
#endif // USE_DS1307
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << endl << pstr("FreeRam: ") << FreeRam() << endl;
|
||||||
|
|
||||||
|
#if WAIT_TO_START
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
#endif // WAIT_TO_START
|
||||||
|
|
||||||
|
#if USE_DS1307
|
||||||
|
// connect to RTC
|
||||||
|
Wire.begin();
|
||||||
|
if (!RTC.begin()) error("RTC failed");
|
||||||
|
|
||||||
|
// set date time callback function
|
||||||
|
SdFile::dateTimeCallback(dateTime);
|
||||||
|
DateTime now = RTC.now();
|
||||||
|
cout << now << endl;
|
||||||
|
#endif // USE_DS1307
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
// if SD chip select is not SS, the second argument to init is CS pin number
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, CHIP_SELECT)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// create a new file in root, the current working directory
|
||||||
|
char name[] = "LOGGER00.CSV";
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 100; i++) {
|
||||||
|
name[6] = i/10 + '0';
|
||||||
|
name[7] = i%10 + '0';
|
||||||
|
if (sd.exists(name)) continue;
|
||||||
|
logfile.open(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!logfile.is_open()) error("file.open");
|
||||||
|
|
||||||
|
cout << pstr("Logging to: ") << name << endl;
|
||||||
|
|
||||||
|
// format header in buffer
|
||||||
|
obufstream bout(buf, sizeof(buf));
|
||||||
|
|
||||||
|
bout << pstr("millis");
|
||||||
|
|
||||||
|
#if USE_DS1307
|
||||||
|
bout << pstr(",date,time");
|
||||||
|
#endif // USE_DS1307
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
|
||||||
|
bout << pstr(",sens") << int(i);
|
||||||
|
}
|
||||||
|
logfile << buf << endl;
|
||||||
|
|
||||||
|
#if ECHO_TO_SERIAL
|
||||||
|
cout << buf << endl;
|
||||||
|
#endif // ECHO_TO_SERIAL
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {
|
||||||
|
uint32_t m;
|
||||||
|
|
||||||
|
// wait for time to be a multiple of interval
|
||||||
|
do {
|
||||||
|
m = millis();
|
||||||
|
} while (m % LOG_INTERVAL);
|
||||||
|
|
||||||
|
// use buffer stream to format line
|
||||||
|
obufstream bout(buf, sizeof(buf));
|
||||||
|
|
||||||
|
// start with time in millis
|
||||||
|
bout << m;
|
||||||
|
|
||||||
|
#if USE_DS1307
|
||||||
|
DateTime now = RTC.now();
|
||||||
|
bout << ',' << now;
|
||||||
|
#endif // USE_DS1307
|
||||||
|
|
||||||
|
// read analog pins and format data
|
||||||
|
for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
|
||||||
|
#if ADC_DELAY
|
||||||
|
analogRead(ia);
|
||||||
|
delay(ADC_DELAY);
|
||||||
|
#endif // ADC_DELAY
|
||||||
|
bout << ',' << analogRead(ia);
|
||||||
|
}
|
||||||
|
bout << endl;
|
||||||
|
|
||||||
|
// log data and flush to SD
|
||||||
|
logfile << buf << flush;
|
||||||
|
|
||||||
|
// check for error
|
||||||
|
if (!logfile) error("write data failed");
|
||||||
|
|
||||||
|
#if ECHO_TO_SERIAL
|
||||||
|
cout << buf;
|
||||||
|
#endif // ECHO_TO_SERIAL
|
||||||
|
|
||||||
|
// don't log two points in the same millis
|
||||||
|
if (m == millis()) delay(1);
|
||||||
|
}
|
11
arduino/floppyemu/SdFat/examples/HelloWorld/HelloWorld.pde
Executable file
11
arduino/floppyemu/SdFat/examples/HelloWorld/HelloWorld.pde
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// create a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
cout << "Hello, World!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {}
|
35
arduino/floppyemu/SdFat/examples/OpenNext/OpenNext.pde
Executable file
35
arduino/floppyemu/SdFat/examples/OpenNext/OpenNext.pde
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Open all files in the root dir and print their filename
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
SdFile file;
|
||||||
|
|
||||||
|
// define a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
char name[13];
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// open next file in root. The volume working directory, vwd, is root
|
||||||
|
while (file.openNext(sd.vwd(), O_READ)) {
|
||||||
|
file.getFilename(name);
|
||||||
|
cout << name << endl;
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
cout << "Done" << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
134
arduino/floppyemu/SdFat/examples/QuickStart/QuickStart.pde
Executable file
134
arduino/floppyemu/SdFat/examples/QuickStart/QuickStart.pde
Executable file
|
@ -0,0 +1,134 @@
|
||||||
|
// Quick hardware test
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// Test with reduced SPI speed for breadboards.
|
||||||
|
// Change spiSpeed to SPI_FULL_SPEED for better performance
|
||||||
|
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
|
||||||
|
const uint8_t spiSpeed = SPI_HALF_SPEED;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Normally SdFat is used in applications in place
|
||||||
|
// of Sd2Card, SdVolume, and SdFile for root.
|
||||||
|
Sd2Card card;
|
||||||
|
SdVolume volume;
|
||||||
|
SdFile root;
|
||||||
|
|
||||||
|
// Serial streams
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
// input buffer for line
|
||||||
|
char cinBuf[40];
|
||||||
|
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
|
||||||
|
|
||||||
|
// Change the value of chipSelect if your hardware does
|
||||||
|
// not use the default value, SS_PIN. Common values are:
|
||||||
|
// Arduino Ethernet shield: pin 4
|
||||||
|
// Sparkfun SD shield: pin 8
|
||||||
|
// Adafruit SD shields and modules: pin 10
|
||||||
|
int chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
void cardOrSpeed() {
|
||||||
|
cout << pstr(
|
||||||
|
"Try another SD card or reduce the SPI bus speed.\n"
|
||||||
|
"The current SPI speed is: ");
|
||||||
|
uint8_t divisor = 1;
|
||||||
|
for (uint8_t i = 0; i < spiSpeed; i++) divisor *= 2;
|
||||||
|
cout << F_CPU * 0.5e-6 / divisor << pstr(" MHz\n");
|
||||||
|
cout << pstr("Edit spiSpeed in this sketch to change it.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void reformatMsg() {
|
||||||
|
cout << pstr("Try reformatting the card. For best results use\n");
|
||||||
|
cout << pstr("the SdFormatter sketch in SdFat/examples or download\n");
|
||||||
|
cout << pstr("and use SDFormatter from www.sdcard.org/consumer.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
cout << pstr(
|
||||||
|
"SD chip select is the key hardware option.\n"
|
||||||
|
"Common values are:\n"
|
||||||
|
"Arduino Ethernet shield, pin 4\n"
|
||||||
|
"Sparkfun SD shield, pin 8\n"
|
||||||
|
"Adafruit SD shields and modules, pin 10\n"
|
||||||
|
"The default chip select pin number is pin ");
|
||||||
|
cout << int(SS_PIN) << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool firstTry = true;
|
||||||
|
void loop() {
|
||||||
|
// read any existing Serial data
|
||||||
|
while (Serial.read() >= 0) {}
|
||||||
|
|
||||||
|
if (!firstTry) cout << pstr("\nRestarting\n");
|
||||||
|
firstTry = false;
|
||||||
|
|
||||||
|
cout << pstr("\nEnter the chip select pin number: ");
|
||||||
|
cin.readline();
|
||||||
|
if (cin >> chipSelect) {
|
||||||
|
cout << chipSelect << endl;
|
||||||
|
} else {
|
||||||
|
cout << pstr("\nInvalid pin number\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!card.init(spiSpeed, chipSelect)) {
|
||||||
|
cout << pstr(
|
||||||
|
"\nSD initialization failed.\n"
|
||||||
|
"Do not reformat the card!\n"
|
||||||
|
"Is the card correctly inserted?\n"
|
||||||
|
"Is chipSelect set to the correct value?\n"
|
||||||
|
"Is there a wiring/soldering problem?\n");
|
||||||
|
cout << pstr("errorCode: ") << hex << showbase << int(card.errorCode());
|
||||||
|
cout << pstr(", errorData: ") << int(card.errorData());
|
||||||
|
cout << dec << noshowbase << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cout << pstr("\nCard successfully initialized.\n");
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
uint32_t size = card.cardSize();
|
||||||
|
if (size == 0) {
|
||||||
|
cout << pstr("Can't determine the card size.\n");
|
||||||
|
cardOrSpeed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t sizeMB = 0.000512 * size + 0.5;
|
||||||
|
cout << pstr("Card size: ") << sizeMB;
|
||||||
|
cout << pstr(" MB (MB = 1,000,000 bytes)\n");
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
if (!volume.init(&card)) {
|
||||||
|
if (card.errorCode()) {
|
||||||
|
cout << pstr("Can't read the card.\n");
|
||||||
|
cardOrSpeed();
|
||||||
|
} else {
|
||||||
|
cout << pstr("Can't find a valid FAT16/FAT32 partition.\n");
|
||||||
|
reformatMsg();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cout << pstr("Volume is FAT") << int(volume.fatType());
|
||||||
|
cout << pstr(", Cluster size (bytes): ") << 512L * volume.blocksPerCluster();
|
||||||
|
cout << endl << endl;
|
||||||
|
|
||||||
|
root.close();
|
||||||
|
if (!root.openRoot(&volume)) {
|
||||||
|
cout << pstr("Can't open root directory.\n");
|
||||||
|
reformatMsg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cout << pstr("Files found (name date time size):\n");
|
||||||
|
root.ls(LS_R | LS_DATE | LS_SIZE);
|
||||||
|
|
||||||
|
if ((sizeMB > 1100 && volume.blocksPerCluster() < 64)
|
||||||
|
|| (sizeMB < 2200 && volume.fatType() == 32)) {
|
||||||
|
cout << pstr("\nThis card should be reformatted for best performance.\n");
|
||||||
|
cout << pstr("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
|
||||||
|
cout << pstr("Only cards larger than 2 GB should be formatted FAT32.\n");
|
||||||
|
reformatMsg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// read any existing Serial data
|
||||||
|
while (Serial.read() >= 0) {}
|
||||||
|
cout << pstr("\nSuccess! Type any character to restart.\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
}
|
64
arduino/floppyemu/SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.pde
Executable file
64
arduino/floppyemu/SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.pde
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
// Ported to SdFat from the native Arduino SD library example by Bill Greiman
|
||||||
|
// On the Ethernet Shield, CS is pin 4. SdFat handles setting SS
|
||||||
|
const int chipSelect = 4;
|
||||||
|
/*
|
||||||
|
SD card read/write
|
||||||
|
|
||||||
|
This example shows how to read and write data to and from an SD card file
|
||||||
|
The circuit:
|
||||||
|
* SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4
|
||||||
|
|
||||||
|
created Nov 2010
|
||||||
|
by David A. Mellis
|
||||||
|
updated 2 Dec 2010
|
||||||
|
by Tom Igoe
|
||||||
|
modified by Bill Greiman 11 Apr 2011
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
SdFat sd;
|
||||||
|
SdFile myFile;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// Initialize SdFat or print a detailed error message and halt
|
||||||
|
// Use half speed like the native library.
|
||||||
|
// change to SPI_FULL_SPEED for more performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// open the file for write at end like the Native SD library
|
||||||
|
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
|
||||||
|
sd.errorHalt("opening test.txt for write failed");
|
||||||
|
}
|
||||||
|
// if the file opened okay, write to it:
|
||||||
|
Serial.print("Writing to test.txt...");
|
||||||
|
myFile.println("testing 1, 2, 3.");
|
||||||
|
|
||||||
|
// close the file:
|
||||||
|
myFile.close();
|
||||||
|
Serial.println("done.");
|
||||||
|
|
||||||
|
// re-open the file for reading:
|
||||||
|
if (!myFile.open("test.txt", O_READ)) {
|
||||||
|
sd.errorHalt("opening test.txt for read failed");
|
||||||
|
}
|
||||||
|
Serial.println("test.txt:");
|
||||||
|
|
||||||
|
// read from the file until there's nothing else in it:
|
||||||
|
int data;
|
||||||
|
while ((data = myFile.read()) > 0) Serial.write(data);
|
||||||
|
// close the file:
|
||||||
|
myFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing happens after setup
|
||||||
|
}
|
||||||
|
|
||||||
|
|
23
arduino/floppyemu/SdFat/examples/SD_Size/SD_Size.pde
Executable file
23
arduino/floppyemu/SdFat/examples/SD_Size/SD_Size.pde
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Sketch to compare size of Arduino SD library with SdFat V2.
|
||||||
|
* See SdFatSize.pde for SdFat sketch.
|
||||||
|
*/
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
File file;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
if (!SD.begin()) {
|
||||||
|
Serial.println("begin failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file = SD.open("TEST_SD.TXT", FILE_WRITE);
|
||||||
|
|
||||||
|
file.println("Hello");
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
25
arduino/floppyemu/SdFat/examples/SdFatSize/SdFatSize.pde
Executable file
25
arduino/floppyemu/SdFat/examples/SdFatSize/SdFatSize.pde
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Sketch to compare size of SdFat V2 with Arduino SD library.
|
||||||
|
* See SD_Size.pde for Arduino SD sketch.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
SdFile file;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
if (!sd.init()) {
|
||||||
|
Serial.println("init failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file.open("SIZE_TST.TXT", O_RDWR | O_CREAT | O_AT_END);
|
||||||
|
|
||||||
|
file.println("Hello");
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
478
arduino/floppyemu/SdFat/examples/SdFormatter/SdFormatter.pde
Executable file
478
arduino/floppyemu/SdFat/examples/SdFormatter/SdFormatter.pde
Executable file
|
@ -0,0 +1,478 @@
|
||||||
|
/*
|
||||||
|
* This sketch will format an SD or SDHC card.
|
||||||
|
* Warning all data will be deleted!
|
||||||
|
*
|
||||||
|
* For SD/SDHC cards larger than 64 MB this
|
||||||
|
* sketch attempts to match the format
|
||||||
|
* generated by SDFormatter available here:
|
||||||
|
*
|
||||||
|
* http://www.sdcard.org/consumers/formatter/
|
||||||
|
*
|
||||||
|
* For smaller cards this sketch uses FAT16
|
||||||
|
* and SDFormatter uses FAT12.
|
||||||
|
*/
|
||||||
|
// Print extra info for debug if DEBUG_PRINT is nonzero
|
||||||
|
#define DEBUG_PRINT 0
|
||||||
|
#include <SdFat.h>
|
||||||
|
#if DEBUG_PRINT
|
||||||
|
#include <SdFatUtil.h>
|
||||||
|
#endif // DEBUG_PRINT
|
||||||
|
//
|
||||||
|
// Change the value of chipSelect if your hardware does
|
||||||
|
// not use the default value, SS_PIN. Common values are:
|
||||||
|
// Arduino Ethernet shield: pin 4
|
||||||
|
// Sparkfun SD shield: pin 8
|
||||||
|
// Adafruit SD shields and modules: pin 10
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// Change spiSpeed to SPI_FULL_SPEED for better performance
|
||||||
|
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
|
||||||
|
const uint8_t spiSpeed = SPI_HALF_SPEED;
|
||||||
|
|
||||||
|
// Serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
Sd2Card card;
|
||||||
|
uint32_t cardSizeBlocks;
|
||||||
|
uint16_t cardCapacityMB;
|
||||||
|
|
||||||
|
// cache for SD block
|
||||||
|
cache_t cache;
|
||||||
|
|
||||||
|
// MBR information
|
||||||
|
uint8_t partType;
|
||||||
|
uint32_t relSector;
|
||||||
|
uint32_t partSize;
|
||||||
|
|
||||||
|
// Fake disk geometry
|
||||||
|
uint8_t numberOfHeads;
|
||||||
|
uint8_t sectorsPerTrack;
|
||||||
|
|
||||||
|
// FAT parameters
|
||||||
|
uint16_t reservedSectors;
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
uint32_t fatStart;
|
||||||
|
uint32_t fatSize;
|
||||||
|
uint32_t dataStart;
|
||||||
|
|
||||||
|
// constants for file system structure
|
||||||
|
uint16_t const BU16 = 128;
|
||||||
|
uint16_t const BU32 = 8192;
|
||||||
|
|
||||||
|
// strings needed in file system structures
|
||||||
|
char noName[] = "NO NAME ";
|
||||||
|
char fat16str[] = "FAT16 ";
|
||||||
|
char fat32str[] = "FAT32 ";
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#define sdError(msg) sdError_P(PSTR(msg))
|
||||||
|
|
||||||
|
void sdError_P(const char* str) {
|
||||||
|
cout << pstr("error: ");
|
||||||
|
cout << pgm(str) << endl;
|
||||||
|
if (card.errorCode()) {
|
||||||
|
cout << pstr("SD error: ") << hex << int(card.errorCode());
|
||||||
|
cout << ',' << int(card.errorData()) << dec << endl;
|
||||||
|
}
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if DEBUG_PRINT
|
||||||
|
void debugPrint() {
|
||||||
|
cout << pstr("FreeRam: ") << FreeRam() << endl;
|
||||||
|
cout << pstr("partStart: ") << relSector << endl;
|
||||||
|
cout << pstr("partSize: ") << partSize << endl;
|
||||||
|
cout << pstr("reserved: ") << reservedSectors << endl;
|
||||||
|
cout << pstr("fatStart: ") << fatStart << endl;
|
||||||
|
cout << pstr("fatSize: ") << fatSize << endl;
|
||||||
|
cout << pstr("dataStart: ") << dataStart << endl;
|
||||||
|
cout << pstr("clusterCount: ");
|
||||||
|
cout << ((relSector + partSize - dataStart)/sectorsPerCluster) << endl;
|
||||||
|
cout << endl;
|
||||||
|
cout << pstr("Heads: ") << int(numberOfHeads) << endl;
|
||||||
|
cout << pstr("Sectors: ") << int(sectorsPerTrack) << endl;
|
||||||
|
cout << pstr("Cylinders: ");
|
||||||
|
cout << cardSizeBlocks/(numberOfHeads*sectorsPerTrack) << endl;
|
||||||
|
}
|
||||||
|
#endif // DEBUG_PRINT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// write cached block to the card
|
||||||
|
uint8_t writeCache(uint32_t lbn) {
|
||||||
|
return card.writeBlock(lbn, cache.data);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// initialize appropriate sizes for SD capacity
|
||||||
|
void initSizes() {
|
||||||
|
if (cardCapacityMB <= 6) {
|
||||||
|
sdError("Card is too small.");
|
||||||
|
} else if (cardCapacityMB <= 16) {
|
||||||
|
sectorsPerCluster = 2;
|
||||||
|
} else if (cardCapacityMB <= 32) {
|
||||||
|
sectorsPerCluster = 4;
|
||||||
|
} else if (cardCapacityMB <= 64) {
|
||||||
|
sectorsPerCluster = 8;
|
||||||
|
} else if (cardCapacityMB <= 128) {
|
||||||
|
sectorsPerCluster = 16;
|
||||||
|
} else if (cardCapacityMB <= 1024) {
|
||||||
|
sectorsPerCluster = 32;
|
||||||
|
} else {
|
||||||
|
sectorsPerCluster = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << pstr("Blocks/Cluster: ") << int(sectorsPerCluster) << endl;
|
||||||
|
// set fake disk geometry
|
||||||
|
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
|
||||||
|
|
||||||
|
if (cardCapacityMB <= 16) {
|
||||||
|
numberOfHeads = 2;
|
||||||
|
} else if (cardCapacityMB <= 32) {
|
||||||
|
numberOfHeads = 4;
|
||||||
|
} else if (cardCapacityMB <= 128) {
|
||||||
|
numberOfHeads = 8;
|
||||||
|
} else if (cardCapacityMB <= 504) {
|
||||||
|
numberOfHeads = 16;
|
||||||
|
} else if (cardCapacityMB <= 1008) {
|
||||||
|
numberOfHeads = 32;
|
||||||
|
} else if (cardCapacityMB <= 2016) {
|
||||||
|
numberOfHeads = 64;
|
||||||
|
} else if (cardCapacityMB <= 4032) {
|
||||||
|
numberOfHeads = 128;
|
||||||
|
} else {
|
||||||
|
numberOfHeads = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// zero cache and optionally set the sector signature
|
||||||
|
void clearCache(uint8_t addSig) {
|
||||||
|
memset(&cache, 0, sizeof(cache));
|
||||||
|
if (addSig) {
|
||||||
|
cache.mbr.mbrSig0 = BOOTSIG0;
|
||||||
|
cache.mbr.mbrSig1 = BOOTSIG1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// zero FAT and root dir area on SD
|
||||||
|
void clearFatDir(uint32_t bgn, uint32_t count) {
|
||||||
|
clearCache(false);
|
||||||
|
if (!card.writeStart(bgn, count)) {
|
||||||
|
sdError("Clear FAT/DIR writeStart failed");
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
if ((i & 0XFF) == 0) cout << '.';
|
||||||
|
if (!card.writeData(cache.data)) {
|
||||||
|
sdError("Clear FAT/DIR writeData failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!card.writeStop()) {
|
||||||
|
sdError("Clear FAT/DIR writeStop failed");
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// return cylinder number for a logical block number
|
||||||
|
uint16_t lbnToCylinder(uint32_t lbn) {
|
||||||
|
return lbn / (numberOfHeads * sectorsPerTrack);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// return head number for a logical block number
|
||||||
|
uint8_t lbnToHead(uint32_t lbn) {
|
||||||
|
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// return sector number for a logical block number
|
||||||
|
uint8_t lbnToSector(uint32_t lbn) {
|
||||||
|
return (lbn % sectorsPerTrack) + 1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format and write the Master Boot Record
|
||||||
|
void writeMbr() {
|
||||||
|
clearCache(true);
|
||||||
|
part_t* p = cache.mbr.part;
|
||||||
|
p->boot = 0;
|
||||||
|
uint16_t c = lbnToCylinder(relSector);
|
||||||
|
if (c > 1023) sdError("MBR CHS");
|
||||||
|
p->beginCylinderHigh = c >> 8;
|
||||||
|
p->beginCylinderLow = c & 0XFF;
|
||||||
|
p->beginHead = lbnToHead(relSector);
|
||||||
|
p->beginSector = lbnToSector(relSector);
|
||||||
|
p->type = partType;
|
||||||
|
uint32_t endLbn = relSector + partSize - 1;
|
||||||
|
c = lbnToCylinder(endLbn);
|
||||||
|
if (c <= 1023) {
|
||||||
|
p->endCylinderHigh = c >> 8;
|
||||||
|
p->endCylinderLow = c & 0XFF;
|
||||||
|
p->endHead = lbnToHead(endLbn);
|
||||||
|
p->endSector = lbnToSector(endLbn);
|
||||||
|
} else {
|
||||||
|
// Too big flag, c = 1023, h = 254, s = 63
|
||||||
|
p->endCylinderHigh = 3;
|
||||||
|
p->endCylinderLow = 255;
|
||||||
|
p->endHead = 254;
|
||||||
|
p->endSector = 63;
|
||||||
|
}
|
||||||
|
p->firstSector = relSector;
|
||||||
|
p->totalSectors = partSize;
|
||||||
|
if (!writeCache(0)) sdError("write MBR");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// generate serial number from card size and micros since boot
|
||||||
|
uint32_t volSerialNumber() {
|
||||||
|
return (cardSizeBlocks << 8) + micros();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format the SD as FAT16
|
||||||
|
void makeFat16() {
|
||||||
|
uint32_t nc;
|
||||||
|
for (dataStart = 2 * BU16;; dataStart += BU16) {
|
||||||
|
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
|
||||||
|
fatSize = (nc + 2 + 255)/256;
|
||||||
|
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
|
||||||
|
if (dataStart < r) continue;
|
||||||
|
relSector = dataStart - r + BU16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check valid cluster count for FAT16 volume
|
||||||
|
if (nc < 4085 || nc >= 65525) sdError("Bad cluster count");
|
||||||
|
reservedSectors = 1;
|
||||||
|
fatStart = relSector + reservedSectors;
|
||||||
|
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
|
||||||
|
if (partSize < 32680) {
|
||||||
|
partType = 0X01;
|
||||||
|
} else if (partSize < 65536) {
|
||||||
|
partType = 0X04;
|
||||||
|
} else {
|
||||||
|
partType = 0X06;
|
||||||
|
}
|
||||||
|
// write MBR
|
||||||
|
writeMbr();
|
||||||
|
clearCache(true);
|
||||||
|
fat_boot_t* pb = &cache.fbs;
|
||||||
|
pb->jump[0] = 0XEB;
|
||||||
|
pb->jump[1] = 0X00;
|
||||||
|
pb->jump[2] = 0X90;
|
||||||
|
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
||||||
|
pb->oemId[i] = ' ';
|
||||||
|
}
|
||||||
|
pb->bytesPerSector = 512;
|
||||||
|
pb->sectorsPerCluster = sectorsPerCluster;
|
||||||
|
pb->reservedSectorCount = reservedSectors;
|
||||||
|
pb->fatCount = 2;
|
||||||
|
pb->rootDirEntryCount = 512;
|
||||||
|
pb->mediaType = 0XF8;
|
||||||
|
pb->sectorsPerFat16 = fatSize;
|
||||||
|
pb->sectorsPerTrack = sectorsPerTrack;
|
||||||
|
pb->headCount = numberOfHeads;
|
||||||
|
pb->hidddenSectors = relSector;
|
||||||
|
pb->totalSectors32 = partSize;
|
||||||
|
pb->driveNumber = 0X80;
|
||||||
|
pb->bootSignature = EXTENDED_BOOT_SIG;
|
||||||
|
pb->volumeSerialNumber = volSerialNumber();
|
||||||
|
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
|
||||||
|
memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType));
|
||||||
|
// write partition boot sector
|
||||||
|
if (!writeCache(relSector)) {
|
||||||
|
sdError("FAT16 write PBS failed");
|
||||||
|
}
|
||||||
|
// clear FAT and root directory
|
||||||
|
clearFatDir(fatStart, dataStart - fatStart);
|
||||||
|
clearCache(false);
|
||||||
|
cache.fat16[0] = 0XFFF8;
|
||||||
|
cache.fat16[1] = 0XFFFF;
|
||||||
|
// write first block of FAT and backup for reserved clusters
|
||||||
|
if (!writeCache(fatStart)
|
||||||
|
|| !writeCache(fatStart + fatSize)) {
|
||||||
|
sdError("FAT16 reserve failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format the SD as FAT32
|
||||||
|
void makeFat32() {
|
||||||
|
uint32_t nc;
|
||||||
|
relSector = BU32;
|
||||||
|
for (dataStart = 2 * BU32;; dataStart += BU32) {
|
||||||
|
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
|
||||||
|
fatSize = (nc + 2 + 127)/128;
|
||||||
|
uint32_t r = relSector + 9 + 2 * fatSize;
|
||||||
|
if (dataStart >= r) break;
|
||||||
|
}
|
||||||
|
// error if too few clusters in FAT32 volume
|
||||||
|
if (nc < 65525) sdError("Bad cluster count");
|
||||||
|
reservedSectors = dataStart - relSector - 2 * fatSize;
|
||||||
|
fatStart = relSector + reservedSectors;
|
||||||
|
partSize = nc * sectorsPerCluster + dataStart - relSector;
|
||||||
|
// type depends on address of end sector
|
||||||
|
// max CHS has lbn = 16450560 = 1024*255*63
|
||||||
|
if ((relSector + partSize) <= 16450560) {
|
||||||
|
// FAT32
|
||||||
|
partType = 0X0B;
|
||||||
|
} else {
|
||||||
|
// FAT32 with INT 13
|
||||||
|
partType = 0X0C;
|
||||||
|
}
|
||||||
|
writeMbr();
|
||||||
|
clearCache(true);
|
||||||
|
|
||||||
|
fat32_boot_t* pb = &cache.fbs32;
|
||||||
|
pb->jump[0] = 0XEB;
|
||||||
|
pb->jump[1] = 0X00;
|
||||||
|
pb->jump[2] = 0X90;
|
||||||
|
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
||||||
|
pb->oemId[i] = ' ';
|
||||||
|
}
|
||||||
|
pb->bytesPerSector = 512;
|
||||||
|
pb->sectorsPerCluster = sectorsPerCluster;
|
||||||
|
pb->reservedSectorCount = reservedSectors;
|
||||||
|
pb->fatCount = 2;
|
||||||
|
pb->mediaType = 0XF8;
|
||||||
|
pb->sectorsPerTrack = sectorsPerTrack;
|
||||||
|
pb->headCount = numberOfHeads;
|
||||||
|
pb->hidddenSectors = relSector;
|
||||||
|
pb->totalSectors32 = partSize;
|
||||||
|
pb->sectorsPerFat32 = fatSize;
|
||||||
|
pb->fat32RootCluster = 2;
|
||||||
|
pb->fat32FSInfo = 1;
|
||||||
|
pb->fat32BackBootBlock = 6;
|
||||||
|
pb->driveNumber = 0X80;
|
||||||
|
pb->bootSignature = EXTENDED_BOOT_SIG;
|
||||||
|
pb->volumeSerialNumber = volSerialNumber();
|
||||||
|
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
|
||||||
|
memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
|
||||||
|
// write partition boot sector and backup
|
||||||
|
if (!writeCache(relSector)
|
||||||
|
|| !writeCache(relSector + 6)) {
|
||||||
|
sdError("FAT32 write PBS failed");
|
||||||
|
}
|
||||||
|
clearCache(true);
|
||||||
|
// write extra boot area and backup
|
||||||
|
if (!writeCache(relSector + 2)
|
||||||
|
|| !writeCache(relSector + 8)) {
|
||||||
|
sdError("FAT32 PBS ext failed");
|
||||||
|
}
|
||||||
|
fat32_fsinfo_t* pf = &cache.fsinfo;
|
||||||
|
pf->leadSignature = FSINFO_LEAD_SIG;
|
||||||
|
pf->structSignature = FSINFO_STRUCT_SIG;
|
||||||
|
pf->freeCount = 0XFFFFFFFF;
|
||||||
|
pf->nextFree = 0XFFFFFFFF;
|
||||||
|
// write FSINFO sector and backup
|
||||||
|
if (!writeCache(relSector + 1)
|
||||||
|
|| !writeCache(relSector + 7)) {
|
||||||
|
sdError("FAT32 FSINFO failed");
|
||||||
|
}
|
||||||
|
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
|
||||||
|
clearCache(false);
|
||||||
|
cache.fat32[0] = 0x0FFFFFF8;
|
||||||
|
cache.fat32[1] = 0x0FFFFFFF;
|
||||||
|
cache.fat32[2] = 0x0FFFFFFF;
|
||||||
|
// write first block of FAT and backup for reserved clusters
|
||||||
|
if (!writeCache(fatStart)
|
||||||
|
|| !writeCache(fatStart + fatSize)) {
|
||||||
|
sdError("FAT32 reserve failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// flash erase all data
|
||||||
|
uint32_t const ERASE_SIZE = 262144L;
|
||||||
|
void eraseCard() {
|
||||||
|
cout << endl << pstr("Erasing\n");
|
||||||
|
uint32_t firstBlock = 0;
|
||||||
|
uint32_t lastBlock;
|
||||||
|
uint16_t n = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
lastBlock = firstBlock + ERASE_SIZE - 1;
|
||||||
|
if (lastBlock >= cardSizeBlocks) lastBlock = cardSizeBlocks - 1;
|
||||||
|
if (!card.erase(firstBlock, lastBlock)) sdError("erase failed");
|
||||||
|
cout << '.';
|
||||||
|
if ((n++)%32 == 31) cout << endl;
|
||||||
|
firstBlock += ERASE_SIZE;
|
||||||
|
} while (firstBlock < cardSizeBlocks);
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
if (!card.readBlock(0, cache.data)) sdError("readBlock");
|
||||||
|
cout << hex << showbase << setfill('0') << internal;
|
||||||
|
cout << pstr("All data set to ") << setw(4) << int(cache.data[0]) << endl;
|
||||||
|
cout << dec << noshowbase << setfill(' ') << right;
|
||||||
|
cout << pstr("Erase done\n");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void formatCard() {
|
||||||
|
cout << endl;
|
||||||
|
cout << pstr("Formatting\n");
|
||||||
|
initSizes();
|
||||||
|
if (card.type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
cout << pstr("FAT16\n");
|
||||||
|
makeFat16();
|
||||||
|
} else {
|
||||||
|
cout << pstr("FAT32\n");
|
||||||
|
makeFat32();
|
||||||
|
}
|
||||||
|
#if DEBUG_PRINT
|
||||||
|
debugPrint();
|
||||||
|
#endif // DEBUG_PRINT
|
||||||
|
cout << pstr("Format done\n");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
char c;
|
||||||
|
Serial.begin(9600);
|
||||||
|
cout << pstr(
|
||||||
|
"This sketch can erase and/or format SD/SDHC cards.\n"
|
||||||
|
"\n"
|
||||||
|
"Erase uses the card's fast flash erase command.\n"
|
||||||
|
"Flash erase sets all data to 0X00 for most cards\n"
|
||||||
|
"and 0XFF for a few vendor's cards.\n"
|
||||||
|
"\n"
|
||||||
|
"Cards larger than 2 GB will be formatted FAT32 and\n"
|
||||||
|
"smaller cards will be formatted FAT16.\n"
|
||||||
|
"\n"
|
||||||
|
"Warning, all data on the card will be erased.\n"
|
||||||
|
"Enter 'Y' to continue: ");
|
||||||
|
while (!Serial.available()) {}
|
||||||
|
c = Serial.read();
|
||||||
|
cout << c << endl;
|
||||||
|
if (c != 'Y') {
|
||||||
|
cout << pstr("Quiting, you did not enter 'Y'.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// read any existing Serial data
|
||||||
|
while (Serial.read() >= 0) {}
|
||||||
|
|
||||||
|
cout << pstr(
|
||||||
|
"\n"
|
||||||
|
"Options are:\n"
|
||||||
|
"E - erase the card and skip formatting.\n"
|
||||||
|
"F - erase and then format the card. (recommended)\n"
|
||||||
|
"Q - quick format the card without erase.\n"
|
||||||
|
"\n"
|
||||||
|
"Enter option: ");
|
||||||
|
|
||||||
|
while (!Serial.available()) {}
|
||||||
|
c = Serial.read();
|
||||||
|
cout << c << endl;
|
||||||
|
if (!strchr("EFQ", c)) {
|
||||||
|
cout << pstr("Quiting, invalid option entered.") << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!card.init(spiSpeed, chipSelect)) {
|
||||||
|
cout << pstr(
|
||||||
|
"\nSD initialization failure!\n"
|
||||||
|
"Is the SD card inserted correctly?\n"
|
||||||
|
"Is chip select correct at the top of this sketch?\n");
|
||||||
|
sdError("card.init failed");
|
||||||
|
}
|
||||||
|
cardSizeBlocks = card.cardSize();
|
||||||
|
if (cardSizeBlocks == 0) sdError("cardSize");
|
||||||
|
cardCapacityMB = (cardSizeBlocks + 2047)/2048;
|
||||||
|
|
||||||
|
cout << pstr("Card Size: ") << cardCapacityMB;
|
||||||
|
cout << pstr(" MB, (MB = 1,048,576 bytes)") << endl;
|
||||||
|
|
||||||
|
if (c == 'E' || c == 'F') {
|
||||||
|
eraseCard();
|
||||||
|
}
|
||||||
|
if (c == 'F' || c == 'Q') {
|
||||||
|
formatCard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
174
arduino/floppyemu/SdFat/examples/SdInfo/SdInfo.pde
Executable file
174
arduino/floppyemu/SdFat/examples/SdInfo/SdInfo.pde
Executable file
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* This sketch attempts to initialize an SD card and analyze its structure.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
/*
|
||||||
|
* SD chip select pin. Common values are:
|
||||||
|
*
|
||||||
|
* Arduino Ethernet shield, pin 4.
|
||||||
|
* SparkFun SD shield, pin 8.
|
||||||
|
* Adafruit SD shields and modules, pin 10.
|
||||||
|
* Default SD chip select is the SPI SS pin.
|
||||||
|
*/
|
||||||
|
const uint8_t SdChipSelect = SS_PIN;
|
||||||
|
|
||||||
|
Sd2Card card;
|
||||||
|
SdVolume vol;
|
||||||
|
|
||||||
|
// serial output steam
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
// global for card erase size
|
||||||
|
uint32_t eraseSize;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash
|
||||||
|
#define sdErrorMsg(msg) sdErrorMsg_P(PSTR(msg));
|
||||||
|
void sdErrorMsg_P(const char* str) {
|
||||||
|
cout << pgm(str) << endl;
|
||||||
|
if (card.errorCode()) {
|
||||||
|
cout << pstr("SD errorCode: ");
|
||||||
|
cout << hex << int(card.errorCode()) << endl;
|
||||||
|
cout << pstr("SD errorData: ");
|
||||||
|
cout << int(card.errorData()) << dec << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint8_t cidDmp() {
|
||||||
|
cid_t cid;
|
||||||
|
if (!card.readCID(&cid)) {
|
||||||
|
sdErrorMsg("readCID failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cout << pstr("\nManufacturer ID: ");
|
||||||
|
cout << hex << int(cid.mid) << dec << endl;
|
||||||
|
cout << pstr("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
|
||||||
|
cout << pstr("Product: ");
|
||||||
|
for (uint8_t i = 0; i < 5; i++) {
|
||||||
|
cout << cid.pnm[i];
|
||||||
|
}
|
||||||
|
cout << pstr("\nVersion: ");
|
||||||
|
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
|
||||||
|
cout << pstr("Serial number: ") << cid.psn << endl;
|
||||||
|
cout << pstr("Manufacturing date: ");
|
||||||
|
cout << int(cid.mdt_month) << '/';
|
||||||
|
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
|
||||||
|
cout << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint8_t csdDmp() {
|
||||||
|
csd_t csd;
|
||||||
|
uint8_t eraseSingleBlock;
|
||||||
|
uint32_t cardSize = card.cardSize();
|
||||||
|
if (cardSize == 0 || !card.readCSD(&csd)) {
|
||||||
|
sdErrorMsg("readCSD failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (csd.v1.csd_ver == 0) {
|
||||||
|
eraseSingleBlock = csd.v1.erase_blk_en;
|
||||||
|
eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
|
||||||
|
} else if (csd.v2.csd_ver == 1) {
|
||||||
|
eraseSingleBlock = csd.v2.erase_blk_en;
|
||||||
|
eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
|
||||||
|
} else {
|
||||||
|
cout << pstr("csd version error\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eraseSize++;
|
||||||
|
cout << pstr("cardSize: ") << cardSize << pstr(" (512 byte blocks)\n");
|
||||||
|
cout << pstr("flashEraseSize: ") << int(eraseSize) << pstr(" blocks\n");
|
||||||
|
cout << pstr("eraseSingleBlock: ");
|
||||||
|
if (eraseSingleBlock) {
|
||||||
|
cout << pstr("true\n");
|
||||||
|
} else {
|
||||||
|
cout << pstr("false\n");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// print partition table
|
||||||
|
uint8_t partDmp() {
|
||||||
|
cache_t *p = vol.cacheClear();
|
||||||
|
if (!card.readBlock(0, p->data)) {
|
||||||
|
sdErrorMsg("read MBR failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cout << pstr("\nSD Partition Table\n");
|
||||||
|
cout << pstr("part,boot,type,start,length\n");
|
||||||
|
for (uint8_t ip = 1; ip < 5; ip++) {
|
||||||
|
part_t *pt = &p->mbr.part[ip - 1];
|
||||||
|
cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
|
||||||
|
cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void volDmp() {
|
||||||
|
cout << pstr("\nVolume is FAT") << int(vol.fatType()) << endl;
|
||||||
|
cout << pstr("blocksPerCluster: ") << int(vol.blocksPerCluster()) << endl;
|
||||||
|
cout << pstr("clusterCount: ") << vol.clusterCount() << endl;
|
||||||
|
cout << pstr("freeClusters: ") << vol.freeClusterCount() << endl;
|
||||||
|
cout << pstr("fatStartBlock: ") << vol.fatStartBlock() << endl;
|
||||||
|
cout << pstr("fatCount: ") << int(vol.fatCount()) << endl;
|
||||||
|
cout << pstr("blocksPerFat: ") << vol.blocksPerFat() << endl;
|
||||||
|
cout << pstr("rootDirStart: ") << vol.rootDirStart() << endl;
|
||||||
|
cout << pstr("dataStartBlock: ") << vol.dataStartBlock() << endl;
|
||||||
|
if (vol.dataStartBlock() % eraseSize) {
|
||||||
|
cout << pstr("Data area is not aligned on flash erase boundaries!\n");
|
||||||
|
cout << pstr("Download and use formatter from www.sdcard.org/consumer!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// use uppercase in hex and use 0X base prefix
|
||||||
|
cout << uppercase << showbase << endl;
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("SdFat version: ") << SD_FAT_VERSION << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {
|
||||||
|
// read any existing Serial data
|
||||||
|
while (Serial.read() >= 0) {}
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("\ntype any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
uint32_t t = millis();
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!card.init(SPI_HALF_SPEED, SdChipSelect)) {
|
||||||
|
sdErrorMsg("\ncard.init failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = millis() - t;
|
||||||
|
cout << pstr("\ninit time: ") << t << " ms" << endl;
|
||||||
|
cout << pstr("\nCard type: ");
|
||||||
|
switch (card.type()) {
|
||||||
|
case SD_CARD_TYPE_SD1:
|
||||||
|
cout << pstr("SD1\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_CARD_TYPE_SD2:
|
||||||
|
cout << pstr("SD2\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_CARD_TYPE_SDHC:
|
||||||
|
cout << pstr("SDHC\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cout << pstr("Unknown\n");
|
||||||
|
}
|
||||||
|
if (!cidDmp()) return;
|
||||||
|
if (!csdDmp()) return;
|
||||||
|
if (!partDmp()) return;
|
||||||
|
if (!vol.init(&card)) {
|
||||||
|
sdErrorMsg("\nvol.init failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
volDmp();
|
||||||
|
}
|
137
arduino/floppyemu/SdFat/examples/TwoCards/TwoCards.pde
Executable file
137
arduino/floppyemu/SdFat/examples/TwoCards/TwoCards.pde
Executable file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Example use of two SD cards.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
#include <SdFatUtil.h>
|
||||||
|
#if !USE_MULTIPLE_CARDS
|
||||||
|
#error You must set USE_MULTIPLE_CARDS nonzero in SdFatConfig.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SdFat sd1;
|
||||||
|
const uint8_t SD1_CS = 10; // chip select for sd1
|
||||||
|
|
||||||
|
SdFat sd2;
|
||||||
|
const uint8_t SD2_CS = 9; // chip select for sd2
|
||||||
|
|
||||||
|
const uint8_t BUF_DIM = 100;
|
||||||
|
uint8_t buf[BUF_DIM];
|
||||||
|
|
||||||
|
const uint32_t FILE_SIZE = 1000000;
|
||||||
|
const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// print error msg, any SD error codes, and halt.
|
||||||
|
// store messages in flash
|
||||||
|
#define errorExit(msg) errorHalt_P(PSTR(msg))
|
||||||
|
#define initError(msg) initErrorHalt_P(PSTR(msg))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
PgmPrint("FreeRam: ");
|
||||||
|
Serial.println(FreeRam());
|
||||||
|
|
||||||
|
// fill buffer with known data
|
||||||
|
for (int i = 0; i < sizeof(buf); i++) buf[i] = i;
|
||||||
|
|
||||||
|
PgmPrintln("type any character to start");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// disable sd2 while initializing sd1
|
||||||
|
pinMode(SD2_CS, OUTPUT);
|
||||||
|
digitalWrite(SD2_CS, HIGH);
|
||||||
|
|
||||||
|
// initialize the first card
|
||||||
|
if (!sd1.init(SPI_FULL_SPEED, SD1_CS)) {
|
||||||
|
sd1.initError("sd1:");
|
||||||
|
}
|
||||||
|
// create DIR1 on sd1 if it does not exist
|
||||||
|
if (!sd1.exists("/DIR1")) {
|
||||||
|
if (!sd1.mkdir("/DIR1")) sd1.errorExit("sd1.mkdir");
|
||||||
|
}
|
||||||
|
// initialize the second card
|
||||||
|
if (!sd2.init(SPI_FULL_SPEED, SD2_CS)) {
|
||||||
|
sd2.initError("sd2:");
|
||||||
|
}
|
||||||
|
// create DIR2 on sd2 if it does not exist
|
||||||
|
if (!sd2.exists("/DIR2")) {
|
||||||
|
if (!sd2.mkdir("/DIR2")) sd2.errorExit("sd2.mkdir");
|
||||||
|
}
|
||||||
|
// list root directory on both cards
|
||||||
|
PgmPrintln("------sd1 root-------");
|
||||||
|
sd1.ls();
|
||||||
|
PgmPrintln("------sd2 root-------");
|
||||||
|
sd2.ls();
|
||||||
|
|
||||||
|
// make /DIR1 the default directory for sd1
|
||||||
|
if (!sd1.chdir("/DIR1")) sd1.errorExit("sd1.chdir");
|
||||||
|
|
||||||
|
// make /DIR2 the default directory for sd2
|
||||||
|
if (!sd2.chdir("/DIR2")) sd2.errorExit("sd2.chdir");
|
||||||
|
|
||||||
|
// list current directory on both cards
|
||||||
|
PgmPrintln("------sd1 DIR1-------");
|
||||||
|
sd1.ls();
|
||||||
|
PgmPrintln("------sd2 DIR2-------");
|
||||||
|
sd2.ls();
|
||||||
|
PgmPrintln("---------------------");
|
||||||
|
|
||||||
|
// remove RENAME.BIN from /DIR2 directory of sd2
|
||||||
|
if (sd2.exists("RENAME.BIN")) {
|
||||||
|
if (!sd2.remove("RENAME.BIN")) {
|
||||||
|
sd2.errorExit("remove RENAME.BIN");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set the current working directory for open() to sd1
|
||||||
|
sd1.chvol();
|
||||||
|
|
||||||
|
// create or open /DIR1/TEST.BIN and truncate it to zero length
|
||||||
|
SdFile file1;
|
||||||
|
if (!file1.open("TEST.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
|
||||||
|
sd1.errorExit("file1");
|
||||||
|
}
|
||||||
|
PgmPrintln("Writing TEST.BIN to sd1");
|
||||||
|
|
||||||
|
// write data to /DIR1/TEST.BIN on sd1
|
||||||
|
for (int i = 0; i < NWRITE; i++) {
|
||||||
|
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
|
sd1.errorExit("sd1.write");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set the current working directory for open() to sd2
|
||||||
|
sd2.chvol();
|
||||||
|
|
||||||
|
// create or open /DIR2/COPY.BIN and truncate it to zero length
|
||||||
|
SdFile file2;
|
||||||
|
if (!file2.open("COPY.BIN", O_WRITE | O_CREAT | O_TRUNC)) {
|
||||||
|
sd2.errorExit("file2");
|
||||||
|
}
|
||||||
|
PgmPrintln("Copying TEST.BIN to COPY.BIN");
|
||||||
|
|
||||||
|
// copy file1 to file2
|
||||||
|
file1.rewind();
|
||||||
|
uint32_t t = millis();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int n = file1.read(buf, sizeof(buf));
|
||||||
|
if (n < 0) sd1.errorExit("read1");
|
||||||
|
if (n == 0) break;
|
||||||
|
if (file2.write(buf, n) != n) sd2.errorExit("write2");
|
||||||
|
}
|
||||||
|
t = millis() - t;
|
||||||
|
PgmPrint("File size: ");
|
||||||
|
Serial.println(file2.fileSize());
|
||||||
|
PgmPrint("Copy time: ");
|
||||||
|
Serial.print(t);
|
||||||
|
PgmPrintln(" millis");
|
||||||
|
|
||||||
|
// close TEST.BIN
|
||||||
|
file1.close();
|
||||||
|
|
||||||
|
// rename the copy
|
||||||
|
file2.close();
|
||||||
|
if (!sd2.rename("COPY.BIN", "RENAME.BIN")) {
|
||||||
|
sd2.errorExit("sd2.rename");
|
||||||
|
}
|
||||||
|
PgmPrintln("Done");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
61
arduino/floppyemu/SdFat/examples/append/append.pde
Executable file
61
arduino/floppyemu/SdFat/examples/append/append.pde
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Append Example
|
||||||
|
*
|
||||||
|
* This sketch shows how to use open for append.
|
||||||
|
* The sketch will append 100 line each time it opens the file.
|
||||||
|
* The sketch will open and close the file 100 times.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// create Serial stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
// store error strings in flash to save RAM
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
// filename for this example
|
||||||
|
char name[] = "APPEND.TXT";
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr() stores strings in flash to save RAM
|
||||||
|
cout << endl << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
cout << pstr("Appending to: ") << name;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 100; i++) {
|
||||||
|
// open stream for append
|
||||||
|
ofstream sdout(name, ios::out | ios::app);
|
||||||
|
if (!sdout) error("open failed");
|
||||||
|
|
||||||
|
// append 100 lines to the file
|
||||||
|
for (uint8_t j = 0; j < 100; j++) {
|
||||||
|
// use int() so byte will print as decimal number
|
||||||
|
sdout << "line " << int(j) << " of pass " << int(i);
|
||||||
|
sdout << " millis = " << millis() << endl;
|
||||||
|
}
|
||||||
|
// close the stream
|
||||||
|
sdout.close();
|
||||||
|
|
||||||
|
if (!sdout) error("append data failed");
|
||||||
|
|
||||||
|
// output progress indicator
|
||||||
|
if (i % 25 == 0) cout << endl;
|
||||||
|
cout << '.';
|
||||||
|
}
|
||||||
|
cout << endl << "Done" << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
68
arduino/floppyemu/SdFat/examples/average/average.pde
Executable file
68
arduino/floppyemu/SdFat/examples/average/average.pde
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Calculate the sum and average of a list of floating point numbers
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// object for the SD file system
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// define a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void writeTestFile() {
|
||||||
|
// open the output file
|
||||||
|
ofstream sdout("AVG_TEST.TXT");
|
||||||
|
|
||||||
|
// write a series of float numbers
|
||||||
|
for (int16_t i = -1001; i < 2000; i += 13) {
|
||||||
|
sdout << 0.1 * i << endl;
|
||||||
|
}
|
||||||
|
if (!sdout) sd.errorHalt("sdout failed");
|
||||||
|
|
||||||
|
// file will be closed by destructor when sdout goes out of scope
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void calcAverage() {
|
||||||
|
uint16_t n = 0; // count of input numbers
|
||||||
|
double num; // current input number
|
||||||
|
double sum = 0; // sum of input numbers
|
||||||
|
|
||||||
|
// open the input file
|
||||||
|
ifstream sdin("AVG_TEST.TXT");
|
||||||
|
|
||||||
|
// check for an open failure
|
||||||
|
if (!sdin) sd.errorHalt("sdin failed");
|
||||||
|
|
||||||
|
// read and sum the numbers
|
||||||
|
while (sdin >> num) {
|
||||||
|
n++;
|
||||||
|
sum += num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the results
|
||||||
|
cout << "sum of " << n << " numbers = " << sum << endl;
|
||||||
|
cout << "average = " << sum/n << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// write the test file
|
||||||
|
writeTestFile();
|
||||||
|
|
||||||
|
// read the test file and calculate the average
|
||||||
|
calcAverage();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
103
arduino/floppyemu/SdFat/examples/bench/bench.pde
Executable file
103
arduino/floppyemu/SdFat/examples/bench/bench.pde
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* This sketch is a simple binary write/read benchmark.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
#include <SdFatUtil.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
#define FILE_SIZE_MB 5
|
||||||
|
#define FILE_SIZE (1000000UL*FILE_SIZE_MB)
|
||||||
|
#define BUF_SIZE 100
|
||||||
|
|
||||||
|
uint8_t buf[BUF_SIZE];
|
||||||
|
|
||||||
|
// file system
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// test file
|
||||||
|
SdFile file;
|
||||||
|
|
||||||
|
// Serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash to save RAM
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
uint32_t maxLatency;
|
||||||
|
uint32_t totalLatency;
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
cout << pstr("Free RAM: ") << FreeRam() << endl;
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||||
|
// try SPI_HALF_SPEED if bus errors occur.
|
||||||
|
if (!sd.init(SPI_FULL_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
cout << pstr("Type is FAT") << int(sd.vol()->fatType()) << endl;
|
||||||
|
|
||||||
|
// open or create file - truncate existing file.
|
||||||
|
if (!file.open("BENCH.DAT", O_CREAT | O_TRUNC | O_RDWR)) {
|
||||||
|
error("open failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill buf with known data
|
||||||
|
for (uint16_t i = 0; i < (BUF_SIZE-2); i++) {
|
||||||
|
buf[i] = 'A' + (i % 26);
|
||||||
|
}
|
||||||
|
buf[BUF_SIZE-2] = '\r';
|
||||||
|
buf[BUF_SIZE-1] = '\n';
|
||||||
|
|
||||||
|
cout << pstr("File size ") << FILE_SIZE_MB << pstr("MB\n");
|
||||||
|
|
||||||
|
cout << pstr("Starting write test. Please wait up to a minute\n");
|
||||||
|
|
||||||
|
// do write test
|
||||||
|
uint32_t n = FILE_SIZE/sizeof(buf);
|
||||||
|
maxLatency = 0;
|
||||||
|
totalLatency = 0;
|
||||||
|
uint32_t t = millis();
|
||||||
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
|
uint32_t m = micros();
|
||||||
|
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
|
error("write failed");
|
||||||
|
}
|
||||||
|
m = micros() - m;
|
||||||
|
if (maxLatency < m) maxLatency = m;
|
||||||
|
totalLatency += m;
|
||||||
|
}
|
||||||
|
file.sync();
|
||||||
|
t = millis() - t;
|
||||||
|
double s = file.fileSize();
|
||||||
|
cout << pstr("Write ") << s/t << pstr(" KB/sec\n");
|
||||||
|
cout << pstr("Maximum latency: ") << maxLatency;
|
||||||
|
cout << pstr(" usec, Avg Latency: ") << totalLatency/n << pstr(" usec\n\n");
|
||||||
|
cout << pstr("Starting read test. Please wait up to a minute\n");
|
||||||
|
// do read test
|
||||||
|
file.rewind();
|
||||||
|
maxLatency = 0;
|
||||||
|
totalLatency = 0;
|
||||||
|
t = millis();
|
||||||
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
|
uint32_t m = micros();
|
||||||
|
if (file.read(buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
|
error("read failed");
|
||||||
|
}
|
||||||
|
m = micros() - m;
|
||||||
|
if (maxLatency < m) maxLatency = m;
|
||||||
|
totalLatency += m;
|
||||||
|
}
|
||||||
|
t = millis() - t;
|
||||||
|
cout << pstr("Read ") << s/t << pstr(" KB/sec\n");
|
||||||
|
cout << pstr("Maximum latency: ") << maxLatency;
|
||||||
|
cout << pstr(" usec, Avg Latency: ") << totalLatency/n << pstr(" usec\n\n");
|
||||||
|
cout << pstr("Done\n");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() { }
|
31
arduino/floppyemu/SdFat/examples/bufstream/bufstream.pde
Executable file
31
arduino/floppyemu/SdFat/examples/bufstream/bufstream.pde
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Use of ibufsteam to parse a line and obufstream to format a line
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// create a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
char buf[20]; // buffer for formatted line
|
||||||
|
int i, j, k; // values from parsed line
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize input string
|
||||||
|
ibufstream bin("123 456 789");
|
||||||
|
|
||||||
|
// parse the string "123 456 789"
|
||||||
|
bin >> i >> j >> k;
|
||||||
|
|
||||||
|
// initialize output buffer
|
||||||
|
obufstream bout(buf, sizeof(buf));
|
||||||
|
|
||||||
|
// format the output string
|
||||||
|
bout << k << ',' << j << ',' << i << endl;
|
||||||
|
|
||||||
|
// write the string to serial
|
||||||
|
cout << buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {}
|
33
arduino/floppyemu/SdFat/examples/cin_cout/cin_cout.pde
Executable file
33
arduino/floppyemu/SdFat/examples/cin_cout/cin_cout.pde
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Demo of ArduinoInStream and ArduinoOutStream
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// create serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
// input buffer for line
|
||||||
|
char cinBuf[40];
|
||||||
|
|
||||||
|
// create serial input stream
|
||||||
|
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {
|
||||||
|
int32_t n;
|
||||||
|
|
||||||
|
cout << "enter an integer\n";
|
||||||
|
|
||||||
|
cin.readline();
|
||||||
|
|
||||||
|
if (cin >> n) {
|
||||||
|
cout << "The number is: " << n << endl;
|
||||||
|
} else {
|
||||||
|
// will fail if no digits or not in range [-2147483648, 2147483647]
|
||||||
|
cout << "Invalid input: " << cinBuf << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
51
arduino/floppyemu/SdFat/examples/eventlog/eventlog.pde
Executable file
51
arduino/floppyemu/SdFat/examples/eventlog/eventlog.pde
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Append a line to a file - demo of pathnames and streams
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// define a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
* Append a line to LOGFILE.TXT
|
||||||
|
*/
|
||||||
|
void logEvent(const char *msg) {
|
||||||
|
// create dir if needed
|
||||||
|
sd.mkdir("LOGS/2011/JAN");
|
||||||
|
|
||||||
|
// create or open a file for append
|
||||||
|
ofstream sdlog("LOGS/2011/JAN/LOGFILE.TXT", ios::out | ios::app);
|
||||||
|
|
||||||
|
// append a line to the file
|
||||||
|
sdlog << msg << endl;
|
||||||
|
|
||||||
|
// check for errors
|
||||||
|
if (!sdlog) sd.errorHalt("append failed");
|
||||||
|
|
||||||
|
// file will be closed when sdlog goes out of scope
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// append a line to the logfile
|
||||||
|
logEvent("Another line for the logfile");
|
||||||
|
|
||||||
|
cout << "Done - check /LOGS/2011/JAN/LOGFILE.TXT on the SD" << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
66
arduino/floppyemu/SdFat/examples/fgets/fgets.pde
Executable file
66
arduino/floppyemu/SdFat/examples/fgets/fgets.pde
Executable file
|
@ -0,0 +1,66 @@
|
||||||
|
// Demo of fgets function to read lines from a file.
|
||||||
|
#include <SdFat.h>
|
||||||
|
SdFat sd;
|
||||||
|
// print stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash memory
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void demoFgets() {
|
||||||
|
char line[25];
|
||||||
|
int n;
|
||||||
|
// open test file
|
||||||
|
SdFile rdfile("FGETS.TXT", O_READ);
|
||||||
|
|
||||||
|
// check for open error
|
||||||
|
if (!rdfile.isOpen()) error("demoFgets");
|
||||||
|
|
||||||
|
cout << endl << pstr(
|
||||||
|
"Lines with '>' end with a '\\n' character\n"
|
||||||
|
"Lines with '#' do not end with a '\\n' character\n"
|
||||||
|
"\n");
|
||||||
|
|
||||||
|
// read lines from the file
|
||||||
|
while ((n = rdfile.fgets(line, sizeof(line))) > 0) {
|
||||||
|
if (line[n - 1] == '\n') {
|
||||||
|
cout << '>' << line;
|
||||||
|
} else {
|
||||||
|
cout << '#' << line << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void makeTestFile() {
|
||||||
|
// create or open test file
|
||||||
|
SdFile wrfile("FGETS.TXT", O_WRITE | O_CREAT | O_TRUNC);
|
||||||
|
|
||||||
|
// check for open error
|
||||||
|
if (!wrfile.isOpen()) error("MakeTestFile");
|
||||||
|
|
||||||
|
// write test file
|
||||||
|
wrfile.write_P(PSTR(
|
||||||
|
"Line with CRLF\r\n"
|
||||||
|
"Line with only LF\n"
|
||||||
|
"Long line that will require an extra read\n"
|
||||||
|
"\n" // empty line
|
||||||
|
"Line at EOF without NL"
|
||||||
|
));
|
||||||
|
// wrfile is closed when it goes out of scope
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the file system
|
||||||
|
if (!sd.init()) sd.initErrorHalt();
|
||||||
|
|
||||||
|
makeTestFile();
|
||||||
|
|
||||||
|
demoFgets();
|
||||||
|
|
||||||
|
cout << pstr("\nDone\n");
|
||||||
|
}
|
||||||
|
void loop(void) {}
|
63
arduino/floppyemu/SdFat/examples/formatting/formatting.pde
Executable file
63
arduino/floppyemu/SdFat/examples/formatting/formatting.pde
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Print a table with various formatting options
|
||||||
|
* Format dates
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// create Serial stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// print a table to demonstrate format manipulators
|
||||||
|
void example(void) {
|
||||||
|
const int max = 10;
|
||||||
|
const int width = 4;
|
||||||
|
|
||||||
|
for (int row = 1; row <= max; row++) {
|
||||||
|
for (int col = 1; col <= max; col++) {
|
||||||
|
cout << setw(width) << row * col << (col == max ? '\n' : ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// print a date as mm/dd/yyyy with zero fill in mm and dd
|
||||||
|
// shows how to set and restore the fill character
|
||||||
|
void showDate(int m, int d, int y) {
|
||||||
|
// convert two digit year
|
||||||
|
if (y < 100) y += 2000;
|
||||||
|
|
||||||
|
// set new fill to '0' save old fill character
|
||||||
|
char old = cout.fill('0');
|
||||||
|
|
||||||
|
// print date
|
||||||
|
cout << setw(2) << m << '/' << setw(2) << d << '/' << y << endl;
|
||||||
|
|
||||||
|
// restore old fill character
|
||||||
|
cout.fill(old);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
cout << endl << "default formatting" << endl;
|
||||||
|
example();
|
||||||
|
|
||||||
|
cout << showpos << "showpos" << endl;
|
||||||
|
example();
|
||||||
|
|
||||||
|
cout << hex << left << showbase << "hex left showbase" << endl;
|
||||||
|
example();
|
||||||
|
|
||||||
|
cout << internal << setfill('0') << uppercase;
|
||||||
|
cout << "uppercase hex internal showbase fill('0')" <<endl;
|
||||||
|
example();
|
||||||
|
|
||||||
|
// restore default format flags and fill character
|
||||||
|
cout.flags(ios::dec | ios::right | ios::skipws);
|
||||||
|
cout.fill(' ');
|
||||||
|
|
||||||
|
cout << "showDate example" <<endl;
|
||||||
|
showDate(7, 4, 11);
|
||||||
|
showDate(12, 25, 11);
|
||||||
|
}
|
||||||
|
void loop(void) {}
|
70
arduino/floppyemu/SdFat/examples/getline/getline.pde
Executable file
70
arduino/floppyemu/SdFat/examples/getline/getline.pde
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Example of getline from section 27.7.1.3 of the C++ standard
|
||||||
|
* Demonstrates the behavior of getline for various exceptions.
|
||||||
|
* See http://www.cplusplus.com/reference/iostream/istream/getline/
|
||||||
|
*
|
||||||
|
* Note: This example is meant to demonstrate subtleties the standard and
|
||||||
|
* may not the best way to read a file.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// create a serial stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void makeTestFile() {
|
||||||
|
ofstream sdout("GETLINE.TXT");
|
||||||
|
// use flash for text to save RAM
|
||||||
|
sdout << pstr(
|
||||||
|
"short line\n"
|
||||||
|
"\n"
|
||||||
|
"17 character line\n"
|
||||||
|
"too long for buffer\n"
|
||||||
|
"line with no nl");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void testGetline() {
|
||||||
|
const int line_buffer_size = 18;
|
||||||
|
char buffer[line_buffer_size];
|
||||||
|
ifstream sdin("GETLINE.TXT");
|
||||||
|
int line_number = 0;
|
||||||
|
|
||||||
|
while (sdin.getline(buffer, line_buffer_size, '\n') || sdin.gcount()) {
|
||||||
|
int count = sdin.gcount();
|
||||||
|
if (sdin.fail()) {
|
||||||
|
cout << "Partial long line";
|
||||||
|
sdin.clear(sdin.rdstate() & ~ios_base::failbit);
|
||||||
|
} else if (sdin.eof()) {
|
||||||
|
cout << "Partial final line"; // sdin.fail() is false
|
||||||
|
} else {
|
||||||
|
count--; // Don’t include newline in count
|
||||||
|
cout << "Line " << ++line_number;
|
||||||
|
}
|
||||||
|
cout << " (" << count << " chars): " << buffer << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// pstr stores strings in flash to save RAM
|
||||||
|
cout << pstr("Type any character to start\n");
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// make the test file
|
||||||
|
makeTestFile();
|
||||||
|
|
||||||
|
// run the example
|
||||||
|
testGetline();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop(void) {}
|
80
arduino/floppyemu/SdFat/examples/readCSV/readCSV.pde
Executable file
80
arduino/floppyemu/SdFat/examples/readCSV/readCSV.pde
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* This example reads a simple CSV, comma-separated values, file.
|
||||||
|
* Each line of the file has three values, a long and two floats.
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// create Serial stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
|
||||||
|
char fileName[] = "3V_FILE.CSV";
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash to save RAM
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// read and print CSV test file
|
||||||
|
void readFile() {
|
||||||
|
long lg;
|
||||||
|
float f1, f2;
|
||||||
|
char c1, c2;
|
||||||
|
|
||||||
|
// open input file
|
||||||
|
ifstream sdin(fileName);
|
||||||
|
|
||||||
|
// check for open error
|
||||||
|
if (!sdin.is_open()) error("open");
|
||||||
|
|
||||||
|
// read until input fails
|
||||||
|
while (sdin >> lg >> c1 >> f1 >> c2 >> f2) {
|
||||||
|
|
||||||
|
// error in line if not commas
|
||||||
|
if (c1 != ',' || c2 != ',') error("comma");
|
||||||
|
|
||||||
|
// print in six character wide columns
|
||||||
|
cout << setw(6) << lg << setw(6) << f1 << setw(6) << f2 << endl;
|
||||||
|
}
|
||||||
|
// Error in an input line if file is not at EOF.
|
||||||
|
if (!sdin.eof()) error("readFile");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// write test file
|
||||||
|
void writeFile() {
|
||||||
|
|
||||||
|
// create or open and truncate output file
|
||||||
|
ofstream sdout(fileName);
|
||||||
|
|
||||||
|
// write file from string stored in flash
|
||||||
|
sdout << pstr(
|
||||||
|
"1,2.3,4.5\n"
|
||||||
|
"6,7.8,9.0\n"
|
||||||
|
"9,8.7,6.5\n"
|
||||||
|
"-4,-3.2,-1\n") << flush;
|
||||||
|
|
||||||
|
// check for any errors
|
||||||
|
if (!sdout) error("writeFile");
|
||||||
|
|
||||||
|
// file is closed by destructor when it goes out of scope.
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// create test file
|
||||||
|
writeFile();
|
||||||
|
|
||||||
|
// read and print test
|
||||||
|
readFile();
|
||||||
|
|
||||||
|
cout << "Done" << endl;
|
||||||
|
}
|
||||||
|
void loop() {}
|
39
arduino/floppyemu/SdFat/examples/readlog/readlog.pde
Executable file
39
arduino/floppyemu/SdFat/examples/readlog/readlog.pde
Executable file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Read the logfile created by the eventlog.pde example.
|
||||||
|
* Demo of pathnames and working directories
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system object
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// define a serial output stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
char c;
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// set current working directory
|
||||||
|
if (!sd.chdir("LOGS/2011/JAN/")) {
|
||||||
|
sd.errorHalt("chdir failed. Did you run eventlog.pde?");
|
||||||
|
}
|
||||||
|
// open file in current working directory
|
||||||
|
ifstream file("LOGFILE.TXT");
|
||||||
|
|
||||||
|
if (!file.is_open()) sd.errorHalt("open failed");
|
||||||
|
|
||||||
|
// copy the file to Serial
|
||||||
|
while ((c = file.get()) >= 0) cout << c;
|
||||||
|
|
||||||
|
cout << "Done" << endl;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void loop() {}
|
74
arduino/floppyemu/SdFat/examples/rename/rename.pde
Executable file
74
arduino/floppyemu/SdFat/examples/rename/rename.pde
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* This sketch demonstrates use of SdFile::rename()
|
||||||
|
* and SdFat::rename().
|
||||||
|
*/
|
||||||
|
#include <SdFat.h>
|
||||||
|
|
||||||
|
// SD chip select pin
|
||||||
|
const uint8_t chipSelect = SS_PIN;
|
||||||
|
|
||||||
|
// file system
|
||||||
|
SdFat sd;
|
||||||
|
|
||||||
|
// Serial print stream
|
||||||
|
ArduinoOutStream cout(Serial);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// store error strings in flash to save RAM
|
||||||
|
#define error(s) sd.errorHalt_P(PSTR(s))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
cout << pstr("Insert an empty SD. Type any character to start.") << endl;
|
||||||
|
while (Serial.read() < 0) {}
|
||||||
|
|
||||||
|
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||||
|
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||||
|
if (!sd.init(SPI_HALF_SPEED, chipSelect)) sd.initErrorHalt();
|
||||||
|
|
||||||
|
// create a file and write one line to the file
|
||||||
|
SdFile file("NAME1.TXT", O_WRITE | O_CREAT);
|
||||||
|
if (!file.isOpen()) error("NAME1");
|
||||||
|
file.println("A test line for NAME1.TXT");
|
||||||
|
|
||||||
|
// rename the file NAME2.TXT and add a line.
|
||||||
|
// sd.vwd() is the volume working directory, root.
|
||||||
|
if (!file.rename(sd.vwd(), "NAME2.TXT")) error("NAME2");
|
||||||
|
file.println("A test line for NAME2.TXT");
|
||||||
|
|
||||||
|
// list files
|
||||||
|
cout << pstr("------") << endl;
|
||||||
|
sd.ls(LS_R);
|
||||||
|
|
||||||
|
// make a new directory - "DIR1"
|
||||||
|
if (!sd.mkdir("DIR1")) error("DIR1");
|
||||||
|
|
||||||
|
// move file into DIR1, rename it NAME3.TXT and add a line
|
||||||
|
if (!file.rename(sd.vwd(), "DIR1/NAME3.TXT")) error("NAME3");
|
||||||
|
file.println("A line for DIR1/NAME3.TXT");
|
||||||
|
|
||||||
|
// list files
|
||||||
|
cout << pstr("------") << endl;
|
||||||
|
sd.ls(LS_R);
|
||||||
|
|
||||||
|
// make directory "DIR2"
|
||||||
|
if (!sd.mkdir("DIR2")) error("DIR2");
|
||||||
|
|
||||||
|
// close file before rename(oldPath, newPath)
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// move DIR1 into DIR2 and rename it DIR3
|
||||||
|
if (!sd.rename("DIR1", "DIR2/DIR3")) error("DIR2/DIR3");
|
||||||
|
|
||||||
|
// open file for append in new location and add a line
|
||||||
|
if (!file.open("DIR2/DIR3/NAME3.TXT", O_WRITE | O_APPEND)) {
|
||||||
|
error("DIR2/DIR3/NAME3.TXT");
|
||||||
|
}
|
||||||
|
file.println("A line for DIR2/DIR3/NAME3.TXT");
|
||||||
|
|
||||||
|
// list files
|
||||||
|
cout << pstr("------") << endl;
|
||||||
|
sd.ls(LS_R);
|
||||||
|
|
||||||
|
cout << pstr("Done") << endl;
|
||||||
|
}
|
||||||
|
void loop() {}
|
235
arduino/floppyemu/cardtest.cpp
Normal file
235
arduino/floppyemu/cardtest.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD_SPI.h>
|
||||||
|
#include "noklcd.h"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "portmacros.h"
|
||||||
|
#include "noklcd.h"
|
||||||
|
#include "millitimer.h"
|
||||||
|
#include "SdFat.h"
|
||||||
|
#include "SdBaseFile.h"
|
||||||
|
#include "micro.h"
|
||||||
|
#include "ports.h"
|
||||||
|
#include "diskmenu.h"
|
||||||
|
#include "cardtest.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_ORIGINAL_COMPILER_WORKAROUND
|
||||||
|
|
||||||
|
// work-around for compiler bug
|
||||||
|
#undef PROGMEM
|
||||||
|
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||||
|
#undef PSTR
|
||||||
|
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define STATUS_LED_PORT B
|
||||||
|
#define STATUS_LED_PIN 3
|
||||||
|
|
||||||
|
#define TEXTBUF_SIZE 22
|
||||||
|
extern char textBuf[];
|
||||||
|
extern uint8_t sectorBuf[512];
|
||||||
|
|
||||||
|
void CardTest()
|
||||||
|
{
|
||||||
|
LcdClear();
|
||||||
|
|
||||||
|
//SdFat sd;
|
||||||
|
SDClass sd(4);
|
||||||
|
|
||||||
|
if (!sd.init(SPI_HALF_SPEED))
|
||||||
|
{
|
||||||
|
snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData());
|
||||||
|
LcdGoto(0,0);
|
||||||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cid_t cid;
|
||||||
|
|
||||||
|
uint32_t cardSize = sd.card()->cardSize();
|
||||||
|
cardSize /= (2L*1024L);
|
||||||
|
|
||||||
|
sd.card()->readCID(&cid);
|
||||||
|
|
||||||
|
snprintf(textBuf, TEXTBUF_SIZE, "CID %d %c%c%c%c%c %lu MB", cid.mid, cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cardSize);
|
||||||
|
LcdGoto(0,0);
|
||||||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||||
|
|
||||||
|
csd_t csd;
|
||||||
|
sd.card()->readCSD(&csd);
|
||||||
|
|
||||||
|
uint8_t writeBlockPow; // write block length, log2
|
||||||
|
uint8_t sectorSizeCnt; // minimum erasable size, in write blocks
|
||||||
|
|
||||||
|
if (csd.v1.csd_ver == 1)
|
||||||
|
{
|
||||||
|
csd1_t* c = &csd.v1;
|
||||||
|
|
||||||
|
writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low;
|
||||||
|
sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
csd2_t* c = &csd.v2;
|
||||||
|
|
||||||
|
writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low;
|
||||||
|
sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorSizeCnt += 1; // these all seem to be 2**n - 1?
|
||||||
|
|
||||||
|
uint32_t writeBlock=1;
|
||||||
|
for (uint8_t i=0; i<writeBlockPow; i++)
|
||||||
|
{
|
||||||
|
writeBlock *= 2;
|
||||||
|
}
|
||||||
|
uint32_t sectorSize = writeBlock * sectorSizeCnt;
|
||||||
|
sectorSize /= 1024;
|
||||||
|
|
||||||
|
snprintf(textBuf, TEXTBUF_SIZE, "BLK %luB ERASE %luK", writeBlock, sectorSize);
|
||||||
|
LcdGoto(0,1);
|
||||||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||||
|
|
||||||
|
LcdGoto(0,2);
|
||||||
|
|
||||||
|
SdBaseFile f;
|
||||||
|
if (!f.open("TESTFILE.DAT", O_RDWR))
|
||||||
|
{
|
||||||
|
LcdTinyStringP(PSTR("TESTFILE.DAT missing"), TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get address of file on SD
|
||||||
|
uint32_t imageFirstBlock, imageLastBlock;
|
||||||
|
if (!f.contiguousRange(&imageFirstBlock, &imageLastBlock))
|
||||||
|
{
|
||||||
|
LcdTinyStringP(PSTR("file not contiguous"), TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.fileSize() < (unsigned long)1024 * 1024)
|
||||||
|
{
|
||||||
|
LcdTinyStringP(PSTR("file too small"), TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
LcdTinyStringP(PSTR("Testing..."), TEXT_NORMAL);
|
||||||
|
|
||||||
|
uint32_t writeCount = 0;
|
||||||
|
uint32_t writeTotalTime = 0;
|
||||||
|
uint32_t worstTime = 0;
|
||||||
|
uint32_t above20Count = 0;
|
||||||
|
|
||||||
|
for (int trial=0; trial<3; trial++)
|
||||||
|
{
|
||||||
|
uint32_t b = 0;
|
||||||
|
for (uint32_t cnt=0; cnt<1600 && b<1600; cnt++)
|
||||||
|
{
|
||||||
|
if (!sd.card()->readBlock(imageFirstBlock + b, sectorBuf))
|
||||||
|
{
|
||||||
|
LcdGoto(0,2);
|
||||||
|
LcdTinyStringP(PSTR("SD read error"), TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// alter the data, to prevent any kind of compression/optimization on the card
|
||||||
|
for (uint16_t i=0; i<512; i++)
|
||||||
|
{
|
||||||
|
sectorBuf[i] ^= sectorBuf[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// blink the LED
|
||||||
|
if ((writeCount & 0x7) == 0)
|
||||||
|
PORT(STATUS_LED_PORT) ^= (1<<STATUS_LED_PIN);
|
||||||
|
|
||||||
|
uint32_t t0;
|
||||||
|
|
||||||
|
_delay_ms(3);
|
||||||
|
|
||||||
|
// write it
|
||||||
|
t0 = millis();
|
||||||
|
|
||||||
|
if (!sd.card()->writeBlock(imageFirstBlock + b, sectorBuf))
|
||||||
|
{
|
||||||
|
LcdGoto(0,2);
|
||||||
|
LcdTinyStringP(PSTR("SD write error"), TEXT_NORMAL);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t writeTime = millis() - t0;
|
||||||
|
|
||||||
|
// update stats
|
||||||
|
writeCount++;
|
||||||
|
writeTotalTime += writeTime;
|
||||||
|
if (writeTime > 20)
|
||||||
|
above20Count++;
|
||||||
|
if (writeTime > worstTime)
|
||||||
|
worstTime = writeTime;
|
||||||
|
|
||||||
|
// pseudo-interleave
|
||||||
|
if ((cnt & 1) == 0)
|
||||||
|
b += 6;
|
||||||
|
else
|
||||||
|
b -= 5;
|
||||||
|
|
||||||
|
_delay_ms(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t avg = (writeTotalTime + (writeCount >> 1))/ writeCount;
|
||||||
|
|
||||||
|
LcdGoto(0,2);
|
||||||
|
LcdTinyStringP(PSTR("AVG.ms/MAX.ms/LONG.%"), TEXT_NORMAL);
|
||||||
|
|
||||||
|
snprintf(textBuf, TEXTBUF_SIZE, "512B RRWI %lu/%lu/%lu", avg, worstTime, above20Count*100/writeCount);
|
||||||
|
LcdGoto(0,3);
|
||||||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||||
|
|
||||||
|
// Card: actual capacity, block size, erase size, best test result (random read-write interleaved) average/max/percent "long" over 20ms
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// PNY class 10 8GB: 7708 MB, 512B block, 64K erase. 512B RRWI 10/189/1 (random read-write interleave)
|
||||||
|
// SanDisk unrated Ultra II 2GB: 1938 MB, 1024B block, 32K erase. 512B RRWI 7/79/0
|
||||||
|
// Transcend unrated 2GB: 1875 MB, 1024B block, 128K erase. 512B RRWI 3/103/0
|
||||||
|
// SanDisk unrated 128MB: 120 MB, 512B block, 16K erase. 512B RRWI 5/94/1
|
||||||
|
|
||||||
|
// enabling the TACH stuff seems to cause some cards to get errors during this test. Coupling between traces? Why doesn't it happen during normal operation?
|
||||||
|
|
||||||
|
// Transcend unrated 2GB: Finder consistently "goes to sleep" after copying first 19 tracks, but worked twice after 3 tries. Maybe it's too fast?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
while(1);
|
||||||
|
}
|
21
arduino/floppyemu/cardtest.h
Executable file
21
arduino/floppyemu/cardtest.h
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARDTEST_H_
|
||||||
|
#define CARDTEST_H_
|
||||||
|
|
||||||
|
void CardTest();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CARDTEST_H_ */
|
368
arduino/floppyemu/diskmenu.cpp
Executable file
368
arduino/floppyemu/diskmenu.cpp
Executable file
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <util/atomic.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "diskmenu.h"
|
||||||
|
#include "SdFat.h"
|
||||||
|
#include "SdBaseFile.h"
|
||||||
|
#include "noklcd.h"
|
||||||
|
|
||||||
|
#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs
|
||||||
|
extern uint8_t sectorBuf[24][512];
|
||||||
|
extern uint8_t extraBuf[512];
|
||||||
|
|
||||||
|
typedef struct FileEntry
|
||||||
|
{
|
||||||
|
char longName[FILENAME_LEN+1];
|
||||||
|
char shortName[SHORTFILENAME_LEN+1];
|
||||||
|
eImageType imageFileType;
|
||||||
|
} FileEntry;
|
||||||
|
|
||||||
|
bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn)
|
||||||
|
{
|
||||||
|
uint8_t offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30};
|
||||||
|
uint8_t lfnIn = 130;
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t ndir=0;
|
||||||
|
uint8_t sum;
|
||||||
|
uint8_t test=0;
|
||||||
|
bool haveLong = false;
|
||||||
|
|
||||||
|
while( sd.vwd()->read( &dir, 32 ) == 32 )
|
||||||
|
{
|
||||||
|
if( DIR_IS_LONG_NAME( &dir ) )
|
||||||
|
{
|
||||||
|
if( ! haveLong )
|
||||||
|
{
|
||||||
|
if(( dir.name[0] & 0XE0 ) != 0X40 )
|
||||||
|
continue;
|
||||||
|
ndir = dir.name[0] & 0X1F;
|
||||||
|
test = dir.creationTimeTenths;
|
||||||
|
haveLong = true;
|
||||||
|
lfnIn = 130;
|
||||||
|
lfn[ lfnIn ] = 0;
|
||||||
|
}
|
||||||
|
else if( dir.name[0] != --ndir || test != dir.creationTimeTenths )
|
||||||
|
{
|
||||||
|
haveLong = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char *p = (char*) & dir;
|
||||||
|
if( lfnIn > 0 )
|
||||||
|
{
|
||||||
|
lfnIn -= 13;
|
||||||
|
for( i = 0; i < 13; i++ )
|
||||||
|
lfn[lfnIn + i] = p[offset[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( DIR_IS_FILE_OR_SUBDIR( &dir )
|
||||||
|
&& dir.name[0] != DIR_NAME_DELETED
|
||||||
|
&& dir.name[0] != DIR_NAME_FREE
|
||||||
|
&& dir.name[0] != '.')
|
||||||
|
{
|
||||||
|
if( haveLong )
|
||||||
|
{
|
||||||
|
for( sum = i = 0; i < 11; i++ )
|
||||||
|
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i];
|
||||||
|
if( sum != test || ndir != 1 )
|
||||||
|
haveLong = false;
|
||||||
|
}
|
||||||
|
if( haveLong )
|
||||||
|
{
|
||||||
|
for( i = 0; lfnIn + i <= 130 ; i++ )
|
||||||
|
lfn[i] = lfn[lfnIn + i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// else if( dir.reservedNT )
|
||||||
|
// return "Reserved NT";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SdBaseFile::dirName( dir, lfn );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( dir.name[0] == DIR_NAME_FREE )
|
||||||
|
break;
|
||||||
|
haveLong = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lfn[ 0 ] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eImageType DiskImageFileType(dir_t& dir, const char *filename)
|
||||||
|
{
|
||||||
|
if (filename[0] == '.')
|
||||||
|
return DISK_IMAGE_NONE;
|
||||||
|
|
||||||
|
if (DIR_IS_SUBDIR(&dir))
|
||||||
|
return DISK_IMAGE_DIRECTORY;
|
||||||
|
|
||||||
|
if (!DIR_IS_FILE(&dir))
|
||||||
|
return DISK_IMAGE_NONE;
|
||||||
|
|
||||||
|
uint32_t size = dir.fileSize;
|
||||||
|
|
||||||
|
if (size == (unsigned long)1024 * 400)
|
||||||
|
return DISK_IMAGE_400K;
|
||||||
|
else if (size == (unsigned long)1024 * 800)
|
||||||
|
return DISK_IMAGE_800K;
|
||||||
|
else if (size == (unsigned long)1024 * 1440)
|
||||||
|
return DISK_IMAGE_1440K;
|
||||||
|
else if (size > (unsigned long)1024 * 400 &&
|
||||||
|
size < (unsigned long)1024 * 1500)
|
||||||
|
{
|
||||||
|
// get the 8.3 filename
|
||||||
|
char shortName[SHORTFILENAME_LEN+1];
|
||||||
|
SdBaseFile::dirName(dir, shortName);
|
||||||
|
|
||||||
|
// read the first sector of the file
|
||||||
|
SdBaseFile f;
|
||||||
|
if (f.open(shortName, O_RDONLY))
|
||||||
|
{
|
||||||
|
f.read(extraBuf, 512);
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
// is it a DiskCopy 4.2 image?
|
||||||
|
if (extraBuf[0x52] == 0x01 &&
|
||||||
|
extraBuf[0x53] == 0x00)
|
||||||
|
{
|
||||||
|
size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024;
|
||||||
|
|
||||||
|
if (size == 400)
|
||||||
|
return DISK_IMAGE_DISKCOPY_400K;
|
||||||
|
else if (size == 800)
|
||||||
|
return DISK_IMAGE_DISKCOPY_800K;
|
||||||
|
else if (size == 1440)
|
||||||
|
return DISK_IMAGE_DISKCOPY_1440K;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DISK_IMAGE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t diskMenuEntryCount;
|
||||||
|
uint16_t diskMenuOffset = 0;
|
||||||
|
uint16_t diskMenuSelection = 0;
|
||||||
|
char selectedFile[FILENAME_LEN+1];
|
||||||
|
char selectedLongFile[FILENAME_LEN+1];
|
||||||
|
eImageType selectedFileType;
|
||||||
|
uint8_t subdirDepth = 0;
|
||||||
|
|
||||||
|
#define LONGFILENAME_LEN 130
|
||||||
|
|
||||||
|
void InitDiskMenu(SdFat& sd)
|
||||||
|
{
|
||||||
|
dir_t dir;
|
||||||
|
char name[LONGFILENAME_LEN+1];
|
||||||
|
|
||||||
|
diskMenuEntryCount = 0;
|
||||||
|
|
||||||
|
// use the sector buffers to hold the filenames
|
||||||
|
uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry);
|
||||||
|
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||||
|
|
||||||
|
sd.vwd()->rewind();
|
||||||
|
while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries)
|
||||||
|
{
|
||||||
|
eImageType imageType;
|
||||||
|
|
||||||
|
if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE)
|
||||||
|
{
|
||||||
|
strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1);
|
||||||
|
SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName);
|
||||||
|
pFileEntries[diskMenuEntryCount].imageFileType = imageType;
|
||||||
|
diskMenuEntryCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add up directory, if not at the root
|
||||||
|
if (!sd.vwd()->isRoot())
|
||||||
|
{
|
||||||
|
strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1);
|
||||||
|
strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1);
|
||||||
|
pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY;
|
||||||
|
diskMenuEntryCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1];
|
||||||
|
eImageType tempType;
|
||||||
|
|
||||||
|
// sort the names by longname
|
||||||
|
for (uint16_t i=0; i<diskMenuEntryCount; i++)
|
||||||
|
{
|
||||||
|
for (uint16_t j=i+1; j<diskMenuEntryCount; j++)
|
||||||
|
{
|
||||||
|
// convert filenames to upper case, for comparison purposes
|
||||||
|
strncpy(file1, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||||
|
for (uint8_t x=0; x<strlen(file1); x++)
|
||||||
|
file1[x] = toupper(file1[x]);
|
||||||
|
|
||||||
|
strncpy(file2, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||||
|
for (uint8_t x=0; x<strlen(file2); x++)
|
||||||
|
file2[x] = toupper(file2[x]);
|
||||||
|
|
||||||
|
// sort directories before regular files
|
||||||
|
int diff = strncmp(file1, file2, FILENAME_LEN+1);
|
||||||
|
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||||
|
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||||
|
diff -= 1000;
|
||||||
|
if (pFileEntries[j].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||||
|
pFileEntries[j].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||||
|
diff += 1000;
|
||||||
|
|
||||||
|
// if file1 > file2, swap them
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||||
|
strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||||
|
strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1);
|
||||||
|
|
||||||
|
strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||||
|
strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1);
|
||||||
|
strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1);
|
||||||
|
|
||||||
|
tempType = pFileEntries[i].imageFileType;
|
||||||
|
pFileEntries[i].imageFileType = pFileEntries[j].imageFileType;
|
||||||
|
pFileEntries[j].imageFileType = tempType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawDiskMenu(SdFat& sd)
|
||||||
|
{
|
||||||
|
// scroll menu if necessary
|
||||||
|
if (diskMenuSelection < diskMenuOffset)
|
||||||
|
diskMenuOffset = diskMenuSelection;
|
||||||
|
if (diskMenuSelection > diskMenuOffset+4)
|
||||||
|
diskMenuOffset = diskMenuSelection-4;
|
||||||
|
|
||||||
|
LcdGoto(0,0);
|
||||||
|
LcdWrite(LCD_DATA, 0x7F);
|
||||||
|
for (int i=0; i<19; i++)
|
||||||
|
LcdWrite(LCD_DATA, 0x40);
|
||||||
|
|
||||||
|
LcdTinyStringFramed("Select Disk");
|
||||||
|
|
||||||
|
for (int i=0; i<19; i++)
|
||||||
|
LcdWrite(LCD_DATA, 0x40);
|
||||||
|
LcdWrite(LCD_DATA, 0x7F);
|
||||||
|
|
||||||
|
if (diskMenuEntryCount == 0)
|
||||||
|
{
|
||||||
|
LcdGoto(0, 1);
|
||||||
|
LcdTinyString("no image files found", TEXT_NORMAL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
for (uint16_t i=diskMenuOffset; i<diskMenuOffset+5 && i<diskMenuEntryCount; i++)
|
||||||
|
{
|
||||||
|
bool selected = (i == diskMenuSelection);
|
||||||
|
|
||||||
|
LcdGoto(0, row+1);
|
||||||
|
for (int j=0; j<LCD_WIDTH; j++)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, selected ? 0x7F : 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the image name
|
||||||
|
LcdGoto(1, row+1);
|
||||||
|
LcdTinyString(pFileEntries[i].longName, selected ? TEXT_INVERSE : TEXT_NORMAL, LCD_WIDTH-1);
|
||||||
|
|
||||||
|
// draw a folder icon for subdirectories
|
||||||
|
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||||
|
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||||
|
{
|
||||||
|
LcdGoto(73, row+1);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||||
|
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
strncpy(selectedLongFile, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||||
|
strncpy(selectedFile, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||||
|
selectedFileType = pFileEntries[i].imageFileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the scrollbar
|
||||||
|
if (diskMenuEntryCount <= 5)
|
||||||
|
{
|
||||||
|
// no scrollbar
|
||||||
|
for (uint8_t r=1; r<6; r++)
|
||||||
|
{
|
||||||
|
LcdGoto(82, r);
|
||||||
|
LcdWrite(LCD_DATA, 0x00);
|
||||||
|
LcdWrite(LCD_DATA, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t barEnd = 8 + (uint16_t)39 * (diskMenuOffset + 5) / diskMenuEntryCount;
|
||||||
|
uint8_t barSize = (uint16_t)39 * 5 / diskMenuEntryCount;
|
||||||
|
uint8_t barStart = barEnd - barSize;
|
||||||
|
|
||||||
|
for (uint8_t r=1; r<6; r++)
|
||||||
|
{
|
||||||
|
LcdGoto(82, r);
|
||||||
|
LcdWrite(LCD_DATA, 0x00);
|
||||||
|
|
||||||
|
uint8_t b = 0;
|
||||||
|
for (uint8_t y=r*8; y<=r*8+7; y++)
|
||||||
|
{
|
||||||
|
if (y >= barStart && y <= barEnd)
|
||||||
|
b = 0x80 | (b >> 1);
|
||||||
|
else
|
||||||
|
b = (b >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LcdWrite(LCD_DATA, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent moving selection past end of list
|
||||||
|
if (diskMenuSelection >= diskMenuOffset + row)
|
||||||
|
{
|
||||||
|
diskMenuSelection = diskMenuOffset + row - 1;
|
||||||
|
if (row == 4 && diskMenuOffset > 0)
|
||||||
|
{
|
||||||
|
diskMenuOffset--; // scroll backwards
|
||||||
|
}
|
||||||
|
DrawDiskMenu(sd); // draw again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
arduino/floppyemu/diskmenu.h
Executable file
45
arduino/floppyemu/diskmenu.h
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISKMENU_H_
|
||||||
|
#define DISKMENU_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DISK_IMAGE_NONE = 0,
|
||||||
|
DISK_IMAGE_DIRECTORY,
|
||||||
|
DISK_IMAGE_UP_DIRECTORY,
|
||||||
|
DISK_IMAGE_400K,
|
||||||
|
DISK_IMAGE_800K,
|
||||||
|
DISK_IMAGE_1440K,
|
||||||
|
DISK_IMAGE_DISKCOPY_400K,
|
||||||
|
DISK_IMAGE_DISKCOPY_800K,
|
||||||
|
DISK_IMAGE_DISKCOPY_1440K
|
||||||
|
} eImageType;
|
||||||
|
|
||||||
|
#define FILENAME_LEN 21
|
||||||
|
#define SHORTFILENAME_LEN 12 // 8.3
|
||||||
|
|
||||||
|
extern uint16_t diskMenuSelection;
|
||||||
|
extern char selectedFile[];
|
||||||
|
extern char selectedLongFile[];
|
||||||
|
extern eImageType selectedFileType;
|
||||||
|
extern uint8_t subdirDepth;
|
||||||
|
|
||||||
|
class SdFat;
|
||||||
|
|
||||||
|
void InitDiskMenu(SdFat& sd);
|
||||||
|
void DrawDiskMenu(SdFat& sd);
|
||||||
|
|
||||||
|
#endif /* DISKMENU_H_ */
|
1990
arduino/floppyemu/floppyemu.ino
Normal file
1990
arduino/floppyemu/floppyemu.ino
Normal file
File diff suppressed because it is too large
Load Diff
2021
arduino/floppyemu/main.cpp
Executable file
2021
arduino/floppyemu/main.cpp
Executable file
File diff suppressed because it is too large
Load Diff
57
arduino/floppyemu/millitimer.cpp
Executable file
57
arduino/floppyemu/millitimer.cpp
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/atomic.h>
|
||||||
|
#include "millitimer.h"
|
||||||
|
|
||||||
|
static uint32_t milliCount;
|
||||||
|
|
||||||
|
void millitimerInit()
|
||||||
|
{
|
||||||
|
TCCR0A = 0; // normal counter mode
|
||||||
|
TCCR0B = (1<<CS01) | (1<<CS00); // use oscillator/64: 4 microseconds at 16 MHz
|
||||||
|
TIFR0 = (1 << TOV0); // clear the timer 0 interrupt flags
|
||||||
|
|
||||||
|
// don't enable the interrupt yet
|
||||||
|
//TIMSK0 = (1 << TOIE0); // enable timer 0 overflow interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
void millitimerOn()
|
||||||
|
{
|
||||||
|
TIMSK0 = (1 << TOIE0); // enable timer 0 overflow interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
void millitimerOff()
|
||||||
|
{
|
||||||
|
TIMSK0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(TIMER0_OVF_vect)
|
||||||
|
{
|
||||||
|
// timer overflows every 256 * 4 microseconds = 1.024 milliseconds
|
||||||
|
milliCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t millis()
|
||||||
|
{
|
||||||
|
// What happens if the millitimer interrupt occurs in the middle of this function? A bad count could be returned
|
||||||
|
uint32_t returnValue;
|
||||||
|
|
||||||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||||
|
{
|
||||||
|
returnValue = milliCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
24
arduino/floppyemu/millitimer.h
Executable file
24
arduino/floppyemu/millitimer.h
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MILLITIMER_H_
|
||||||
|
#define MILLITIMER_H_
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
void millitimerInit();
|
||||||
|
void millitimerOn();
|
||||||
|
void millitimerOff();
|
||||||
|
uint32_t millis();
|
||||||
|
|
||||||
|
#endif /* MILLITIMER_H_ */
|
350
arduino/floppyemu/noklcd.cpp
Executable file
350
arduino/floppyemu/noklcd.cpp
Executable file
|
@ -0,0 +1,350 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <util/atomic.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "noklcd.h"
|
||||||
|
#include "portmacros.h"
|
||||||
|
|
||||||
|
#define LCD_RESET_PORT B
|
||||||
|
#define LCD_RESET_PIN 0
|
||||||
|
|
||||||
|
#define LCD_CS_PORT B
|
||||||
|
#define LCD_CS_PIN 2
|
||||||
|
|
||||||
|
#define SPI_CLK_PORT B
|
||||||
|
#define SPI_CLK_PIN 7
|
||||||
|
|
||||||
|
#define SPI_DATA_PORT B
|
||||||
|
#define SPI_DATA_PIN 5
|
||||||
|
|
||||||
|
#define SPI_DC_PORT D
|
||||||
|
#define SPI_DC_PIN 6
|
||||||
|
|
||||||
|
volatile uint8_t lcd_vop;
|
||||||
|
volatile uint8_t lcd_bias;
|
||||||
|
volatile uint8_t lcd_tempCoef;
|
||||||
|
|
||||||
|
extern const uint8_t tiny_font[][3] PROGMEM;
|
||||||
|
const uint8_t tiny_font[][3] = {
|
||||||
|
|
||||||
|
{0x00,0x00,0x00}, // 20
|
||||||
|
{0x00,0x17,0x00}, // 21 !
|
||||||
|
{0x03,0x00,0x03}, // 22 "
|
||||||
|
{0x1f,0x0a,0x1f}, // 23 #
|
||||||
|
{0x0a,0x1f,0x05}, // 24 $
|
||||||
|
{0x09,0x04,0x12}, // 25 %
|
||||||
|
{0x0f,0x17,0x1c}, // 26 &
|
||||||
|
{0x00,0x03,0x03}, // 27 ' -> degree
|
||||||
|
{0x00,0x0e,0x11}, // 28 (
|
||||||
|
{0x11,0x0e,0x00}, // 29 )
|
||||||
|
{0x05,0x02,0x05}, // 2a *
|
||||||
|
{0x04,0x0e,0x04}, // 2b +
|
||||||
|
{0x10,0x08,0x00}, // 2c ,
|
||||||
|
{0x04,0x04,0x04}, // 2d -
|
||||||
|
{0x00,0x10,0x00}, // 2e .
|
||||||
|
{0x18,0x04,0x03}, // 2f /
|
||||||
|
{0x1e,0x11,0x0f}, // 30 0
|
||||||
|
{0x02,0x1f,0x00}, // 31 1
|
||||||
|
{0x19,0x15,0x12}, // 32 2
|
||||||
|
{0x15,0x15,0x0a}, // 33 3
|
||||||
|
{0x07,0x04,0x1f}, // 34 4
|
||||||
|
{0x17,0x15,0x09}, // 35 5
|
||||||
|
{0x1e,0x15,0x1d}, // 36 6
|
||||||
|
{0x19,0x05,0x03}, // 37 7
|
||||||
|
{0x1a,0x15,0x0b}, // 38 8
|
||||||
|
{0x17,0x15,0x0f}, // 39 9
|
||||||
|
{0x00,0x0a,0x00}, // 3a :
|
||||||
|
{0x04,0x0c,0x04}, // 3b ; -> down arrow
|
||||||
|
{0x04,0x0e,0x1f}, // 3c <
|
||||||
|
{0x0a,0x0a,0x0a}, // 3d =
|
||||||
|
{0x1f,0x0e,0x04}, // 3e >
|
||||||
|
{0x01,0x15,0x03}, // 3f ?
|
||||||
|
{0x0e,0x15,0x16}, // 40 @
|
||||||
|
{0x1e,0x05,0x1e}, // 41 A
|
||||||
|
{0x1f,0x15,0x0a}, // 42 B
|
||||||
|
{0x0e,0x11,0x11}, // 43 C
|
||||||
|
{0x1f,0x11,0x0e}, // 44 D
|
||||||
|
{0x1f,0x15,0x15}, // 45 E
|
||||||
|
{0x1f,0x05,0x05}, // 46 F
|
||||||
|
{0x0e,0x15,0x1d}, // 47 G
|
||||||
|
{0x1f,0x04,0x1f}, // 48 H
|
||||||
|
{0x11,0x1f,0x11}, // 49 I
|
||||||
|
{0x08,0x10,0x0f}, // 4a J
|
||||||
|
{0x1f,0x04,0x1b}, // 4b K
|
||||||
|
{0x1f,0x10,0x10}, // 4c L
|
||||||
|
{0x1f,0x06,0x1f}, // 4d M
|
||||||
|
{0x1f,0x0e,0x1f}, // 4e N
|
||||||
|
{0x0e,0x11,0x0e}, // 4f O
|
||||||
|
{0x1f,0x05,0x02}, // 50 P
|
||||||
|
{0x0e,0x19,0x1e}, // 51 Q
|
||||||
|
{0x1f,0x0d,0x16}, // 52 R
|
||||||
|
{0x12,0x15,0x09}, // 53 S
|
||||||
|
{0x01,0x1f,0x01}, // 54 T
|
||||||
|
{0x0f,0x10,0x1f}, // 55 U
|
||||||
|
{0x07,0x18,0x07}, // 56 V
|
||||||
|
{0x1f,0x0c,0x1f}, // 57 W
|
||||||
|
{0x1b,0x04,0x1b}, // 58 X
|
||||||
|
{0x03,0x1c,0x03}, // 59 Y
|
||||||
|
{0x19,0x15,0x13}, // 5a Z
|
||||||
|
{0x1f,0x10,0x10}, // 5b [
|
||||||
|
{0x02,0x04,0x08}, // 5c backslash
|
||||||
|
{0x10,0x10,0x1f}, // 5d ]
|
||||||
|
{0x04,0x06,0x04}, // 5e ^
|
||||||
|
{0x10,0x10,0x10}, // 5f _
|
||||||
|
{0x00,0x03,0x03}, // 60 ` -> degree
|
||||||
|
{0x1a,0x16,0x1c}, // 61 a
|
||||||
|
{0x1f,0x12,0x0c}, // 62 b
|
||||||
|
{0x0c,0x12,0x12}, // 63 c
|
||||||
|
{0x0c,0x12,0x1f}, // 64 d
|
||||||
|
{0x0c,0x1a,0x16}, // 65 e
|
||||||
|
{0x04,0x1e,0x05}, // 66 f
|
||||||
|
{0x0c,0x2a,0x1e}, // 67 g
|
||||||
|
{0x1f,0x02,0x1c}, // 68 h
|
||||||
|
{0x00,0x1d,0x00}, // 69 i
|
||||||
|
{0x10,0x20,0x1d}, // 6a j
|
||||||
|
{0x1f,0x0c,0x12}, // 6b k
|
||||||
|
{0x11,0x1f,0x10}, // 6c l
|
||||||
|
{0x1e,0x0e,0x1e}, // 6d m
|
||||||
|
{0x1e,0x02,0x1c}, // 6e n
|
||||||
|
{0x0c,0x12,0x0c}, // 6f o
|
||||||
|
{0x3e,0x12,0x0c}, // 70 p
|
||||||
|
{0x0c,0x12,0x3e}, // 71 q
|
||||||
|
{0x1c,0x02,0x02}, // 72 r
|
||||||
|
{0x14,0x1e,0x0a}, // 73 s
|
||||||
|
{0x02,0x1f,0x12}, // 74 t
|
||||||
|
{0x0e,0x10,0x1e}, // 75 u
|
||||||
|
{0x0e,0x18,0x0e}, // 76 v
|
||||||
|
{0x1e,0x1c,0x1e}, // 77 w
|
||||||
|
{0x12,0x0c,0x12}, // 78 x
|
||||||
|
{0x06,0x28,0x1e}, // 79 y
|
||||||
|
{0x1a,0x1f,0x16}, // 7a z
|
||||||
|
{0x04,0x1b,0x11}, // 7b {
|
||||||
|
{0x00,0x1f,0x00}, // 7c |
|
||||||
|
{0x11,0x1b,0x04}, // 7d }
|
||||||
|
{0x08,0x0c,0x04}, // 7e ~
|
||||||
|
};
|
||||||
|
|
||||||
|
void LcdWrite(uint8_t dc, uint8_t data)
|
||||||
|
{
|
||||||
|
// set SPI speed to "half speed": clock speed / 4
|
||||||
|
SPCR = (1 << SPE) | (1 << MSTR);
|
||||||
|
SPSR = 0;
|
||||||
|
|
||||||
|
if (dc)
|
||||||
|
{
|
||||||
|
PORT(SPI_DC_PORT) |= (1<<SPI_DC_PIN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PORT(SPI_DC_PORT) &= ~(1<<SPI_DC_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT(LCD_CS_PORT) &= ~(1<<LCD_CS_PIN);
|
||||||
|
|
||||||
|
SPDR = data;
|
||||||
|
while(!(SPSR & (1<<SPIF)))
|
||||||
|
{}
|
||||||
|
|
||||||
|
PORT(LCD_CS_PORT) |= (1<<LCD_CS_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdGoto(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_CMD, 0x80 | x);
|
||||||
|
LcdWrite(LCD_CMD, 0x40 | y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdTinyString(const char *characters, uint8_t inverse, uint8_t maxWidth)
|
||||||
|
{
|
||||||
|
uint8_t width = 0;
|
||||||
|
|
||||||
|
while (*characters && width < maxWidth)
|
||||||
|
{
|
||||||
|
if (*characters == 'm')
|
||||||
|
{
|
||||||
|
// special case 'm'
|
||||||
|
characters++;
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x3c ^ 0x7F : 0x3c);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x04 ^ 0x7F : 0x04);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x18 ^ 0x7F : 0x18);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x04 ^ 0x7F : 0x04);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x38 ^ 0x7F : 0x38);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x7F : 0x00);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned short charbase = (*characters++ - 0x20) * 3;
|
||||||
|
|
||||||
|
for (uint8_t index = 0; index < 3 && width < maxWidth; index++)
|
||||||
|
{
|
||||||
|
uint8_t pixels = pgm_read_byte((unsigned char*)tiny_font + charbase + index);
|
||||||
|
pixels = pixels << 1;
|
||||||
|
LcdWrite(LCD_DATA, inverse ? pixels ^ 0x7F : pixels);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width < maxWidth)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x7F : 0x00);
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdTinyStringP(PGM_P characters, uint8_t inverse)
|
||||||
|
{
|
||||||
|
while (pgm_read_byte(characters))
|
||||||
|
{
|
||||||
|
if (pgm_read_byte(characters) == 'm')
|
||||||
|
{
|
||||||
|
// special case 'm'
|
||||||
|
characters++;
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x3c ^ 0x7F : 0x3c);
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x04 ^ 0x7F : 0x04);
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x18 ^ 0x7F : 0x18);
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x04 ^ 0x7F : 0x04);
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x38 ^ 0x7F : 0x38);
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x7F : 0x00);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned short charbase = (pgm_read_byte(characters) - 0x20) * 3;
|
||||||
|
characters++;
|
||||||
|
|
||||||
|
for (uint8_t index = 0; index < 3; index++)
|
||||||
|
{
|
||||||
|
uint8_t pixels = pgm_read_byte((unsigned char*)tiny_font + charbase + index);
|
||||||
|
pixels = pixels << 1;
|
||||||
|
LcdWrite(LCD_DATA, inverse ? pixels ^ 0x7F : pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
LcdWrite(LCD_DATA, inverse ? 0x7F : 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdTinyStringFramed(const char *characters)
|
||||||
|
{
|
||||||
|
while (*characters)
|
||||||
|
{
|
||||||
|
if (*characters == 'm')
|
||||||
|
{
|
||||||
|
// special case 'm'
|
||||||
|
characters++;
|
||||||
|
LcdWrite(LCD_DATA, (0x3c >> 1) | 0x40);
|
||||||
|
LcdWrite(LCD_DATA, (0x04 >> 1) | 0x40);
|
||||||
|
LcdWrite(LCD_DATA, (0x18 >> 1) | 0x40);
|
||||||
|
LcdWrite(LCD_DATA, (0x04 >> 1) | 0x40);
|
||||||
|
LcdWrite(LCD_DATA, (0x38 >> 1) | 0x40);
|
||||||
|
LcdWrite(LCD_DATA, (0x00 >> 1) | 0x40);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned short charbase = (*characters++ - 0x20) * 3;
|
||||||
|
|
||||||
|
for (uint8_t index = 0; index < 3; index++)
|
||||||
|
{
|
||||||
|
uint8_t pixels = pgm_read_byte((unsigned char*)tiny_font + charbase + index);
|
||||||
|
//pixels = pixels << 2;
|
||||||
|
pixels |= 0x40;
|
||||||
|
LcdWrite(LCD_DATA, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
LcdWrite(LCD_DATA, 0x40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdClear(void)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < LCD_WIDTH * LCD_HEIGHT / 8; index++)
|
||||||
|
{
|
||||||
|
LcdWrite(LCD_DATA, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LcdReset(void)
|
||||||
|
{
|
||||||
|
lcd_vop = 0xBF;
|
||||||
|
lcd_bias = 0x14;
|
||||||
|
lcd_tempCoef = 0x04;
|
||||||
|
|
||||||
|
// set pin directions
|
||||||
|
DDR(SPI_DC_PORT) |= (1<<SPI_DC_PIN);
|
||||||
|
DDR(SPI_CLK_PORT) |= (1<<SPI_CLK_PIN);
|
||||||
|
DDR(SPI_DATA_PORT) |= (1<<SPI_DATA_PIN);
|
||||||
|
DDR(LCD_CS_PORT) |= (1<<LCD_CS_PIN);
|
||||||
|
DDR(LCD_RESET_PORT) |= (1<<LCD_RESET_PIN);
|
||||||
|
|
||||||
|
// toggle RST low to reset; CS low so it'll listen to us
|
||||||
|
PORT(LCD_CS_PORT) &= ~(1<<LCD_CS_PIN);
|
||||||
|
|
||||||
|
PORT(LCD_RESET_PORT) |= (1<<LCD_RESET_PIN);
|
||||||
|
_delay_ms(20);
|
||||||
|
PORT(LCD_RESET_PORT) &= ~(1<<LCD_RESET_PIN);
|
||||||
|
_delay_ms(20);
|
||||||
|
PORT(LCD_RESET_PORT) |= (1<<LCD_RESET_PIN);
|
||||||
|
_delay_ms(20);
|
||||||
|
|
||||||
|
// check for the signature byte in EEPROM
|
||||||
|
uint8_t signature = eeprom_read_byte((uint8_t*)0);
|
||||||
|
|
||||||
|
// get the stored contrast setting
|
||||||
|
if (signature == 0xF1)
|
||||||
|
{
|
||||||
|
lcd_vop = eeprom_read_byte((uint8_t*)1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eeprom_update_byte((uint8_t*)0, 0xF1);
|
||||||
|
eeprom_update_byte((uint8_t*)1, lcd_vop);
|
||||||
|
}
|
||||||
|
|
||||||
|
LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands.
|
||||||
|
LcdWrite(LCD_CMD, lcd_vop); // Set LCD Vop (Contrast).
|
||||||
|
//LcdWrite(LCD_CMD, lcd_tempCoef); // Set Temp coefficent.
|
||||||
|
LcdWrite(LCD_CMD, lcd_bias); // LCD bias mode
|
||||||
|
LcdWrite(LCD_CMD, 0x20);
|
||||||
|
LcdWrite(LCD_CMD, 0x0C); // LCD in normal mode. 0x0d for inverse
|
||||||
|
}
|
40
arduino/floppyemu/noklcd.h
Executable file
40
arduino/floppyemu/noklcd.h
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||||
|
|
||||||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||||
|
|
||||||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||||
|
or from mailto:steve@bigmessowires.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOKLCD_H_
|
||||||
|
#define NOKLCD_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define LCD_WIDTH 84
|
||||||
|
#define LCD_HEIGHT 48
|
||||||
|
|
||||||
|
#define LCD_CMD 0
|
||||||
|
#define LCD_DATA 1
|
||||||
|
|
||||||
|
#define TEXT_NORMAL 0
|
||||||
|
#define TEXT_INVERSE 1
|
||||||
|
|
||||||
|
extern volatile uint8_t lcd_vop;
|
||||||
|
extern volatile uint8_t lcd_bias;
|
||||||
|
extern volatile uint8_t lcd_tempCoef;
|
||||||
|
|
||||||
|
void LcdReset(void);
|
||||||
|
void LcdClear(void);
|
||||||
|
void LcdGoto(uint8_t x, uint8_t y);
|
||||||
|
void LcdWrite(uint8_t dc, uint8_t data);
|
||||||
|
void LcdTinyString(const char *characters, uint8_t inverse, uint8_t maxWidth = 84);
|
||||||
|
void LcdTinyStringP(PGM_P characters, uint8_t inverse);
|
||||||
|
void LcdTinyStringFramed(const char *characters);
|
||||||
|
|
||||||
|
#endif /* NOKLCD_H_ */
|
20
arduino/floppyemu/portmacros.h
Executable file
20
arduino/floppyemu/portmacros.h
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* portmacros.h
|
||||||
|
*
|
||||||
|
* Created: 11/16/2011 11:05:46 AM
|
||||||
|
* Author: steve
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PORTMACROS_H_
|
||||||
|
#define PORTMACROS_H_
|
||||||
|
|
||||||
|
#define PORT_(port) PORT ## port
|
||||||
|
#define DDR_(port) DDR ## port
|
||||||
|
#define PIN_(port) PIN ## port
|
||||||
|
|
||||||
|
#define PORT(port) PORT_(port)
|
||||||
|
#define DDR(port) DDR_(port)
|
||||||
|
#define PIN(port) PIN_(port)
|
||||||
|
|
||||||
|
#endif /* PORTMACROS_H_ */
|
190
arduino/floppyemu/xsvf/lenval.cpp
Executable file
190
arduino/floppyemu/xsvf/lenval.cpp
Executable file
|
@ -0,0 +1,190 @@
|
||||||
|
/*******************************************************/
|
||||||
|
/* file: lenval.c */
|
||||||
|
/* abstract: This file contains routines for using */
|
||||||
|
/* the lenVal data structure. */
|
||||||
|
/*******************************************************/
|
||||||
|
#include "lenval.h"
|
||||||
|
#include "ports.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: value
|
||||||
|
* Description: Extract the long value from the lenval array.
|
||||||
|
* Parameters: plvValue - ptr to lenval.
|
||||||
|
* Returns: long - the extracted value.
|
||||||
|
*****************************************************************************/
|
||||||
|
long value( lenVal* plvValue )
|
||||||
|
{
|
||||||
|
long lValue; /* result to hold the accumulated result */
|
||||||
|
short sIndex;
|
||||||
|
|
||||||
|
lValue = 0;
|
||||||
|
for ( sIndex = 0; sIndex < plvValue->len ; ++sIndex )
|
||||||
|
{
|
||||||
|
lValue <<= 8; /* shift the accumulated result */
|
||||||
|
lValue |= plvValue->val[ sIndex]; /* get the last byte first */
|
||||||
|
}
|
||||||
|
|
||||||
|
return( lValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: initLenVal
|
||||||
|
* Description: Initialize the lenval array with the given value.
|
||||||
|
* Assumes lValue is less than 256.
|
||||||
|
* Parameters: plv - ptr to lenval.
|
||||||
|
* lValue - the value to set.
|
||||||
|
* Returns: void.
|
||||||
|
*****************************************************************************/
|
||||||
|
void initLenVal( lenVal* plv,
|
||||||
|
long lValue )
|
||||||
|
{
|
||||||
|
plv->len = 1;
|
||||||
|
plv->val[0] = (unsigned char)lValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: EqualLenVal
|
||||||
|
* Description: Compare two lenval arrays with an optional mask.
|
||||||
|
* Parameters: plvTdoExpected - ptr to lenval #1.
|
||||||
|
* plvTdoCaptured - ptr to lenval #2.
|
||||||
|
* plvTdoMask - optional ptr to mask (=0 if no mask).
|
||||||
|
* Returns: short - 0 = mismatch; 1 = equal.
|
||||||
|
*****************************************************************************/
|
||||||
|
short EqualLenVal( lenVal* plvTdoExpected,
|
||||||
|
lenVal* plvTdoCaptured,
|
||||||
|
lenVal* plvTdoMask )
|
||||||
|
{
|
||||||
|
short sEqual;
|
||||||
|
short sIndex;
|
||||||
|
unsigned char ucByteVal1;
|
||||||
|
unsigned char ucByteVal2;
|
||||||
|
unsigned char ucByteMask;
|
||||||
|
|
||||||
|
sEqual = 1;
|
||||||
|
sIndex = plvTdoExpected->len;
|
||||||
|
|
||||||
|
while ( sEqual && sIndex-- )
|
||||||
|
{
|
||||||
|
ucByteVal1 = plvTdoExpected->val[ sIndex ];
|
||||||
|
ucByteVal2 = plvTdoCaptured->val[ sIndex ];
|
||||||
|
if ( plvTdoMask )
|
||||||
|
{
|
||||||
|
ucByteMask = plvTdoMask->val[ sIndex ];
|
||||||
|
ucByteVal1 &= ucByteMask;
|
||||||
|
ucByteVal2 &= ucByteMask;
|
||||||
|
}
|
||||||
|
if ( ucByteVal1 != ucByteVal2 )
|
||||||
|
{
|
||||||
|
sEqual = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return( sEqual );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: RetBit
|
||||||
|
* Description: return the (byte, bit) of lv (reading from left to right).
|
||||||
|
* Parameters: plv - ptr to lenval.
|
||||||
|
* iByte - the byte to get the bit from.
|
||||||
|
* iBit - the bit number (0=msb)
|
||||||
|
* Returns: short - the bit value.
|
||||||
|
*****************************************************************************/
|
||||||
|
short RetBit( lenVal* plv,
|
||||||
|
int iByte,
|
||||||
|
int iBit )
|
||||||
|
{
|
||||||
|
/* assert( ( iByte >= 0 ) && ( iByte < plv->len ) ); */
|
||||||
|
/* assert( ( iBit >= 0 ) && ( iBit < 8 ) ); */
|
||||||
|
return( (short)( ( plv->val[ iByte ] >> ( 7 - iBit ) ) & 0x1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: SetBit
|
||||||
|
* Description: set the (byte, bit) of lv equal to val
|
||||||
|
* Example: SetBit("00000000",byte, 1) equals "01000000".
|
||||||
|
* Parameters: plv - ptr to lenval.
|
||||||
|
* iByte - the byte to get the bit from.
|
||||||
|
* iBit - the bit number (0=msb).
|
||||||
|
* sVal - the bit value to set.
|
||||||
|
* Returns: void.
|
||||||
|
*****************************************************************************/
|
||||||
|
void SetBit( lenVal* plv,
|
||||||
|
int iByte,
|
||||||
|
int iBit,
|
||||||
|
short sVal )
|
||||||
|
{
|
||||||
|
unsigned char ucByteVal;
|
||||||
|
unsigned char ucBitMask;
|
||||||
|
|
||||||
|
ucBitMask = (unsigned char)(1 << ( 7 - iBit ));
|
||||||
|
ucByteVal = (unsigned char)(plv->val[ iByte ] & (~ucBitMask));
|
||||||
|
|
||||||
|
if ( sVal )
|
||||||
|
{
|
||||||
|
ucByteVal |= ucBitMask;
|
||||||
|
}
|
||||||
|
plv->val[ iByte ] = ucByteVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: AddVal
|
||||||
|
* Description: add val1 to val2 and store in resVal;
|
||||||
|
* assumes val1 and val2 are of equal length.
|
||||||
|
* Parameters: plvResVal - ptr to result.
|
||||||
|
* plvVal1 - ptr of addendum.
|
||||||
|
* plvVal2 - ptr of addendum.
|
||||||
|
* Returns: void.
|
||||||
|
*****************************************************************************/
|
||||||
|
void addVal( lenVal* plvResVal,
|
||||||
|
lenVal* plvVal1,
|
||||||
|
lenVal* plvVal2 )
|
||||||
|
{
|
||||||
|
unsigned char ucCarry;
|
||||||
|
unsigned short usSum;
|
||||||
|
unsigned short usVal1;
|
||||||
|
unsigned short usVal2;
|
||||||
|
short sIndex;
|
||||||
|
|
||||||
|
plvResVal->len = plvVal1->len; /* set up length of result */
|
||||||
|
|
||||||
|
/* start at least significant bit and add bytes */
|
||||||
|
ucCarry = 0;
|
||||||
|
sIndex = plvVal1->len;
|
||||||
|
while ( sIndex-- )
|
||||||
|
{
|
||||||
|
usVal1 = plvVal1->val[ sIndex ]; /* i'th byte of val1 */
|
||||||
|
usVal2 = plvVal2->val[ sIndex ]; /* i'th byte of val2 */
|
||||||
|
|
||||||
|
/* add the two bytes plus carry from previous addition */
|
||||||
|
usSum = (unsigned short)( usVal1 + usVal2 + ucCarry );
|
||||||
|
|
||||||
|
/* set up carry for next byte */
|
||||||
|
ucCarry = (unsigned char)( ( usSum > 255 ) ? 1 : 0 );
|
||||||
|
|
||||||
|
/* set the i'th byte of the result */
|
||||||
|
plvResVal->val[ sIndex ] = (unsigned char)usSum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: readVal
|
||||||
|
* Description: read from XSVF numBytes bytes of data into x.
|
||||||
|
* Parameters: plv - ptr to lenval in which to put the bytes read.
|
||||||
|
* sNumBytes - the number of bytes to read.
|
||||||
|
* Returns: void.
|
||||||
|
*****************************************************************************/
|
||||||
|
void readVal( lenVal* plv,
|
||||||
|
short sNumBytes )
|
||||||
|
{
|
||||||
|
unsigned char* pucVal;
|
||||||
|
|
||||||
|
plv->len = sNumBytes; /* set the length of the lenVal */
|
||||||
|
for ( pucVal = plv->val; sNumBytes; --sNumBytes, ++pucVal )
|
||||||
|
{
|
||||||
|
/* read a byte of data into the lenVal */
|
||||||
|
readByte( pucVal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
93
arduino/floppyemu/xsvf/lenval.h
Executable file
93
arduino/floppyemu/xsvf/lenval.h
Executable file
|
@ -0,0 +1,93 @@
|
||||||
|
/*******************************************************/
|
||||||
|
/* file: lenval.h */
|
||||||
|
/* abstract: This file contains a description of the */
|
||||||
|
/* data structure "lenval". */
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
#ifndef lenval_dot_h
|
||||||
|
#define lenval_dot_h
|
||||||
|
|
||||||
|
/* the lenVal structure is a byte oriented type used to store an */
|
||||||
|
/* arbitrary length binary value. As an example, the hex value */
|
||||||
|
/* 0x0e3d is represented as a lenVal with len=2 (since 2 bytes */
|
||||||
|
/* and val[0]=0e and val[1]=3d. val[2-MAX_LEN] are undefined */
|
||||||
|
|
||||||
|
/* maximum length (in bytes) of value to read in */
|
||||||
|
/* this needs to be at least 4, and longer than the */
|
||||||
|
/* length of the longest SDR instruction. If there is, */
|
||||||
|
/* only 1 device in the chain, MAX_LEN must be at least */
|
||||||
|
/* ceil(27/8) == 4. For 6 devices in a chain, MAX_LEN */
|
||||||
|
/* must be 5, for 14 devices MAX_LEN must be 6, for 20 */
|
||||||
|
/* devices MAX_LEN must be 7, etc.. */
|
||||||
|
/* You can safely set MAX_LEN to a smaller number if you*/
|
||||||
|
/* know how many devices will be in your chain. */
|
||||||
|
/* #define MAX_LEN (Actual #define is below this comment block)
|
||||||
|
This #define defines the maximum length (in bytes) of predefined
|
||||||
|
buffers in which the XSVF player stores the current shift data.
|
||||||
|
This length must be greater than the longest shift length (in bytes)
|
||||||
|
in the XSVF files that will be processed. 7000 is a very conservative
|
||||||
|
number. The buffers are stored on the stack and if you have limited
|
||||||
|
stack space, you may decrease the MAX_LEN value.
|
||||||
|
|
||||||
|
How to find the "shift length" in bits?
|
||||||
|
Look at the ASCII version of the XSVF (generated with the -a option
|
||||||
|
for the SVF2XSVF translator) and search for the XSDRSIZE command
|
||||||
|
with the biggest parameter. XSDRSIZE is equivalent to the SVF's
|
||||||
|
SDR length plus the lengths of applicable HDR and TDR commands.
|
||||||
|
Remember that the MAX_LEN is defined in bytes. Therefore, the
|
||||||
|
minimum MAX_LEN = ceil( max( XSDRSIZE ) / 8 );
|
||||||
|
|
||||||
|
The following MAX_LEN values have been tested and provide relatively
|
||||||
|
good margin for the corresponding devices:
|
||||||
|
|
||||||
|
DEVICE MAX_LEN Resulting Shift Length Max (in bits)
|
||||||
|
--------- ------- ----------------------------------------------
|
||||||
|
XC9500/XL/XV 32 256
|
||||||
|
|
||||||
|
CoolRunner/II 256 2048 - actual max 1 device = 1035 bits
|
||||||
|
|
||||||
|
FPGA 128 1024 - svf2xsvf -rlen 1024
|
||||||
|
|
||||||
|
XC18V00/XCF00
|
||||||
|
1100 8800 - no blank check performed (default)
|
||||||
|
- actual max 1 device = 8192 bits verify
|
||||||
|
- max 1 device = 4096 bits program-only
|
||||||
|
|
||||||
|
XC18V00/XCF00 when using the optional Blank Check operation
|
||||||
|
2500 20000 - required for blank check
|
||||||
|
- blank check max 1 device = 16384 bits
|
||||||
|
*/
|
||||||
|
#define MAX_LEN 32
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct var_len_byte
|
||||||
|
{
|
||||||
|
short len; /* number of chars in this value */
|
||||||
|
unsigned char val[MAX_LEN+1]; /* bytes of data */
|
||||||
|
} lenVal;
|
||||||
|
|
||||||
|
|
||||||
|
/* return the long representation of a lenVal */
|
||||||
|
extern long value(lenVal *x);
|
||||||
|
|
||||||
|
/* set lenVal equal to value */
|
||||||
|
extern void initLenVal(lenVal *x, long value);
|
||||||
|
|
||||||
|
/* check if expected equals actual (taking the mask into account) */
|
||||||
|
extern short EqualLenVal(lenVal *expected, lenVal *actual, lenVal *mask);
|
||||||
|
|
||||||
|
/* add val1+val2 and put the result in resVal */
|
||||||
|
extern void addVal(lenVal *resVal, lenVal *val1, lenVal *val2);
|
||||||
|
|
||||||
|
/* return the (byte, bit) of lv (reading from left to right) */
|
||||||
|
extern short RetBit(lenVal *lv, int byte, int bit);
|
||||||
|
|
||||||
|
/* set the (byte, bit) of lv equal to val (e.g. SetBit("00000000",byte, 1)
|
||||||
|
equals "01000000" */
|
||||||
|
extern void SetBit(lenVal *lv, int byte, int bit, short val);
|
||||||
|
|
||||||
|
/* read from XSVF numBytes bytes of data into x */
|
||||||
|
extern void readVal(lenVal *x, short numBytes);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
1820
arduino/floppyemu/xsvf/micro.cpp
Executable file
1820
arduino/floppyemu/xsvf/micro.cpp
Executable file
File diff suppressed because it is too large
Load Diff
42
arduino/floppyemu/xsvf/micro.h
Executable file
42
arduino/floppyemu/xsvf/micro.h
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* File: micro.h
|
||||||
|
* Description: This header file contains the function prototype to the
|
||||||
|
* primary interface function for the XSVF player.
|
||||||
|
* Usage: FIRST - PORTS.C
|
||||||
|
* Customize the ports.c function implementations to establish
|
||||||
|
* the correct protocol for communicating with your JTAG ports
|
||||||
|
* (setPort() and readTDOBit()) and tune the waitTime() delay
|
||||||
|
* function. Also, establish access to the XSVF data source
|
||||||
|
* in the readByte() function.
|
||||||
|
* FINALLY - Call xsvfExecute().
|
||||||
|
*****************************************************************************/
|
||||||
|
#ifndef XSVF_MICRO_H
|
||||||
|
#define XSVF_MICRO_H
|
||||||
|
|
||||||
|
/* Legacy error codes for xsvfExecute from original XSVF player v2.0 */
|
||||||
|
#define XSVF_LEGACY_SUCCESS 1
|
||||||
|
#define XSVF_LEGACY_ERROR 0
|
||||||
|
|
||||||
|
/* 4.04 [NEW] Error codes for xsvfExecute. */
|
||||||
|
/* Must #define XSVF_SUPPORT_ERRORCODES in micro.c to get these codes */
|
||||||
|
#define XSVF_ERROR_NONE 0
|
||||||
|
#define XSVF_ERROR_UNKNOWN 1
|
||||||
|
#define XSVF_ERROR_TDOMISMATCH 2
|
||||||
|
#define XSVF_ERROR_MAXRETRIES 3 /* TDO mismatch after max retries */
|
||||||
|
#define XSVF_ERROR_ILLEGALCMD 4
|
||||||
|
#define XSVF_ERROR_ILLEGALSTATE 5
|
||||||
|
#define XSVF_ERROR_DATAOVERFLOW 6 /* Data > lenVal MAX_LEN buffer size*/
|
||||||
|
/* Insert new errors here */
|
||||||
|
#define XSVF_ERROR_LAST 7
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function: xsvfExecute
|
||||||
|
* Description: Process, interpret, and apply the XSVF commands.
|
||||||
|
* See port.c:readByte for source of XSVF data.
|
||||||
|
* Parameters: none.
|
||||||
|
* Returns: int - For error codes see above.
|
||||||
|
*****************************************************************************/
|
||||||
|
extern int xsvfExecute();
|
||||||
|
|
||||||
|
#endif /* XSVF_MICRO_H */
|
||||||
|
|
135
arduino/floppyemu/xsvf/ports.cpp
Executable file
135
arduino/floppyemu/xsvf/ports.cpp
Executable file
|
@ -0,0 +1,135 @@
|
||||||
|
#include <math.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "ports.h"
|
||||||
|
|
||||||
|
#define TMS_PORT PORTC
|
||||||
|
#define TMS_PIN 3
|
||||||
|
|
||||||
|
#define TCK_PORT PORTC
|
||||||
|
#define TCK_PIN 2
|
||||||
|
|
||||||
|
#define TDO_PORT PINC
|
||||||
|
#define TDO_PIN 4
|
||||||
|
|
||||||
|
#define TDI_PORT PORTC
|
||||||
|
#define TDI_PIN 5
|
||||||
|
|
||||||
|
/* setPort: Implement to set the named JTAG signal (p) to the new value (v).*/
|
||||||
|
void setPort(short p,short val)
|
||||||
|
{
|
||||||
|
if (p==TMS)
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
TMS_PORT |= (1<<TMS_PIN);
|
||||||
|
else
|
||||||
|
TMS_PORT &= ~(1<<TMS_PIN);
|
||||||
|
}
|
||||||
|
else if (p==TDI)
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
TDI_PORT |= (1<<TDI_PIN);
|
||||||
|
else
|
||||||
|
TDI_PORT &= ~(1<<TDI_PIN);
|
||||||
|
}
|
||||||
|
else if (p==TCK)
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
TCK_PORT |= (1<<TCK_PIN);
|
||||||
|
else
|
||||||
|
TCK_PORT &= ~(1<<TCK_PIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* toggle tck LH. No need to modify this code. It is output via setPort. */
|
||||||
|
void pulseClock()
|
||||||
|
{
|
||||||
|
setPort(TCK,0); /* set the TCK port to low */
|
||||||
|
setPort(TCK,1); /* set the TCK port to high */
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadFuncPtr pReadFunc = 0;
|
||||||
|
void setReadCallback(ReadFuncPtr p)
|
||||||
|
{
|
||||||
|
pReadFunc = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* readByte: Implement to source the next byte from your XSVF file location */
|
||||||
|
/* read in a byte of data from the prom */
|
||||||
|
void readByte(unsigned char *data)
|
||||||
|
{
|
||||||
|
if (pReadFunc)
|
||||||
|
*data = pReadFunc();
|
||||||
|
else
|
||||||
|
*data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* readTDOBit: Implement to return the current value of the JTAG TDO signal.*/
|
||||||
|
/* read the TDO bit from port */
|
||||||
|
unsigned char readTDOBit()
|
||||||
|
{
|
||||||
|
return bit_is_set(TDO_PORT, TDO_PIN) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* waitTime: Implement as follows: */
|
||||||
|
/* REQUIRED: This function must consume/wait at least the specified number */
|
||||||
|
/* of microsec, interpreting microsec as a number of microseconds.*/
|
||||||
|
/* REQUIRED FOR SPARTAN/VIRTEX FPGAs and indirect flash programming: */
|
||||||
|
/* This function must pulse TCK for at least microsec times, */
|
||||||
|
/* interpreting microsec as an integer value. */
|
||||||
|
/* RECOMMENDED IMPLEMENTATION: Pulse TCK at least microsec times AND */
|
||||||
|
/* continue pulsing TCK until the microsec wait */
|
||||||
|
/* requirement is also satisfied. */
|
||||||
|
void waitTime(long microsec)
|
||||||
|
{
|
||||||
|
static long tckCyclesPerMicrosec = 1; /* must be at least 1 */
|
||||||
|
long tckCycles = microsec * tckCyclesPerMicrosec;
|
||||||
|
long i;
|
||||||
|
|
||||||
|
// For Floppy Emu, tckCyclesPerMicrosec = 1 results in wait times about 3x longer than necessary.
|
||||||
|
|
||||||
|
/* This implementation is highly recommended!!! */
|
||||||
|
/* This implementation requires you to tune the tckCyclesPerMicrosec
|
||||||
|
variable (above) to match the performance of your embedded system
|
||||||
|
in order to satisfy the microsec wait time requirement. */
|
||||||
|
for ( i = 0; i < tckCycles; ++i )
|
||||||
|
{
|
||||||
|
pulseClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Alternate implementation */
|
||||||
|
/* For systems with TCK rates << 1 MHz; Consider this implementation. */
|
||||||
|
/* This implementation does not work with Spartan-3AN or indirect flash
|
||||||
|
programming. */
|
||||||
|
if ( microsec >= 50L )
|
||||||
|
{
|
||||||
|
/* Make sure TCK is low during wait for XC18V00/XCFxxS */
|
||||||
|
/* Or, a running TCK implementation as shown above is an OK alternate */
|
||||||
|
setPort( TCK, 0 );
|
||||||
|
|
||||||
|
/* Use Windows Sleep(). Round up to the nearest millisec */
|
||||||
|
_sleep( ( microsec + 999L ) / 1000L );
|
||||||
|
}
|
||||||
|
else /* Satisfy FPGA JTAG configuration, startup TCK cycles */
|
||||||
|
{
|
||||||
|
for ( i = 0; i < microsec; ++i )
|
||||||
|
{
|
||||||
|
pulseClock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Alternate implementation */
|
||||||
|
/* This implementation is valid for only XC9500/XL/XV, CoolRunner/II CPLDs,
|
||||||
|
XC18V00 PROMs, or Platform Flash XCFxxS/XCFxxP PROMs.
|
||||||
|
This implementation does not work with FPGAs JTAG configuration. */
|
||||||
|
/* Make sure TCK is low during wait for XC18V00/XCFxxS PROMs */
|
||||||
|
/* Or, a running TCK implementation as shown above is an OK alternate */
|
||||||
|
setPort( TCK, 0 );
|
||||||
|
/* Use Windows Sleep(). Round up to the nearest millisec */
|
||||||
|
_sleep( ( microsec + 999L ) / 1000L );
|
||||||
|
#endif
|
||||||
|
}
|
36
arduino/floppyemu/xsvf/ports.h
Executable file
36
arduino/floppyemu/xsvf/ports.h
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
/*******************************************************/
|
||||||
|
/* file: ports.h */
|
||||||
|
/* abstract: This file contains extern declarations */
|
||||||
|
/* for providing stimulus to the JTAG ports.*/
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
#ifndef ports_dot_h
|
||||||
|
#define ports_dot_h
|
||||||
|
|
||||||
|
/* these constants are used to send the appropriate ports to setPort */
|
||||||
|
/* they should be enumerated types, but some of the microcontroller */
|
||||||
|
/* compilers don't like enumerated types */
|
||||||
|
#define TCK (short) 0
|
||||||
|
#define TMS (short) 1
|
||||||
|
#define TDI (short) 2
|
||||||
|
|
||||||
|
/* set the port "p" (TCK, TMS, or TDI) to val (0 or 1) */
|
||||||
|
extern void setPort(short p, short val);
|
||||||
|
|
||||||
|
/* read the TDO bit and store it in val */
|
||||||
|
extern unsigned char readTDOBit();
|
||||||
|
|
||||||
|
/* make clock go down->up->down*/
|
||||||
|
extern void pulseClock();
|
||||||
|
|
||||||
|
/* read the next byte of data from the xsvf file */
|
||||||
|
extern void readByte(unsigned char *data);
|
||||||
|
|
||||||
|
extern void waitTime(long microsec);
|
||||||
|
|
||||||
|
/* set the callback function used to read the next byte of the xsvf data */
|
||||||
|
typedef unsigned char (*ReadFuncPtr)(void);
|
||||||
|
extern void setReadCallback(ReadFuncPtr p);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
BIN
arduino/instructions.docx
Executable file
BIN
arduino/instructions.docx
Executable file
Binary file not shown.
3
arduino/license.txt
Executable file
3
arduino/license.txt
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
Floppy Emu was designed and developed by Steve Chamberlin, "Big Mess o' Wires", copyright 2013. The source files, schematics, and related materials are licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported license. To learn more about the CC BY-NC 3.0 license, see http://creativecommons.org/licenses/by-nc/3.0/
|
||||||
|
|
||||||
|
You're free to build a Floppy Emu for personal use, or adapt and share the design for other non-commercial projects. Please do not build a batch of Floppy Emus and sell them on eBay. If you need a commercial license or another non-creative-commons license, contact steve@bigmessowires.com.
|
BIN
arduino/~$bom.xlsx
Executable file
BIN
arduino/~$bom.xlsx
Executable file
Binary file not shown.
BIN
arduino/~$cost.xlsx
Executable file
BIN
arduino/~$cost.xlsx
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user