47 changed files with 22121 additions and 346 deletions
@ -1,248 +1,255 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> |
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> |
||||
<storageModule moduleId="org.eclipse.cdt.core.settings"> |
<storageModule moduleId="org.eclipse.cdt.core.settings"> |
||||
<cconfiguration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094"> |
<cconfiguration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094"> |
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094" moduleId="org.eclipse.cdt.core.settings" name="Debug"> |
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094" moduleId="org.eclipse.cdt.core.settings" name="Debug"> |
||||
<externalSettings /> |
<externalSettings/> |
||||
<extensions> |
<extensions> |
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser" /> |
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> |
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" 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.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser" /> |
<extension id="org.eclipse.cdt.core.GmakeErrorParser" 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.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser" /> |
<extension id="org.eclipse.cdt.core.CWDLocator" 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.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||
</extensions> |
</extensions> |
||||
</storageModule> |
</storageModule> |
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
||||
<configuration artifactName="rtthread" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="${cross_rm} -rf" description="" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094" name="Debug" parent="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug"> |
<configuration artifactName="rtthread" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="${cross_rm} -rf" description="" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094" name="Debug" parent="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug" postbuildStep="arm-none-eabi-objcopy -O ihex "rtthread.elf" "${ProjName}.hex""> |
||||
<folderInfo id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094." name="/" resourcePath=""> |
<folderInfo id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094." name="/" resourcePath=""> |
||||
<toolChain id="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug.1201710416" name="ARM Cross GCC" superClass="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug"> |
<toolChain id="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug.1201710416" name="ARM Cross GCC" superClass="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash.251260409" name="Create flash image" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash.251260409" name="Create flash image" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createlisting.1365878149" name="Create extended listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createlisting" useByScannerDiscovery="false" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createlisting.1365878149" name="Create extended listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createlisting" useByScannerDiscovery="false"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize.709136944" name="Print size" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize.709136944" name="Print size" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.1986446770" name="Optimization Level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.none" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.1986446770" name="Optimization Level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.none" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength.1312975261" name="Message length (-fmessage-length=0)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength" useByScannerDiscovery="true" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength.1312975261" name="Message length (-fmessage-length=0)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength" useByScannerDiscovery="true" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar.1538128212" name="'char' is signed (-fsigned-char)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar" useByScannerDiscovery="true" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar.1538128212" name="'char' is signed (-fsigned-char)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar" useByScannerDiscovery="true" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections.2136804218" name="Function sections (-ffunction-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections" useByScannerDiscovery="true" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections.2136804218" name="Function sections (-ffunction-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections" useByScannerDiscovery="true" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections.244767666" name="Data sections (-fdata-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections" useByScannerDiscovery="true" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections.244767666" name="Data sections (-fdata-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections" useByScannerDiscovery="true" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.1055848773" name="Debug level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.default" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.1055848773" name="Debug level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.default" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.501941135" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.dwarf2" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.501941135" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.dwarf2" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.1696308067" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" useByScannerDiscovery="false" value="GNU Tools for ARM Embedded Processors" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.1696308067" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" useByScannerDiscovery="false" value="GNU Tools for ARM Embedded Processors" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.1558403188" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.architecture" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.arm" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.1558403188" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.architecture" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.arm" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.749415257" name="ARM family" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m7" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.749415257" name="ARM family" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m7" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.2114153533" name="Instruction set" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.thumb" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.2114153533" name="Instruction set" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.thumb" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.1600865811" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.1600865811" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.1109963929" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" useByScannerDiscovery="false" value="gcc" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.1109963929" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" useByScannerDiscovery="false" value="gcc" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp.1040883831" name="C++ compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp" useByScannerDiscovery="false" value="g++" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp.1040883831" name="C++ compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp" useByScannerDiscovery="false" value="g++" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar.1678200391" name="Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar" useByScannerDiscovery="false" value="ar" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar.1678200391" name="Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar" useByScannerDiscovery="false" value="ar" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy.1171840296" name="Hex/Bin converter" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy" useByScannerDiscovery="false" value="objcopy" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy.1171840296" name="Hex/Bin converter" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy" useByScannerDiscovery="false" value="objcopy" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump.342604837" name="Listing generator" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump" useByScannerDiscovery="false" value="objdump" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump.342604837" name="Listing generator" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump" useByScannerDiscovery="false" value="objdump" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.size.898269225" name="Size command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.size" useByScannerDiscovery="false" value="size" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.size.898269225" name="Size command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.size" useByScannerDiscovery="false" value="size" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.make.2016398076" name="Build command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.make" useByScannerDiscovery="false" value="make" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.make.2016398076" name="Build command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.make" useByScannerDiscovery="false" value="make" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm.1606171496" name="Remove command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm" useByScannerDiscovery="false" value="rm" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm.1606171496" name="Remove command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm" useByScannerDiscovery="false" value="rm" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id.540792084" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id" useByScannerDiscovery="false" value="1287942917" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id.540792084" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id" useByScannerDiscovery="false" value="1287942917" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture.430121817" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.arch.none" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture.430121817" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.arch.none" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.966735324" name="Float ABI" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.hard" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.966735324" name="Float ABI" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.hard" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.allwarn.1381561249" name="Enable all common warnings (-Wall)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.allwarn" useByScannerDiscovery="true" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.allwarn.1381561249" name="Enable all common warnings (-Wall)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.allwarn" useByScannerDiscovery="true" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.target.other.2041717463" name="Other target flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.target.other" useByScannerDiscovery="true" value="" valueType="string" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.target.other.2041717463" name="Other target flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.target.other" useByScannerDiscovery="true" value="" valueType="string"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.1463655269" name="FPU Type" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.fpv5spd16" valueType="enumerated" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.1463655269" name="FPU Type" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.fpv5spd16" valueType="enumerated"/> |
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.1798638225" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform" /> |
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.1798638225" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/> |
||||
<builder buildPath="${workspace_loc:/qemu-vexpress-a9}/Debug" cleanBuildTarget="clean2" id="ilg.gnuarmeclipse.managedbuild.cross.builder.1736709688" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="GNU Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="ilg.gnuarmeclipse.managedbuild.cross.builder" /> |
<builder buildPath="${workspace_loc:/qemu-vexpress-a9}/Debug" cleanBuildTarget="clean2" id="ilg.gnuarmeclipse.managedbuild.cross.builder.1736709688" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="GNU Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="ilg.gnuarmeclipse.managedbuild.cross.builder"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.1810966071" name="GNU ARM Cross Assembler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler"> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.1810966071" name="GNU ARM Cross Assembler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1072524326" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1072524326" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.include.paths.161242639" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.include.paths.161242639" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}""/> |
||||
</option> |
</option> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.defs.1521934876" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.defs" useByScannerDiscovery="true" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.defs.1521934876" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.defs" useByScannerDiscovery="true"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.flags.1325367962" name="Assembler flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.flags" useByScannerDiscovery="false" valueType="stringList"> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.flags.1325367962" name="Assembler flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.flags" useByScannerDiscovery="false" valueType="stringList"> |
||||
<listOptionValue builtIn="false" value="-mimplicit-it=thumb" /> |
<listOptionValue builtIn="false" value="-mimplicit-it=thumb"/> |
||||
</option> |
</option> |
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input.1843333483" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input" /> |
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input.1843333483" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input"/> |
||||
</tool> |
</tool> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.1570350559" name="GNU ARM Cross C Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler"> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.1570350559" name="GNU ARM Cross C Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler"> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths.634882052" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths.634882052" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/cubemx/Inc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/cubemx/Inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include//config}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include//config}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Device//ST//STM32H7xx//Include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Device//ST//STM32H7xx//Include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//RTOS//Template}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//RTOS//Template}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc//Legacy}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc//Legacy}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/.}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/.}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/applications}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/applications}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//.}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//.}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx/Inc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx/Inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/cJSON-v1.7.17}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/cJSON-v1.7.17}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/sqlite-v3.19.3}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/littlefs-v2.11.2}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/devfs}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/sqlite-v3.19.3}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/elmfat}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/devfs}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/tmpfs}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/elmfat}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/tmpfs}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/finsh}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi/sfud/inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/common/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/newlib}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/fal/inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/epoll}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/finsh}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/eventfd}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/common/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/poll}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/newlib}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/ipc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/epoll}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/eventfd}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/common}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/poll}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/cortex-m7}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/ipc}""/> |
||||
</option> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/include}""/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs.100549972" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols"> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/common}""/> |
||||
<listOptionValue builtIn="false" value="SOC_FAMILY_STM32" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/cortex-m7}""/> |
||||
<listOptionValue builtIn="false" value="SOC_SERIES_STM32H7" /> |
</option> |
||||
<listOptionValue builtIn="false" value="USE_HAL_DRIVER" /> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs.100549972" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols"> |
||||
<listOptionValue builtIn="false" value="STM32H743xx" /> |
<listOptionValue builtIn="false" value="SOC_FAMILY_STM32"/> |
||||
</option> |
<listOptionValue builtIn="false" value="SOC_SERIES_STM32H7"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.other.2133065240" name="Other compiler flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.other" useByScannerDiscovery="true" value="" valueType="string" /> |
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.files.714348818" name="Include files (-include)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.files" useByScannerDiscovery="true" valueType="includeFiles"> |
<listOptionValue builtIn="false" value="STM32H743xx"/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/rtconfig_preinc.h}"" /> |
</option> |
||||
</option> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.other.2133065240" name="Other compiler flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.other" useByScannerDiscovery="true" value="" valueType="string"/> |
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.992053063" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input" /> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.files.714348818" name="Include files (-include)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.files" useByScannerDiscovery="true" valueType="includeFiles"> |
||||
</tool> |
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/rtconfig_preinc.h}""/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.869072473" name="Cross ARM C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker"> |
</option> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections.1167322178" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.992053063" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostart.351692886" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostart" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
</tool> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostdlibs.1009243715" name="No startup or default libs (-nostdlib)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.869072473" name="Cross ARM C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nodeflibs.2016026082" name="Do not use default libraries (-nodefaultlibs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections.1167322178" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.usenewlibnano.923990336" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.usenewlibnano" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostart.351692886" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostart" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option defaultValue="true" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.shared.548869459" name="Shared (-shared)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.shared" useByScannerDiscovery="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostdlibs.1009243715" name="No startup or default libs (-nostdlib)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.scriptfile.1818777301" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.scriptfile" useByScannerDiscovery="false" valueType="stringList"> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nodeflibs.2016026082" name="Do not use default libraries (-nodefaultlibs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//linkscripts//STM32H743IITx//link.lds}"" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.usenewlibnano.923990336" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.usenewlibnano" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
</option> |
<option defaultValue="true" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.shared.548869459" name="Shared (-shared)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.shared" useByScannerDiscovery="false" valueType="boolean"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.libs.1135656995" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.libs" useByScannerDiscovery="false" valueType="libs"> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.scriptfile.1818777301" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.scriptfile" useByScannerDiscovery="false" valueType="stringList"> |
||||
<listOptionValue builtIn="false" value="c " /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//linkscripts//STM32H743IITx//link.lds}""/> |
||||
<listOptionValue builtIn="false" value="m " /> |
</option> |
||||
</option> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.libs.1135656995" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.libs" useByScannerDiscovery="false" valueType="libs"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.paths.36884122" name="Library search path (-L)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.paths" useByScannerDiscovery="false" /> |
<listOptionValue builtIn="false" value="c "/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.other.396049466" name="Other linker flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.other" useByScannerDiscovery="false" value="" valueType="string" /> |
<listOptionValue builtIn="false" value="m "/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.cref.1645737861" name="Cross reference (-Xlinker --cref)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.cref" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
</option> |
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.input.334732222" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.input"> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.paths.36884122" name="Library search path (-L)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.paths" useByScannerDiscovery="false"/> |
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.other.396049466" name="Other linker flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.other" useByScannerDiscovery="false" value="" valueType="string"/> |
||||
<additionalInput kind="additionalinput" paths="$(LIBS)" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.cref.1645737861" name="Cross reference (-Xlinker --cref)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.cref" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
</inputType> |
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.input.334732222" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.input"> |
||||
</tool> |
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.1601059928" name="GNU ARM Cross C++ Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker"> |
<additionalInput kind="additionalinput" paths="$(LIBS)"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections.437759352" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections" value="true" valueType="boolean" /> |
</inputType> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile.1101974459" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile" useByScannerDiscovery="false" valueType="stringList"> |
</tool> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//linkscripts//STM32H743IITx//link.lds}"" /> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.1601059928" name="GNU ARM Cross C++ Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker"> |
||||
</option> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections.437759352" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.cref.2007675975" name="Cross reference (-Xlinker --cref)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.cref" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile.1101974459" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile" useByScannerDiscovery="false" valueType="stringList"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano.2105838438" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano" useByScannerDiscovery="false" value="true" valueType="boolean" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//linkscripts//STM32H743IITx//link.lds}""/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs.934137837" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs" useByScannerDiscovery="false" valueType="libs"> |
</option> |
||||
<listOptionValue builtIn="false" value="c " /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.cref.2007675975" name="Cross reference (-Xlinker --cref)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.cref" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
<listOptionValue builtIn="false" value="m " /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano.2105838438" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano" useByScannerDiscovery="false" value="true" valueType="boolean"/> |
||||
</option> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs.934137837" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs" useByScannerDiscovery="false" valueType="libs"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart.2118356996" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<listOptionValue builtIn="false" value="c "/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nodeflibs.1427884346" name="Do not use default libraries (-nodefaultlibs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<listOptionValue builtIn="false" value="m "/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostdlibs.1433863653" name="No startup or default libs (-nostdlib)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
</option> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printgcsections.1387745410" name="Print removed sections (-Xlinker --print-gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printgcsections" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart.2118356996" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.strip.1230158061" name="Omit all symbol information (-s)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.strip" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nodeflibs.1427884346" name="Do not use default libraries (-nodefaultlibs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printmap.1307581821" name="Print link map (-Xlinker --print-map)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printmap" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostdlibs.1433863653" name="No startup or default libs (-nostdlib)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.useprintffloat.960778920" name="Use float with nano printf (-u _printf_float)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.useprintffloat" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printgcsections.1387745410" name="Print removed sections (-Xlinker --print-gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printgcsections" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usescanffloat.637205035" name="Use float with nano scanf (-u _scanf_float)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usescanffloat" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.strip.1230158061" name="Omit all symbol information (-s)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.strip" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnosys.1948314201" name="Do not use syscalls (--specs=nosys.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnosys" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printmap.1307581821" name="Print link map (-Xlinker --print-map)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.printmap" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.verbose.273162112" name="Verbose (-v)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.verbose" useByScannerDiscovery="false" value="false" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.useprintffloat.960778920" name="Use float with nano printf (-u _printf_float)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.useprintffloat" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths.1399535143" name="Library search path (-L)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths" useByScannerDiscovery="false" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usescanffloat.637205035" name="Use float with nano scanf (-u _scanf_float)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usescanffloat" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input.262373798" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input"> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnosys.1948314201" name="Do not use syscalls (--specs=nosys.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnosys" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.verbose.273162112" name="Verbose (-v)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.verbose" useByScannerDiscovery="false" value="false" valueType="boolean"/> |
||||
<additionalInput kind="additionalinput" paths="$(LIBS)" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths.1399535143" name="Library search path (-L)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths" useByScannerDiscovery="false"/> |
||||
</inputType> |
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input.262373798" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input"> |
||||
</tool> |
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver.506412204" name="GNU ARM Cross Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver" /> |
<additionalInput kind="additionalinput" paths="$(LIBS)"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash.1461589245" name="GNU ARM Cross Create Flash Image" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash"> |
</inputType> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice.1937707052" name="Output file format (-O)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice.binary" valueType="enumerated" /> |
</tool> |
||||
</tool> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver.506412204" name="GNU ARM Cross Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting.82359725" name="GNU ARM Cross Create Listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting"> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash.1461589245" name="GNU ARM Cross Create Flash Image" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source.601724476" name="Display source (--source|-S)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice.1937707052" name="Output file format (-O)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.createflash.choice.binary" valueType="enumerated"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders.692505279" name="Display all headers (--all-headers|-x)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders" value="true" valueType="boolean" /> |
</tool> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle.97345172" name="Demangle names (--demangle|-C)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle" value="true" valueType="boolean" /> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting.82359725" name="GNU ARM Cross Create Listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting"> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers.1342893377" name="Display line numbers (--line-numbers|-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source.601724476" name="Display source (--source|-S)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide.1533725981" name="Wide lines (--wide|-w)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide" value="true" valueType="boolean" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders.692505279" name="Display all headers (--all-headers|-x)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders" value="true" valueType="boolean"/> |
||||
</tool> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle.97345172" name="Demangle names (--demangle|-C)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle" value="true" valueType="boolean"/> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize.1073550295" name="GNU ARM Cross Print Size" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize"> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers.1342893377" name="Display line numbers (--line-numbers|-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers" value="true" valueType="boolean"/> |
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format.946451386" name="Size format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format" useByScannerDiscovery="false" /> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide.1533725981" name="Wide lines (--wide|-w)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide" value="true" valueType="boolean"/> |
||||
</tool> |
</tool> |
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.1302177015" name="GNU ARM Cross C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler"> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize.1073550295" name="GNU ARM Cross Print Size" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize"> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs.704468062" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols"> |
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format.946451386" name="Size format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format" useByScannerDiscovery="false"/> |
||||
<listOptionValue builtIn="false" value="SOC_FAMILY_STM32" /> |
</tool> |
||||
<listOptionValue builtIn="false" value="SOC_SERIES_STM32H7" /> |
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.1302177015" name="GNU ARM Cross C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler"> |
||||
<listOptionValue builtIn="false" value="USE_HAL_DRIVER" /> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs.704468062" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols"> |
||||
<listOptionValue builtIn="false" value="STM32H743xx" /> |
<listOptionValue builtIn="false" value="SOC_FAMILY_STM32"/> |
||||
</option> |
<listOptionValue builtIn="false" value="SOC_SERIES_STM32H7"/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths.302877723" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers}"" /> |
<listOptionValue builtIn="false" value="STM32H743xx"/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include}"" /> |
</option> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include//config}"" /> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths.302877723" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths" useByScannerDiscovery="true" valueType="includePath"> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Device//ST//STM32H7xx//Include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//RTOS//Template}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/drivers//include//config}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Device//ST//STM32H7xx//Include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc//Legacy}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//Include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/.}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//CMSIS//RTOS//Template}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/applications}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//.}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/libraries//STM32H7xx_HAL_Driver//Inc//Legacy}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx/Inc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/.}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}/applications}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/cJSON-v1.7.17}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//.}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/sqlite-v3.19.3}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx/Inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/devfs}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//cubemx}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/elmfat}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/cJSON-v1.7.17}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/tmpfs}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/littlefs-v2.11.2}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//packages/sqlite-v3.19.3}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/devfs}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/elmfat}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/finsh}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/filesystems/tmpfs}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/common/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/dfs/dfs_v1/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/newlib}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/epoll}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi/sfud/inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/eventfd}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/drivers/spi}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/poll}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/fal/inc}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/ipc}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/finsh}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/include}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/common/include}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/common}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/compilers/newlib}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/cortex-m7}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/epoll}""/> |
||||
</option> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/eventfd}""/> |
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.files.343249373" name="Include files (-include)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.files" useByScannerDiscovery="true" valueType="includeFiles"> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/io/poll}""/> |
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/rtconfig_preinc.h}"" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/components/libc/posix/ipc}""/> |
||||
</option> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/include}""/> |
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.45918001" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input" /> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/common}""/> |
||||
</tool> |
<listOptionValue builtIn="false" value=""${workspace_loc://${ProjName}//rt-thread/libcpu/arm/cortex-m7}""/> |
||||
</toolChain> |
</option> |
||||
</folderInfo> |
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.files.343249373" name="Include files (-include)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.files" useByScannerDiscovery="true" valueType="includeFiles"> |
||||
<sourceEntries> |
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/rtconfig_preinc.h}""/> |
||||
<entry excluding="packages/sqlite-v3.19.3/rtthread_vfs.c|//cubemx/Drivers|//cubemx/EWARM|//cubemx/Src/stm32h7xx_it.c|//cubemx/Src/system_stm32h7xx.c|//packages/sqlite-v3.19.3/dbhelper.c|//packages/sqlite-v3.19.3/rtthread_io_methods.c|//packages/sqlite-v3.19.3/rtthread_mutex.c|//packages/sqlite-v3.19.3/rtthread_vfs.c|//packages/sqlite-v3.19.3/shell.c|//packages/sqlite-v3.19.3/student_dao.c|//rt-thread/components/dfs/dfs_v1/filesystems/cromfs|//rt-thread/components/dfs/dfs_v1/filesystems/mqueue|//rt-thread/components/dfs/dfs_v1/filesystems/nfs|//rt-thread/components/dfs/dfs_v1/filesystems/ramfs|//rt-thread/components/dfs/dfs_v1/filesystems/romfs|//rt-thread/components/dfs/dfs_v1/filesystems/skeleton|//rt-thread/components/dfs/dfs_v2|//rt-thread/components/drivers/audio|//rt-thread/components/drivers/can|//rt-thread/components/drivers/clk|//rt-thread/components/drivers/core/dm.c|//rt-thread/components/drivers/core/driver.c|//rt-thread/components/drivers/core/platform.c|//rt-thread/components/drivers/core/platform_ofw.c|//rt-thread/components/drivers/cputime|//rt-thread/components/drivers/fdt|//rt-thread/components/drivers/hwcrypto|//rt-thread/components/drivers/hwtimer|//rt-thread/components/drivers/i2c|//rt-thread/components/drivers/ktime|//rt-thread/components/drivers/misc|//rt-thread/components/drivers/mtd|//rt-thread/components/drivers/ofw|//rt-thread/components/drivers/phy|//rt-thread/components/drivers/pic|//rt-thread/components/drivers/pin/pin_dm.c|//rt-thread/components/drivers/pin/pin_ofw.c|//rt-thread/components/drivers/pinctrl|//rt-thread/components/drivers/pm|//rt-thread/components/drivers/rtc/alarm.c|//rt-thread/components/drivers/sensor|//rt-thread/components/drivers/serial/serial_dm.c|//rt-thread/components/drivers/serial/serial_tty.c|//rt-thread/components/drivers/serial/serial_v2.c|//rt-thread/components/drivers/spi/enc28j60.c|//rt-thread/components/drivers/spi/sfud|//rt-thread/components/drivers/spi/spi-bit-ops.c|//rt-thread/components/drivers/spi/spi_flash_sfud.c|//rt-thread/components/drivers/spi/spi_wifi_rw009.c|//rt-thread/components/drivers/touch|//rt-thread/components/drivers/usb|//rt-thread/components/drivers/virtio|//rt-thread/components/drivers/watchdog|//rt-thread/components/drivers/wlan|//rt-thread/components/fal|//rt-thread/components/legacy|//rt-thread/components/libc/compilers/armlibc|//rt-thread/components/libc/compilers/dlib|//rt-thread/components/libc/compilers/musl|//rt-thread/components/libc/compilers/picolibc|//rt-thread/components/libc/cplusplus|//rt-thread/components/libc/posix|//rt-thread/components/lwp|//rt-thread/components/mm|//rt-thread/components/mprotect|//rt-thread/components/net|//rt-thread/components/utilities|//rt-thread/components/vbus|//rt-thread/libcpu/aarch64|//rt-thread/libcpu/arc|//rt-thread/libcpu/arm/AT91SAM7S|//rt-thread/libcpu/arm/AT91SAM7X|//rt-thread/libcpu/arm/am335x|//rt-thread/libcpu/arm/arm926|//rt-thread/libcpu/arm/armv6|//rt-thread/libcpu/arm/common/atomic_arm.c|//rt-thread/libcpu/arm/common/divsi3.S|//rt-thread/libcpu/arm/cortex-a|//rt-thread/libcpu/arm/cortex-m0|//rt-thread/libcpu/arm/cortex-m23|//rt-thread/libcpu/arm/cortex-m3|//rt-thread/libcpu/arm/cortex-m33|//rt-thread/libcpu/arm/cortex-m4|//rt-thread/libcpu/arm/cortex-m7/context_iar.S|//rt-thread/libcpu/arm/cortex-m7/context_rvds.S|//rt-thread/libcpu/arm/cortex-m7/mpu.c|//rt-thread/libcpu/arm/cortex-m85|//rt-thread/libcpu/arm/cortex-r4|//rt-thread/libcpu/arm/cortex-r52|//rt-thread/libcpu/arm/dm36x|//rt-thread/libcpu/arm/lpc214x|//rt-thread/libcpu/arm/lpc24xx|//rt-thread/libcpu/arm/realview-a8-vmm|//rt-thread/libcpu/arm/s3c24x0|//rt-thread/libcpu/arm/s3c44b0|//rt-thread/libcpu/arm/sep4020|//rt-thread/libcpu/arm/zynqmp-r5|//rt-thread/libcpu/avr32|//rt-thread/libcpu/blackfin|//rt-thread/libcpu/c-sky|//rt-thread/libcpu/ia32|//rt-thread/libcpu/m16c|//rt-thread/libcpu/mips|//rt-thread/libcpu/nios|//rt-thread/libcpu/ppc|//rt-thread/libcpu/risc-v|//rt-thread/libcpu/rx|//rt-thread/libcpu/sim|//rt-thread/libcpu/sparc-v8|//rt-thread/libcpu/ti-dsp|//rt-thread/libcpu/unicore32|//rt-thread/libcpu/v850|//rt-thread/libcpu/xilinx|//rt-thread/src/cpu.c|//rt-thread/src/mem.c|//rt-thread/src/scheduler_mp.c|//rt-thread/src/signal.c|//rt-thread/src/slab.c|//rt-thread/tools" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="" /> |
</option> |
||||
</sourceEntries> |
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.45918001" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/> |
||||
</configuration> |
</tool> |
||||
</storageModule> |
</toolChain> |
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings" /> |
</folderInfo> |
||||
</cconfiguration> |
<sourceEntries> |
||||
</storageModule> |
<entry excluding="packages/sqlite-v3.19.3/rtthread_vfs.c|//cubemx/Drivers|//cubemx/EWARM|//cubemx/Src/stm32h7xx_it.c|//cubemx/Src/system_stm32h7xx.c|//packages/littlefs-v2.11.2/runners|//packages/sqlite-v3.19.3/dbhelper.c|//packages/sqlite-v3.19.3/rtthread_io_methods.c|//packages/sqlite-v3.19.3/rtthread_mutex.c|//packages/sqlite-v3.19.3/rtthread_vfs.c|//packages/sqlite-v3.19.3/shell.c|//packages/sqlite-v3.19.3/student_dao.c|//rt-thread/components/dfs/dfs_v1/filesystems/cromfs|//rt-thread/components/dfs/dfs_v1/filesystems/mqueue|//rt-thread/components/dfs/dfs_v1/filesystems/nfs|//rt-thread/components/dfs/dfs_v1/filesystems/ramfs|//rt-thread/components/dfs/dfs_v1/filesystems/romfs|//rt-thread/components/dfs/dfs_v1/filesystems/skeleton|//rt-thread/components/dfs/dfs_v2|//rt-thread/components/drivers/audio|//rt-thread/components/drivers/can|//rt-thread/components/drivers/clk|//rt-thread/components/drivers/core/dm.c|//rt-thread/components/drivers/core/driver.c|//rt-thread/components/drivers/core/platform.c|//rt-thread/components/drivers/core/platform_ofw.c|//rt-thread/components/drivers/cputime|//rt-thread/components/drivers/fdt|//rt-thread/components/drivers/hwcrypto|//rt-thread/components/drivers/hwtimer|//rt-thread/components/drivers/i2c|//rt-thread/components/drivers/ktime|//rt-thread/components/drivers/misc|//rt-thread/components/drivers/mtd/mtd_nand.c|//rt-thread/components/drivers/ofw|//rt-thread/components/drivers/phy|//rt-thread/components/drivers/pic|//rt-thread/components/drivers/pin/pin_dm.c|//rt-thread/components/drivers/pin/pin_ofw.c|//rt-thread/components/drivers/pinctrl|//rt-thread/components/drivers/pm|//rt-thread/components/drivers/rtc/alarm.c|//rt-thread/components/drivers/sensor|//rt-thread/components/drivers/serial/serial_dm.c|//rt-thread/components/drivers/serial/serial_tty.c|//rt-thread/components/drivers/serial/serial_v2.c|//rt-thread/components/drivers/spi/enc28j60.c|//rt-thread/components/drivers/spi/spi-bit-ops.c|//rt-thread/components/drivers/spi/spi_wifi_rw009.c|//rt-thread/components/drivers/touch|//rt-thread/components/drivers/usb|//rt-thread/components/drivers/virtio|//rt-thread/components/drivers/watchdog|//rt-thread/components/drivers/wlan|//rt-thread/components/fal/samples/porting/fal_flash_stm32f2_port.c|//rt-thread/components/legacy|//rt-thread/components/libc/compilers/armlibc|//rt-thread/components/libc/compilers/dlib|//rt-thread/components/libc/compilers/musl|//rt-thread/components/libc/compilers/picolibc|//rt-thread/components/libc/cplusplus|//rt-thread/components/libc/posix|//rt-thread/components/lwp|//rt-thread/components/mm|//rt-thread/components/mprotect|//rt-thread/components/net|//rt-thread/components/utilities|//rt-thread/components/vbus|//rt-thread/libcpu/aarch64|//rt-thread/libcpu/arc|//rt-thread/libcpu/arm/AT91SAM7S|//rt-thread/libcpu/arm/AT91SAM7X|//rt-thread/libcpu/arm/am335x|//rt-thread/libcpu/arm/arm926|//rt-thread/libcpu/arm/armv6|//rt-thread/libcpu/arm/common/atomic_arm.c|//rt-thread/libcpu/arm/common/divsi3.S|//rt-thread/libcpu/arm/cortex-a|//rt-thread/libcpu/arm/cortex-m0|//rt-thread/libcpu/arm/cortex-m23|//rt-thread/libcpu/arm/cortex-m3|//rt-thread/libcpu/arm/cortex-m33|//rt-thread/libcpu/arm/cortex-m4|//rt-thread/libcpu/arm/cortex-m7/context_iar.S|//rt-thread/libcpu/arm/cortex-m7/context_rvds.S|//rt-thread/libcpu/arm/cortex-m7/mpu.c|//rt-thread/libcpu/arm/cortex-m85|//rt-thread/libcpu/arm/cortex-r4|//rt-thread/libcpu/arm/cortex-r52|//rt-thread/libcpu/arm/dm36x|//rt-thread/libcpu/arm/lpc214x|//rt-thread/libcpu/arm/lpc24xx|//rt-thread/libcpu/arm/realview-a8-vmm|//rt-thread/libcpu/arm/s3c24x0|//rt-thread/libcpu/arm/s3c44b0|//rt-thread/libcpu/arm/sep4020|//rt-thread/libcpu/arm/zynqmp-r5|//rt-thread/libcpu/avr32|//rt-thread/libcpu/blackfin|//rt-thread/libcpu/c-sky|//rt-thread/libcpu/ia32|//rt-thread/libcpu/m16c|//rt-thread/libcpu/mips|//rt-thread/libcpu/nios|//rt-thread/libcpu/ppc|//rt-thread/libcpu/risc-v|//rt-thread/libcpu/rx|//rt-thread/libcpu/sim|//rt-thread/libcpu/sparc-v8|//rt-thread/libcpu/ti-dsp|//rt-thread/libcpu/unicore32|//rt-thread/libcpu/v850|//rt-thread/libcpu/xilinx|//rt-thread/src/cpu.c|//rt-thread/src/mem.c|//rt-thread/src/scheduler_mp.c|//rt-thread/src/signal.c|//rt-thread/src/slab.c|//rt-thread/tools" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> |
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
</sourceEntries> |
||||
<project id="qemu-vexpress-a9.ilg.gnuarmeclipse.managedbuild.cross.target.elf.860020518" name="Executable" projectType="ilg.gnuarmeclipse.managedbuild.cross.target.elf" /> |
</configuration> |
||||
</storageModule> |
</storageModule> |
||||
<storageModule moduleId="scannerConfiguration"> |
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> |
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="" /> |
<storageModule moduleId="ilg.gnumcueclipse.managedbuild.packs"/> |
||||
<scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094;ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094.;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.1570350559;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.992053063"> |
</cconfiguration> |
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="" /> |
</storageModule> |
||||
</scannerConfigBuildInfo> |
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
||||
</storageModule> |
<project id="qemu-vexpress-a9.ilg.gnuarmeclipse.managedbuild.cross.target.elf.860020518" name="Executable" projectType="ilg.gnuarmeclipse.managedbuild.cross.target.elf"/> |
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders" /> |
</storageModule> |
||||
<storageModule moduleId="refreshScope" versionNumber="2"> |
<storageModule moduleId="scannerConfiguration"> |
||||
<configuration configurationName="Debug"> |
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> |
||||
<resource resourceType="PROJECT" workspacePath="/828F" /> |
<scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094;ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.553091094.;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.1570350559;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.992053063"> |
||||
</configuration> |
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> |
||||
</storageModule> |
</scannerConfigBuildInfo> |
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets" /> |
</storageModule> |
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"> |
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> |
||||
<doc-comment-owner id="org.eclipse.cdt.ui.doxygen"> |
<storageModule moduleId="refreshScope" versionNumber="2"> |
||||
<path value="" /> |
<configuration configurationName="Debug"> |
||||
</doc-comment-owner> |
<resource resourceType="PROJECT" workspacePath="/project"/> |
||||
</storageModule> |
</configuration> |
||||
|
</storageModule> |
||||
|
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> |
||||
|
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"> |
||||
|
<doc-comment-owner id="org.eclipse.cdt.ui.doxygen"> |
||||
|
<path value=""/> |
||||
|
</doc-comment-owner> |
||||
|
</storageModule> |
||||
</cproject> |
</cproject> |
||||
|
|||||
Binary file not shown.
@ -0,0 +1,128 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 2006-2021, RT-Thread Development Team |
||||
|
* |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
* |
||||
|
* Change Logs: |
||||
|
* Date Author Notes |
||||
|
* 2025-11-22 Administrator the first version |
||||
|
*//*
|
||||
|
* Copyright (c) 2006-2021, RT-Thread Development Team |
||||
|
* |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
* |
||||
|
* Change Logs: |
||||
|
* Date Author Notes |
||||
|
* 2025-11-22 Administrator the first version |
||||
|
*/ |
||||
|
#include <rtthread.h> |
||||
|
#include <rtdevice.h> |
||||
|
#include "fal_cfg.h" |
||||
|
#include "spi_flash.h" |
||||
|
#include "spi_flash_sfud.h" |
||||
|
#include "drv_qspi.h" |
||||
|
#include "dfs_fs.h" |
||||
|
#include "fal.h" |
||||
|
|
||||
|
/* 添加 DEBUG 头文件 */ |
||||
|
#include <rtdbg.h> |
||||
|
|
||||
|
char w25qxx_read_status_register2(struct rt_qspi_device *device) |
||||
|
{ |
||||
|
/* 0x35 read status register2 */ |
||||
|
char instruction = 0x35, status; |
||||
|
rt_qspi_send_then_recv(device, &instruction, 1, &status, 1); |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
void w25qxx_write_enable(struct rt_qspi_device *device) |
||||
|
{ |
||||
|
/* 0x06 write enable */ |
||||
|
char instruction = 0x06; |
||||
|
rt_qspi_send(device, &instruction, 1); |
||||
|
} |
||||
|
|
||||
|
void w25qxx_enter_qspi_mode(struct rt_qspi_device *device) |
||||
|
{ |
||||
|
char status = 0; |
||||
|
/* 0x38 enter qspi mode */ |
||||
|
char instruction = 0x38; |
||||
|
char write_status2_buf[2] = {0}; |
||||
|
/* 0x31 write status register2 */ |
||||
|
write_status2_buf[0] = 0x31; |
||||
|
status = w25qxx_read_status_register2(device); |
||||
|
if (!(status & 0x02)) |
||||
|
{ |
||||
|
status |= 1 << 1; |
||||
|
w25qxx_write_enable(device); |
||||
|
write_status2_buf[1] = status; |
||||
|
rt_qspi_send(device, &write_status2_buf, 2); |
||||
|
rt_qspi_send(device, &instruction, 1); |
||||
|
LOG_D("flash already enter qspi mode"); |
||||
|
rt_thread_mdelay(10); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int spi_flash_init(void) |
||||
|
{ |
||||
|
rt_err_t ret = stm32_qspi_bus_attach_device("qspi1", "qspi10", RT_NULL, 4, w25qxx_enter_qspi_mode, RT_NULL); |
||||
|
if (ret != RT_EOK) |
||||
|
{ |
||||
|
LOG_E("qspi attach device failed\n"); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
/* init W25Q256 */ |
||||
|
// spi_flash_dev_name 需要用配置文件内的,spi_dev_name实际是SPI挂在参数
|
||||
|
if(rt_sfud_flash_probe(FAL_USING_NOR_FLASH_DEV_NAME, "qspi10") == RT_NULL) |
||||
|
{ |
||||
|
LOG_E("rt sfud flash error"); |
||||
|
return -1; |
||||
|
} |
||||
|
LOG_I("SFUD flash '%s' probed successfully.", FAL_USING_NOR_FLASH_DEV_NAME); |
||||
|
/* 初始化 fal */ |
||||
|
int fal_ = fal_init(); |
||||
|
if (fal_ > 0) |
||||
|
{ |
||||
|
LOG_I("FAL Number of partitions = %d",fal_); |
||||
|
}else{ |
||||
|
return -1; |
||||
|
} |
||||
|
/* 创建 MTD 块设备 */ |
||||
|
if (fal_mtd_nor_device_create("sysdata") == RT_NULL) |
||||
|
{ |
||||
|
LOG_E("Failed to create MTD device for sysdata!"); |
||||
|
return -1; |
||||
|
} |
||||
|
LOG_I("MTD device 'sysdata' created."); |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
INIT_DEVICE_EXPORT(spi_flash_init); |
||||
|
|
||||
|
int qspi_fal(void) |
||||
|
{ |
||||
|
LOG_I("Create file path /sys"); |
||||
|
mkdir("/sys", 0777); |
||||
|
|
||||
|
/* 挂载 littlefs */ |
||||
|
if (dfs_mount("sysdata", "/sys", "lfs", 0, NULL) == RT_EOK) |
||||
|
{ |
||||
|
LOG_I("Filesystem initialized!"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
LOG_E("Format memory sysdata"); |
||||
|
/* 格式化文件系统 */ |
||||
|
dfs_mkfs("lfs", "sysdata"); |
||||
|
/* 挂载 littlefs */ |
||||
|
if (dfs_mount("sysdata", "/sys", "lfs", 0, NULL) == RT_EOK) |
||||
|
{ |
||||
|
LOG_I("Filesystem initialized!"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
LOG_E("Failed to initialize filesystem!"); |
||||
|
} |
||||
|
} |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
INIT_APP_EXPORT(qspi_fal); |
||||
@ -0,0 +1,30 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 2006-2021, RT-Thread Development Team |
||||
|
* |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
* |
||||
|
* Change Logs: |
||||
|
* Date Author Notes |
||||
|
* 2025-11-22 Administrator the first version |
||||
|
*/ |
||||
|
#ifndef _FAL_CFG_H_ |
||||
|
#define _FAL_CFG_H_ |
||||
|
|
||||
|
#include <rtconfig.h> |
||||
|
#include <fal.h> |
||||
|
|
||||
|
extern struct fal_flash_dev nor_flash0; |
||||
|
|
||||
|
/* flash device table */ |
||||
|
#define FAL_FLASH_DEV_TABLE \ |
||||
|
{ \ |
||||
|
&nor_flash0, \ |
||||
|
} |
||||
|
|
||||
|
/* 分区表:根据你的需求划分 */ |
||||
|
#define FAL_PART_TABLE \ |
||||
|
{ \ |
||||
|
{FAL_PART_MAGIC_WORD, "sysdata","W25Q128", 0, 16 * 1024 * 1024, 0 }, \ |
||||
|
} |
||||
|
|
||||
|
#endif /* _FAL_CFG_H_ */ |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,747 @@ |
|||||
|
/**
|
||||
|
****************************************************************************** |
||||
|
* @file stm32h7xx_hal_qspi.h |
||||
|
* @author MCD Application Team |
||||
|
* @brief Header file of QSPI HAL module. |
||||
|
****************************************************************************** |
||||
|
* @attention |
||||
|
* |
||||
|
* Copyright (c) 2017 STMicroelectronics. |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under terms that can be found in the LICENSE file |
||||
|
* in the root directory of this software component. |
||||
|
* If no LICENSE file comes with this software, it is provided AS-IS. |
||||
|
* |
||||
|
****************************************************************************** |
||||
|
*/ |
||||
|
|
||||
|
/* Define to prevent recursive inclusion -------------------------------------*/ |
||||
|
#ifndef STM32H7xx_HAL_QSPI_H |
||||
|
#define STM32H7xx_HAL_QSPI_H |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
/* Includes ------------------------------------------------------------------*/ |
||||
|
#include "stm32h7xx_hal_def.h" |
||||
|
#if defined (DLYB_QUADSPI) |
||||
|
#include "stm32h7xx_ll_delayblock.h" |
||||
|
#endif /* DLYB_QUADSPI */ |
||||
|
|
||||
|
#if defined(QUADSPI) |
||||
|
|
||||
|
/** @addtogroup STM32H7xx_HAL_Driver
|
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/** @addtogroup QSPI
|
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/* Exported types ------------------------------------------------------------*/ |
||||
|
/** @defgroup QSPI_Exported_Types QSPI Exported Types
|
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/**
|
||||
|
* @brief QSPI Init structure definition |
||||
|
*/ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint32_t ClockPrescaler; /* Specifies the prescaler factor for generating clock based on the AHB clock.
|
||||
|
This parameter can be a number between 0 and 255 */ |
||||
|
uint32_t FifoThreshold; /* Specifies the threshold number of bytes in the FIFO (used only in indirect mode)
|
||||
|
This parameter can be a value between 1 and 32 */ |
||||
|
uint32_t SampleShifting; /* Specifies the Sample Shift. The data is sampled 1/2 clock cycle delay later to
|
||||
|
take in account external signal delays. (It should be QSPI_SAMPLE_SHIFTING_NONE in DDR mode) |
||||
|
This parameter can be a value of @ref QSPI_SampleShifting */ |
||||
|
uint32_t FlashSize; /* Specifies the Flash Size. FlashSize+1 is effectively the number of address bits
|
||||
|
required to address the flash memory. The flash capacity can be up to 4GB |
||||
|
(addressed using 32 bits) in indirect mode, but the addressable space in |
||||
|
memory-mapped mode is limited to 256MB |
||||
|
This parameter can be a number between 0 and 31 */ |
||||
|
uint32_t ChipSelectHighTime; /* Specifies the Chip Select High Time. ChipSelectHighTime+1 defines the minimum number
|
||||
|
of clock cycles which the chip select must remain high between commands. |
||||
|
This parameter can be a value of @ref QSPI_ChipSelectHighTime */ |
||||
|
uint32_t ClockMode; /* Specifies the Clock Mode. It indicates the level that clock takes between commands.
|
||||
|
This parameter can be a value of @ref QSPI_ClockMode */ |
||||
|
uint32_t FlashID; /* Specifies the Flash which will be used,
|
||||
|
This parameter can be a value of @ref QSPI_Flash_Select */ |
||||
|
uint32_t DualFlash; /* Specifies the Dual Flash Mode State
|
||||
|
This parameter can be a value of @ref QSPI_DualFlash_Mode */ |
||||
|
}QSPI_InitTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief HAL QSPI State structures definition |
||||
|
*/ |
||||
|
typedef enum |
||||
|
{ |
||||
|
HAL_QSPI_STATE_RESET = 0x00U, /*!< Peripheral not initialized */ |
||||
|
HAL_QSPI_STATE_READY = 0x01U, /*!< Peripheral initialized and ready for use */ |
||||
|
HAL_QSPI_STATE_BUSY = 0x02U, /*!< Peripheral in indirect mode and busy */ |
||||
|
HAL_QSPI_STATE_BUSY_INDIRECT_TX = 0x12U, /*!< Peripheral in indirect mode with transmission ongoing */ |
||||
|
HAL_QSPI_STATE_BUSY_INDIRECT_RX = 0x22U, /*!< Peripheral in indirect mode with reception ongoing */ |
||||
|
HAL_QSPI_STATE_BUSY_AUTO_POLLING = 0x42U, /*!< Peripheral in auto polling mode ongoing */ |
||||
|
HAL_QSPI_STATE_BUSY_MEM_MAPPED = 0x82U, /*!< Peripheral in memory mapped mode ongoing */ |
||||
|
HAL_QSPI_STATE_ABORT = 0x08U, /*!< Peripheral with abort request ongoing */ |
||||
|
HAL_QSPI_STATE_ERROR = 0x04U /*!< Peripheral in error */ |
||||
|
}HAL_QSPI_StateTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief QSPI Handle Structure definition |
||||
|
*/ |
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
typedef struct __QSPI_HandleTypeDef |
||||
|
#else |
||||
|
typedef struct |
||||
|
#endif |
||||
|
{ |
||||
|
QUADSPI_TypeDef *Instance; /* QSPI registers base address */ |
||||
|
QSPI_InitTypeDef Init; /* QSPI communication parameters */ |
||||
|
uint8_t *pTxBuffPtr; /* Pointer to QSPI Tx transfer Buffer */ |
||||
|
__IO uint32_t TxXferSize; /* QSPI Tx Transfer size */ |
||||
|
__IO uint32_t TxXferCount; /* QSPI Tx Transfer Counter */ |
||||
|
uint8_t *pRxBuffPtr; /* Pointer to QSPI Rx transfer Buffer */ |
||||
|
__IO uint32_t RxXferSize; /* QSPI Rx Transfer size */ |
||||
|
__IO uint32_t RxXferCount; /* QSPI Rx Transfer Counter */ |
||||
|
MDMA_HandleTypeDef *hmdma; /* QSPI Rx/Tx MDMA Handle parameters */ |
||||
|
__IO HAL_LockTypeDef Lock; /* Locking object */ |
||||
|
__IO HAL_QSPI_StateTypeDef State; /* QSPI communication state */ |
||||
|
__IO uint32_t ErrorCode; /* QSPI Error code */ |
||||
|
uint32_t Timeout; /* Timeout for the QSPI memory access */ |
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
void (* ErrorCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* AbortCpltCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* FifoThresholdCallback)(struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* CmdCpltCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* RxCpltCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* TxCpltCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* StatusMatchCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* TimeOutCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
void (* MspInitCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
void (* MspDeInitCallback) (struct __QSPI_HandleTypeDef *hqspi); |
||||
|
#endif |
||||
|
}QSPI_HandleTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief QSPI Command structure definition |
||||
|
*/ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint32_t Instruction; /* Specifies the Instruction to be sent
|
||||
|
This parameter can be a value (8-bit) between 0x00 and 0xFF */ |
||||
|
uint32_t Address; /* Specifies the Address to be sent (Size from 1 to 4 bytes according AddressSize)
|
||||
|
This parameter can be a value (32-bits) between 0x0 and 0xFFFFFFFF */ |
||||
|
uint32_t AlternateBytes; /* Specifies the Alternate Bytes to be sent (Size from 1 to 4 bytes according AlternateBytesSize)
|
||||
|
This parameter can be a value (32-bits) between 0x0 and 0xFFFFFFFF */ |
||||
|
uint32_t AddressSize; /* Specifies the Address Size
|
||||
|
This parameter can be a value of @ref QSPI_AddressSize */ |
||||
|
uint32_t AlternateBytesSize; /* Specifies the Alternate Bytes Size
|
||||
|
This parameter can be a value of @ref QSPI_AlternateBytesSize */ |
||||
|
uint32_t DummyCycles; /* Specifies the Number of Dummy Cycles.
|
||||
|
This parameter can be a number between 0 and 31 */ |
||||
|
uint32_t InstructionMode; /* Specifies the Instruction Mode
|
||||
|
This parameter can be a value of @ref QSPI_InstructionMode */ |
||||
|
uint32_t AddressMode; /* Specifies the Address Mode
|
||||
|
This parameter can be a value of @ref QSPI_AddressMode */ |
||||
|
uint32_t AlternateByteMode; /* Specifies the Alternate Bytes Mode
|
||||
|
This parameter can be a value of @ref QSPI_AlternateBytesMode */ |
||||
|
uint32_t DataMode; /* Specifies the Data Mode (used for dummy cycles and data phases)
|
||||
|
This parameter can be a value of @ref QSPI_DataMode */ |
||||
|
uint32_t NbData; /* Specifies the number of data to transfer. (This is the number of bytes)
|
||||
|
This parameter can be any value between 0 and 0xFFFFFFFF (0 means undefined length |
||||
|
until end of memory)*/ |
||||
|
uint32_t DdrMode; /* Specifies the double data rate mode for address, alternate byte and data phase
|
||||
|
This parameter can be a value of @ref QSPI_DdrMode */ |
||||
|
uint32_t DdrHoldHalfCycle; /* Specifies if the DDR hold is enabled. When enabled it delays the data
|
||||
|
output by one half of system clock in DDR mode. |
||||
|
This parameter can be a value of @ref QSPI_DdrHoldHalfCycle */ |
||||
|
uint32_t SIOOMode; /* Specifies the send instruction only once mode
|
||||
|
This parameter can be a value of @ref QSPI_SIOOMode */ |
||||
|
}QSPI_CommandTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief QSPI Auto Polling mode configuration structure definition |
||||
|
*/ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint32_t Match; /* Specifies the value to be compared with the masked status register to get a match.
|
||||
|
This parameter can be any value between 0 and 0xFFFFFFFF */ |
||||
|
uint32_t Mask; /* Specifies the mask to be applied to the status bytes received.
|
||||
|
This parameter can be any value between 0 and 0xFFFFFFFF */ |
||||
|
uint32_t Interval; /* Specifies the number of clock cycles between two read during automatic polling phases.
|
||||
|
This parameter can be any value between 0 and 0xFFFF */ |
||||
|
uint32_t StatusBytesSize; /* Specifies the size of the status bytes received.
|
||||
|
This parameter can be any value between 1 and 4 */ |
||||
|
uint32_t MatchMode; /* Specifies the method used for determining a match.
|
||||
|
This parameter can be a value of @ref QSPI_MatchMode */ |
||||
|
uint32_t AutomaticStop; /* Specifies if automatic polling is stopped after a match.
|
||||
|
This parameter can be a value of @ref QSPI_AutomaticStop */ |
||||
|
}QSPI_AutoPollingTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief QSPI Memory Mapped mode configuration structure definition |
||||
|
*/ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint32_t TimeOutPeriod; /* Specifies the number of clock to wait when the FIFO is full before to release the chip select.
|
||||
|
This parameter can be any value between 0 and 0xFFFF */ |
||||
|
uint32_t TimeOutActivation; /* Specifies if the timeout counter is enabled to release the chip select.
|
||||
|
This parameter can be a value of @ref QSPI_TimeOutActivation */ |
||||
|
}QSPI_MemoryMappedTypeDef; |
||||
|
|
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
/**
|
||||
|
* @brief HAL QSPI Callback ID enumeration definition |
||||
|
*/ |
||||
|
typedef enum |
||||
|
{ |
||||
|
HAL_QSPI_ERROR_CB_ID = 0x00U, /*!< QSPI Error Callback ID */ |
||||
|
HAL_QSPI_ABORT_CB_ID = 0x01U, /*!< QSPI Abort Callback ID */ |
||||
|
HAL_QSPI_FIFO_THRESHOLD_CB_ID = 0x02U, /*!< QSPI FIFO Threshold Callback ID */ |
||||
|
HAL_QSPI_CMD_CPLT_CB_ID = 0x03U, /*!< QSPI Command Complete Callback ID */ |
||||
|
HAL_QSPI_RX_CPLT_CB_ID = 0x04U, /*!< QSPI Rx Complete Callback ID */ |
||||
|
HAL_QSPI_TX_CPLT_CB_ID = 0x05U, /*!< QSPI Tx Complete Callback ID */ |
||||
|
HAL_QSPI_STATUS_MATCH_CB_ID = 0x08U, /*!< QSPI Status Match Callback ID */ |
||||
|
HAL_QSPI_TIMEOUT_CB_ID = 0x09U, /*!< QSPI Timeout Callback ID */ |
||||
|
|
||||
|
HAL_QSPI_MSP_INIT_CB_ID = 0x0AU, /*!< QSPI MspInit Callback ID */ |
||||
|
HAL_QSPI_MSP_DEINIT_CB_ID = 0x0B0 /*!< QSPI MspDeInit Callback ID */ |
||||
|
}HAL_QSPI_CallbackIDTypeDef; |
||||
|
|
||||
|
/**
|
||||
|
* @brief HAL QSPI Callback pointer definition |
||||
|
*/ |
||||
|
typedef void (*pQSPI_CallbackTypeDef)(QSPI_HandleTypeDef *hqspi); |
||||
|
#endif |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/* Exported constants --------------------------------------------------------*/ |
||||
|
/** @defgroup QSPI_Exported_Constants QSPI Exported Constants
|
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_ErrorCode QSPI Error Code
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define HAL_QSPI_ERROR_NONE 0x00000000U /*!< No error */ |
||||
|
#define HAL_QSPI_ERROR_TIMEOUT 0x00000001U /*!< Timeout error */ |
||||
|
#define HAL_QSPI_ERROR_TRANSFER 0x00000002U /*!< Transfer error */ |
||||
|
#define HAL_QSPI_ERROR_DMA 0x00000004U /*!< DMA transfer error */ |
||||
|
#define HAL_QSPI_ERROR_INVALID_PARAM 0x00000008U /*!< Invalid parameters error */ |
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
#define HAL_QSPI_ERROR_INVALID_CALLBACK 0x00000010U /*!< Invalid callback error */ |
||||
|
#endif |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_SampleShifting QSPI Sample Shifting
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_SAMPLE_SHIFTING_NONE 0x00000000U /*!<No clock cycle shift to sample data*/ |
||||
|
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT) /*!<1/2 clock cycle shift to sample data*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_ChipSelectHighTime QSPI ChipSelect High Time
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_CS_HIGH_TIME_1_CYCLE 0x00000000U /*!<nCS stay high for at least 1 clock cycle between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_2_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_0) /*!<nCS stay high for at least 2 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_3_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_1) /*!<nCS stay high for at least 3 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_4_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1) /*!<nCS stay high for at least 4 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_5_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_2) /*!<nCS stay high for at least 5 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_6_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0) /*!<nCS stay high for at least 6 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_7_CYCLE ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1) /*!<nCS stay high for at least 7 clock cycles between commands*/ |
||||
|
#define QSPI_CS_HIGH_TIME_8_CYCLE ((uint32_t)QUADSPI_DCR_CSHT) /*!<nCS stay high for at least 8 clock cycles between commands*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_ClockMode QSPI Clock Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_CLOCK_MODE_0 0x00000000U /*!<Clk stays low while nCS is released*/ |
||||
|
#define QSPI_CLOCK_MODE_3 ((uint32_t)QUADSPI_DCR_CKMODE) /*!<Clk goes high while nCS is released*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_Flash_Select QSPI Flash Select
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_FLASH_ID_1 0x00000000U /*!<FLASH 1 selected*/ |
||||
|
#define QSPI_FLASH_ID_2 ((uint32_t)QUADSPI_CR_FSEL) /*!<FLASH 2 selected*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_DualFlash_Mode QSPI Dual Flash Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_DUALFLASH_ENABLE ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/ |
||||
|
#define QSPI_DUALFLASH_DISABLE 0x00000000U /*!<Dual-flash mode disabled*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_AddressSize QSPI Address Size
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_ADDRESS_8_BITS 0x00000000U /*!<8-bit address*/ |
||||
|
#define QSPI_ADDRESS_16_BITS ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/ |
||||
|
#define QSPI_ADDRESS_24_BITS ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/ |
||||
|
#define QSPI_ADDRESS_32_BITS ((uint32_t)QUADSPI_CCR_ADSIZE) /*!<32-bit address*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_AlternateBytesSize QSPI Alternate Bytes Size
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_8_BITS 0x00000000U /*!<8-bit alternate bytes*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_16_BITS ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_24_BITS ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_32_BITS ((uint32_t)QUADSPI_CCR_ABSIZE) /*!<32-bit alternate bytes*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_InstructionMode QSPI Instruction Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_INSTRUCTION_NONE 0x00000000U /*!<No instruction*/ |
||||
|
#define QSPI_INSTRUCTION_1_LINE ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/ |
||||
|
#define QSPI_INSTRUCTION_2_LINES ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/ |
||||
|
#define QSPI_INSTRUCTION_4_LINES ((uint32_t)QUADSPI_CCR_IMODE) /*!<Instruction on four lines*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_AddressMode QSPI Address Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_ADDRESS_NONE 0x00000000U /*!<No address*/ |
||||
|
#define QSPI_ADDRESS_1_LINE ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/ |
||||
|
#define QSPI_ADDRESS_2_LINES ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/ |
||||
|
#define QSPI_ADDRESS_4_LINES ((uint32_t)QUADSPI_CCR_ADMODE) /*!<Address on four lines*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_AlternateBytesMode QSPI Alternate Bytes Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_NONE 0x00000000U /*!<No alternate bytes*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_1_LINE ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_2_LINES ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/ |
||||
|
#define QSPI_ALTERNATE_BYTES_4_LINES ((uint32_t)QUADSPI_CCR_ABMODE) /*!<Alternate bytes on four lines*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_DataMode QSPI Data Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_DATA_NONE 0x00000000U /*!<No data*/ |
||||
|
#define QSPI_DATA_1_LINE ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/ |
||||
|
#define QSPI_DATA_2_LINES ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/ |
||||
|
#define QSPI_DATA_4_LINES ((uint32_t)QUADSPI_CCR_DMODE) /*!<Data on four lines*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_DdrMode QSPI DDR Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_DDR_MODE_DISABLE 0x00000000U /*!<Double data rate mode disabled*/ |
||||
|
#define QSPI_DDR_MODE_ENABLE ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_DdrHoldHalfCycle QSPI DDR Data Output Delay
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_DDR_HHC_ANALOG_DELAY 0x00000000U /*!<Delay the data output using analog delay in DDR mode*/ |
||||
|
#define QSPI_DDR_HHC_HALF_CLK_DELAY ((uint32_t)QUADSPI_CCR_DHHC) /*!<Delay the data output by one half of system clock in DDR mode*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_SIOOMode QSPI Send Instruction Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_SIOO_INST_EVERY_CMD 0x00000000U /*!<Send instruction on every transaction*/ |
||||
|
#define QSPI_SIOO_INST_ONLY_FIRST_CMD ((uint32_t)QUADSPI_CCR_SIOO) /*!<Send instruction only for the first command*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_MatchMode QSPI Match Mode
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_MATCH_MODE_AND 0x00000000U /*!<AND match mode between unmasked bits*/ |
||||
|
#define QSPI_MATCH_MODE_OR ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_AutomaticStop QSPI Automatic Stop
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_AUTOMATIC_STOP_DISABLE 0x00000000U /*!<AutoPolling stops only with abort or QSPI disabling*/ |
||||
|
#define QSPI_AUTOMATIC_STOP_ENABLE ((uint32_t)QUADSPI_CR_APMS) /*!<AutoPolling stops as soon as there is a match*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_TimeOutActivation QSPI Timeout Activation
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_TIMEOUT_COUNTER_DISABLE 0x00000000U /*!<Timeout counter disabled, nCS remains active*/ |
||||
|
#define QSPI_TIMEOUT_COUNTER_ENABLE ((uint32_t)QUADSPI_CR_TCEN) /*!<Timeout counter enabled, nCS released when timeout expires*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_Flags QSPI Flags
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_FLAG_BUSY QUADSPI_SR_BUSY /*!<Busy flag: operation is ongoing*/ |
||||
|
#define QSPI_FLAG_TO QUADSPI_SR_TOF /*!<Timeout flag: timeout occurs in memory-mapped mode*/ |
||||
|
#define QSPI_FLAG_SM QUADSPI_SR_SMF /*!<Status match flag: received data matches in autopolling mode*/ |
||||
|
#define QSPI_FLAG_FT QUADSPI_SR_FTF /*!<Fifo threshold flag: Fifo threshold reached or data left after read from memory is complete*/ |
||||
|
#define QSPI_FLAG_TC QUADSPI_SR_TCF /*!<Transfer complete flag: programmed number of data have been transferred or the transfer has been aborted*/ |
||||
|
#define QSPI_FLAG_TE QUADSPI_SR_TEF /*!<Transfer error flag: invalid address is being accessed*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_Interrupts QSPI Interrupts
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define QSPI_IT_TO QUADSPI_CR_TOIE /*!<Interrupt on the timeout flag*/ |
||||
|
#define QSPI_IT_SM QUADSPI_CR_SMIE /*!<Interrupt on the status match flag*/ |
||||
|
#define QSPI_IT_FT QUADSPI_CR_FTIE /*!<Interrupt on the fifo threshold flag*/ |
||||
|
#define QSPI_IT_TC QUADSPI_CR_TCIE /*!<Interrupt on the transfer complete flag*/ |
||||
|
#define QSPI_IT_TE QUADSPI_CR_TEIE /*!<Interrupt on the transfer error flag*/ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @defgroup QSPI_Timeout_definition QSPI Timeout definition
|
||||
|
* @brief QSPI Timeout definition |
||||
|
* @{ |
||||
|
*/ |
||||
|
#define HAL_QSPI_TIMEOUT_DEFAULT_VALUE 5000U /* 5 s */ |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/* Exported macros -----------------------------------------------------------*/ |
||||
|
/** @defgroup QSPI_Exported_Macros QSPI Exported Macros
|
||||
|
* @{ |
||||
|
*/ |
||||
|
/** @brief Reset QSPI handle state.
|
||||
|
* @param __HANDLE__ QSPI handle. |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
#define __HAL_QSPI_RESET_HANDLE_STATE(__HANDLE__) do { \ |
||||
|
(__HANDLE__)->State = HAL_QSPI_STATE_RESET; \ |
||||
|
(__HANDLE__)->MspInitCallback = NULL; \ |
||||
|
(__HANDLE__)->MspDeInitCallback = NULL; \ |
||||
|
} while(0) |
||||
|
#else |
||||
|
#define __HAL_QSPI_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_QSPI_STATE_RESET) |
||||
|
#endif |
||||
|
|
||||
|
/** @brief Enable the QSPI peripheral.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_ENABLE(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CR, QUADSPI_CR_EN) |
||||
|
|
||||
|
/** @brief Disable the QSPI peripheral.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_DISABLE(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CR, QUADSPI_CR_EN) |
||||
|
|
||||
|
/** @brief Enable the specified QSPI interrupt.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @param __INTERRUPT__ specifies the QSPI interrupt source to enable. |
||||
|
* This parameter can be one of the following values: |
||||
|
* @arg QSPI_IT_TO: QSPI Timeout interrupt |
||||
|
* @arg QSPI_IT_SM: QSPI Status match interrupt |
||||
|
* @arg QSPI_IT_FT: QSPI FIFO threshold interrupt |
||||
|
* @arg QSPI_IT_TC: QSPI Transfer complete interrupt |
||||
|
* @arg QSPI_IT_TE: QSPI Transfer error interrupt |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_ENABLE_IT(__HANDLE__, __INTERRUPT__) SET_BIT((__HANDLE__)->Instance->CR, (__INTERRUPT__)) |
||||
|
|
||||
|
|
||||
|
/** @brief Disable the specified QSPI interrupt.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @param __INTERRUPT__ specifies the QSPI interrupt source to disable. |
||||
|
* This parameter can be one of the following values: |
||||
|
* @arg QSPI_IT_TO: QSPI Timeout interrupt |
||||
|
* @arg QSPI_IT_SM: QSPI Status match interrupt |
||||
|
* @arg QSPI_IT_FT: QSPI FIFO threshold interrupt |
||||
|
* @arg QSPI_IT_TC: QSPI Transfer complete interrupt |
||||
|
* @arg QSPI_IT_TE: QSPI Transfer error interrupt |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_DISABLE_IT(__HANDLE__, __INTERRUPT__) CLEAR_BIT((__HANDLE__)->Instance->CR, (__INTERRUPT__)) |
||||
|
|
||||
|
/** @brief Check whether the specified QSPI interrupt source is enabled or not.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @param __INTERRUPT__ specifies the QSPI interrupt source to check. |
||||
|
* This parameter can be one of the following values: |
||||
|
* @arg QSPI_IT_TO: QSPI Timeout interrupt |
||||
|
* @arg QSPI_IT_SM: QSPI Status match interrupt |
||||
|
* @arg QSPI_IT_FT: QSPI FIFO threshold interrupt |
||||
|
* @arg QSPI_IT_TC: QSPI Transfer complete interrupt |
||||
|
* @arg QSPI_IT_TE: QSPI Transfer error interrupt |
||||
|
* @retval The new state of __INTERRUPT__ (TRUE or FALSE). |
||||
|
*/ |
||||
|
#define __HAL_QSPI_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) (READ_BIT((__HANDLE__)->Instance->CR, (__INTERRUPT__)) == (__INTERRUPT__)) |
||||
|
|
||||
|
/**
|
||||
|
* @brief Check whether the selected QSPI flag is set or not. |
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @param __FLAG__ specifies the QSPI flag to check. |
||||
|
* This parameter can be one of the following values: |
||||
|
* @arg QSPI_FLAG_BUSY: QSPI Busy flag |
||||
|
* @arg QSPI_FLAG_TO: QSPI Timeout flag |
||||
|
* @arg QSPI_FLAG_SM: QSPI Status match flag |
||||
|
* @arg QSPI_FLAG_FT: QSPI FIFO threshold flag |
||||
|
* @arg QSPI_FLAG_TC: QSPI Transfer complete flag |
||||
|
* @arg QSPI_FLAG_TE: QSPI Transfer error flag |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_GET_FLAG(__HANDLE__, __FLAG__) ((READ_BIT((__HANDLE__)->Instance->SR, (__FLAG__)) != 0U) ? SET : RESET) |
||||
|
|
||||
|
/** @brief Clears the specified QSPI's flag status.
|
||||
|
* @param __HANDLE__ specifies the QSPI Handle. |
||||
|
* @param __FLAG__ specifies the QSPI clear register flag that needs to be set |
||||
|
* This parameter can be one of the following values: |
||||
|
* @arg QSPI_FLAG_TO: QSPI Timeout flag |
||||
|
* @arg QSPI_FLAG_SM: QSPI Status match flag |
||||
|
* @arg QSPI_FLAG_TC: QSPI Transfer complete flag |
||||
|
* @arg QSPI_FLAG_TE: QSPI Transfer error flag |
||||
|
* @retval None |
||||
|
*/ |
||||
|
#define __HAL_QSPI_CLEAR_FLAG(__HANDLE__, __FLAG__) WRITE_REG((__HANDLE__)->Instance->FCR, (__FLAG__)) |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/* Exported functions --------------------------------------------------------*/ |
||||
|
/** @addtogroup QSPI_Exported_Functions
|
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/** @addtogroup QSPI_Exported_Functions_Group1
|
||||
|
* @{ |
||||
|
*/ |
||||
|
/* Initialization/de-initialization functions ********************************/ |
||||
|
HAL_StatusTypeDef HAL_QSPI_Init (QSPI_HandleTypeDef *hqspi); |
||||
|
HAL_StatusTypeDef HAL_QSPI_DeInit (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_MspInit (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi); |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @addtogroup QSPI_Exported_Functions_Group2
|
||||
|
* @{ |
||||
|
*/ |
||||
|
/* IO operation functions *****************************************************/ |
||||
|
/* QSPI IRQ handler method */ |
||||
|
void HAL_QSPI_IRQHandler(QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
/* QSPI indirect mode */ |
||||
|
HAL_StatusTypeDef HAL_QSPI_Command (QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Transmit (QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Receive (QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Command_IT (QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Transmit_IT (QSPI_HandleTypeDef *hqspi, uint8_t *pData); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Receive_IT (QSPI_HandleTypeDef *hqspi, uint8_t *pData); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Transmit_DMA (QSPI_HandleTypeDef *hqspi, uint8_t *pData); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Receive_DMA (QSPI_HandleTypeDef *hqspi, uint8_t *pData); |
||||
|
|
||||
|
/* QSPI status flag polling mode */ |
||||
|
HAL_StatusTypeDef HAL_QSPI_AutoPolling (QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout); |
||||
|
HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg); |
||||
|
|
||||
|
/* QSPI memory-mapped mode */ |
||||
|
HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg); |
||||
|
|
||||
|
/* Callback functions in non-blocking modes ***********************************/ |
||||
|
void HAL_QSPI_ErrorCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_AbortCpltCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_FifoThresholdCallback(QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
/* QSPI indirect mode */ |
||||
|
void HAL_QSPI_CmdCpltCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_RxCpltCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_TxCpltCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
/* QSPI status flag polling mode */ |
||||
|
void HAL_QSPI_StatusMatchCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
/* QSPI memory-mapped mode */ |
||||
|
void HAL_QSPI_TimeOutCallback (QSPI_HandleTypeDef *hqspi); |
||||
|
|
||||
|
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1) |
||||
|
/* QSPI callback registering/unregistering */ |
||||
|
HAL_StatusTypeDef HAL_QSPI_RegisterCallback (QSPI_HandleTypeDef *hqspi, HAL_QSPI_CallbackIDTypeDef CallbackId, pQSPI_CallbackTypeDef pCallback); |
||||
|
HAL_StatusTypeDef HAL_QSPI_UnRegisterCallback (QSPI_HandleTypeDef *hqspi, HAL_QSPI_CallbackIDTypeDef CallbackId); |
||||
|
#endif |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/** @addtogroup QSPI_Exported_Functions_Group3
|
||||
|
* @{ |
||||
|
*/ |
||||
|
/* Peripheral Control and State functions ************************************/ |
||||
|
HAL_QSPI_StateTypeDef HAL_QSPI_GetState (const QSPI_HandleTypeDef *hqspi); |
||||
|
uint32_t HAL_QSPI_GetError (const QSPI_HandleTypeDef *hqspi); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Abort (QSPI_HandleTypeDef *hqspi); |
||||
|
HAL_StatusTypeDef HAL_QSPI_Abort_IT (QSPI_HandleTypeDef *hqspi); |
||||
|
void HAL_QSPI_SetTimeout (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); |
||||
|
HAL_StatusTypeDef HAL_QSPI_SetFifoThreshold(QSPI_HandleTypeDef *hqspi, uint32_t Threshold); |
||||
|
uint32_t HAL_QSPI_GetFifoThreshold(const QSPI_HandleTypeDef *hqspi); |
||||
|
HAL_StatusTypeDef HAL_QSPI_SetFlashID (QSPI_HandleTypeDef *hqspi, uint32_t FlashID); |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
/* End of exported functions -------------------------------------------------*/ |
||||
|
|
||||
|
/* Private macros ------------------------------------------------------------*/ |
||||
|
/** @defgroup QSPI_Private_Macros QSPI Private Macros
|
||||
|
* @{ |
||||
|
*/ |
||||
|
#define IS_QSPI_CLOCK_PRESCALER(PRESCALER) ((PRESCALER) <= 0xFFU) |
||||
|
|
||||
|
#define IS_QSPI_FIFO_THRESHOLD(THR) (((THR) > 0U) && ((THR) <= 32U)) |
||||
|
|
||||
|
#define IS_QSPI_SSHIFT(SSHIFT) (((SSHIFT) == QSPI_SAMPLE_SHIFTING_NONE) || \ |
||||
|
((SSHIFT) == QSPI_SAMPLE_SHIFTING_HALFCYCLE)) |
||||
|
|
||||
|
#define IS_QSPI_FLASH_SIZE(FSIZE) (((FSIZE) <= 31U)) |
||||
|
|
||||
|
#define IS_QSPI_CS_HIGH_TIME(CSHTIME) (((CSHTIME) == QSPI_CS_HIGH_TIME_1_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_2_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_3_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_4_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_5_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_6_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_7_CYCLE) || \ |
||||
|
((CSHTIME) == QSPI_CS_HIGH_TIME_8_CYCLE)) |
||||
|
|
||||
|
#define IS_QSPI_CLOCK_MODE(CLKMODE) (((CLKMODE) == QSPI_CLOCK_MODE_0) || \ |
||||
|
((CLKMODE) == QSPI_CLOCK_MODE_3)) |
||||
|
|
||||
|
#define IS_QSPI_FLASH_ID(FLASH_ID) (((FLASH_ID) == QSPI_FLASH_ID_1) || \ |
||||
|
((FLASH_ID) == QSPI_FLASH_ID_2)) |
||||
|
|
||||
|
#define IS_QSPI_DUAL_FLASH_MODE(MODE) (((MODE) == QSPI_DUALFLASH_ENABLE) || \ |
||||
|
((MODE) == QSPI_DUALFLASH_DISABLE)) |
||||
|
|
||||
|
#define IS_QSPI_INSTRUCTION(INSTRUCTION) ((INSTRUCTION) <= 0xFFU) |
||||
|
|
||||
|
#define IS_QSPI_ADDRESS_SIZE(ADDR_SIZE) (((ADDR_SIZE) == QSPI_ADDRESS_8_BITS) || \ |
||||
|
((ADDR_SIZE) == QSPI_ADDRESS_16_BITS) || \ |
||||
|
((ADDR_SIZE) == QSPI_ADDRESS_24_BITS) || \ |
||||
|
((ADDR_SIZE) == QSPI_ADDRESS_32_BITS)) |
||||
|
|
||||
|
#define IS_QSPI_ALTERNATE_BYTES_SIZE(SIZE) (((SIZE) == QSPI_ALTERNATE_BYTES_8_BITS) || \ |
||||
|
((SIZE) == QSPI_ALTERNATE_BYTES_16_BITS) || \ |
||||
|
((SIZE) == QSPI_ALTERNATE_BYTES_24_BITS) || \ |
||||
|
((SIZE) == QSPI_ALTERNATE_BYTES_32_BITS)) |
||||
|
|
||||
|
#define IS_QSPI_DUMMY_CYCLES(DCY) ((DCY) <= 31U) |
||||
|
|
||||
|
#define IS_QSPI_INSTRUCTION_MODE(MODE) (((MODE) == QSPI_INSTRUCTION_NONE) || \ |
||||
|
((MODE) == QSPI_INSTRUCTION_1_LINE) || \ |
||||
|
((MODE) == QSPI_INSTRUCTION_2_LINES) || \ |
||||
|
((MODE) == QSPI_INSTRUCTION_4_LINES)) |
||||
|
|
||||
|
#define IS_QSPI_ADDRESS_MODE(MODE) (((MODE) == QSPI_ADDRESS_NONE) || \ |
||||
|
((MODE) == QSPI_ADDRESS_1_LINE) || \ |
||||
|
((MODE) == QSPI_ADDRESS_2_LINES) || \ |
||||
|
((MODE) == QSPI_ADDRESS_4_LINES)) |
||||
|
|
||||
|
#define IS_QSPI_ALTERNATE_BYTES_MODE(MODE) (((MODE) == QSPI_ALTERNATE_BYTES_NONE) || \ |
||||
|
((MODE) == QSPI_ALTERNATE_BYTES_1_LINE) || \ |
||||
|
((MODE) == QSPI_ALTERNATE_BYTES_2_LINES) || \ |
||||
|
((MODE) == QSPI_ALTERNATE_BYTES_4_LINES)) |
||||
|
|
||||
|
#define IS_QSPI_DATA_MODE(MODE) (((MODE) == QSPI_DATA_NONE) || \ |
||||
|
((MODE) == QSPI_DATA_1_LINE) || \ |
||||
|
((MODE) == QSPI_DATA_2_LINES) || \ |
||||
|
((MODE) == QSPI_DATA_4_LINES)) |
||||
|
|
||||
|
#define IS_QSPI_DDR_MODE(DDR_MODE) (((DDR_MODE) == QSPI_DDR_MODE_DISABLE) || \ |
||||
|
((DDR_MODE) == QSPI_DDR_MODE_ENABLE)) |
||||
|
|
||||
|
#define IS_QSPI_DDR_HHC(DDR_HHC) (((DDR_HHC) == QSPI_DDR_HHC_ANALOG_DELAY) || \ |
||||
|
((DDR_HHC) == QSPI_DDR_HHC_HALF_CLK_DELAY)) |
||||
|
|
||||
|
#define IS_QSPI_SIOO_MODE(SIOO_MODE) (((SIOO_MODE) == QSPI_SIOO_INST_EVERY_CMD) || \ |
||||
|
((SIOO_MODE) == QSPI_SIOO_INST_ONLY_FIRST_CMD)) |
||||
|
|
||||
|
#define IS_QSPI_INTERVAL(INTERVAL) ((INTERVAL) <= QUADSPI_PIR_INTERVAL) |
||||
|
|
||||
|
#define IS_QSPI_STATUS_BYTES_SIZE(SIZE) (((SIZE) >= 1U) && ((SIZE) <= 4U)) |
||||
|
|
||||
|
#define IS_QSPI_MATCH_MODE(MODE) (((MODE) == QSPI_MATCH_MODE_AND) || \ |
||||
|
((MODE) == QSPI_MATCH_MODE_OR)) |
||||
|
|
||||
|
#define IS_QSPI_AUTOMATIC_STOP(APMS) (((APMS) == QSPI_AUTOMATIC_STOP_DISABLE) || \ |
||||
|
((APMS) == QSPI_AUTOMATIC_STOP_ENABLE)) |
||||
|
|
||||
|
#define IS_QSPI_TIMEOUT_ACTIVATION(TCEN) (((TCEN) == QSPI_TIMEOUT_COUNTER_DISABLE) || \ |
||||
|
((TCEN) == QSPI_TIMEOUT_COUNTER_ENABLE)) |
||||
|
|
||||
|
#define IS_QSPI_TIMEOUT_PERIOD(PERIOD) ((PERIOD) <= 0xFFFFU) |
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
/* End of private macros -----------------------------------------------------*/ |
||||
|
|
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
/**
|
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
#endif /* defined(QUADSPI) */ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif /* STM32H7xx_HAL_QSPI_H */ |
||||
File diff suppressed because it is too large
@ -0,0 +1,4 @@ |
|||||
|
# GitHub really wants to mark littlefs as a python project, telling it to |
||||
|
# reclassify our test .toml files as C code (which they are 95% of anyways) |
||||
|
# remedies this |
||||
|
*.toml linguist-language=c |
||||
@ -0,0 +1,34 @@ |
|||||
|
# Compilation output |
||||
|
*.o |
||||
|
*.d |
||||
|
*.a |
||||
|
*.ci |
||||
|
*.csv |
||||
|
*.t.* |
||||
|
*.b.* |
||||
|
*.gcno |
||||
|
*.gcda |
||||
|
*.perf |
||||
|
lfs |
||||
|
liblfs.a |
||||
|
|
||||
|
# Testing things |
||||
|
runners/test_runner |
||||
|
runners/bench_runner |
||||
|
lfs.code.csv |
||||
|
lfs.data.csv |
||||
|
lfs.stack.csv |
||||
|
lfs.structs.csv |
||||
|
lfs.cov.csv |
||||
|
lfs.perf.csv |
||||
|
lfs.perfbd.csv |
||||
|
lfs.test.csv |
||||
|
lfs.bench.csv |
||||
|
|
||||
|
# Misc |
||||
|
tags |
||||
|
.gdb_history |
||||
|
scripts/__pycache__ |
||||
|
|
||||
|
# Historical, probably should remove at some point |
||||
|
tests/*.toml.* |
||||
File diff suppressed because it is too large
@ -0,0 +1,25 @@ |
|||||
|
Copyright (c) 2022, The littlefs authors. |
||||
|
Copyright (c) 2017, Arm Limited. All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||
|
are permitted provided that the following conditions are met: |
||||
|
|
||||
|
- Redistributions of source code must retain the above copyright notice, this |
||||
|
list of conditions and the following disclaimer. |
||||
|
- Redistributions in binary form must reproduce the above copyright notice, this |
||||
|
list of conditions and the following disclaimer in the documentation and/or |
||||
|
other materials provided with the distribution. |
||||
|
- Neither the name of ARM nor the names of its contributors may be used to |
||||
|
endorse or promote products derived from this software without specific prior |
||||
|
written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
@ -0,0 +1,342 @@ |
|||||
|
## littlefs for RT-Thread |
||||
|
|
||||
|
A little fail-safe filesystem designed for microcontrollers. |
||||
|
|
||||
|
``` |
||||
|
| | | .---._____ |
||||
|
.-----. | | |
||||
|
--|o |---| littlefs | |
||||
|
--| |---| | |
||||
|
'-----' '----------' |
||||
|
| | | |
||||
|
``` |
||||
|
|
||||
|
**Power-loss resilience** - littlefs is designed to handle random power |
||||
|
failures. All file operations have strong copy-on-write guarantees and if |
||||
|
power is lost the filesystem will fall back to the last known good state. |
||||
|
|
||||
|
**Dynamic wear leveling** - littlefs is designed with flash in mind, and |
||||
|
provides wear leveling over dynamic blocks. Additionally, littlefs can |
||||
|
detect bad blocks and work around them. |
||||
|
|
||||
|
**Bounded RAM/ROM** - littlefs is designed to work with a small amount of |
||||
|
memory. RAM usage is strictly bounded, which means RAM consumption does not |
||||
|
change as the filesystem grows. The filesystem contains no unbounded |
||||
|
recursion and dynamic memory is limited to configurable buffers that can be |
||||
|
provided statically. |
||||
|
|
||||
|
## Example |
||||
|
|
||||
|
Here's a simple example that updates a file named `boot_count` every time |
||||
|
main runs. The program can be interrupted at any time without losing track |
||||
|
of how many times it has been booted and without corrupting the filesystem: |
||||
|
|
||||
|
``` c |
||||
|
#include "lfs.h" |
||||
|
|
||||
|
// variables used by the filesystem |
||||
|
lfs_t lfs; |
||||
|
lfs_file_t file; |
||||
|
|
||||
|
// configuration of the filesystem is provided by this struct |
||||
|
const struct lfs_config cfg = { |
||||
|
// block device operations |
||||
|
.read = user_provided_block_device_read, |
||||
|
.prog = user_provided_block_device_prog, |
||||
|
.erase = user_provided_block_device_erase, |
||||
|
.sync = user_provided_block_device_sync, |
||||
|
|
||||
|
// block device configuration |
||||
|
.read_size = 16, |
||||
|
.prog_size = 16, |
||||
|
.block_size = 4096, |
||||
|
.block_count = 128, |
||||
|
.cache_size = 16, |
||||
|
.lookahead_size = 16, |
||||
|
.block_cycles = 500, |
||||
|
}; |
||||
|
|
||||
|
// entry point |
||||
|
int main(void) { |
||||
|
// mount the filesystem |
||||
|
int err = lfs_mount(&lfs, &cfg); |
||||
|
|
||||
|
// reformat if we can't mount the filesystem |
||||
|
// this should only happen on the first boot |
||||
|
if (err) { |
||||
|
lfs_format(&lfs, &cfg); |
||||
|
lfs_mount(&lfs, &cfg); |
||||
|
} |
||||
|
|
||||
|
// read current count |
||||
|
uint32_t boot_count = 0; |
||||
|
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); |
||||
|
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); |
||||
|
|
||||
|
// update boot count |
||||
|
boot_count += 1; |
||||
|
lfs_file_rewind(&lfs, &file); |
||||
|
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); |
||||
|
|
||||
|
// remember the storage is not updated until the file is closed successfully |
||||
|
lfs_file_close(&lfs, &file); |
||||
|
|
||||
|
// release any resources we were using |
||||
|
lfs_unmount(&lfs); |
||||
|
|
||||
|
// print the boot count |
||||
|
printf("boot_count: %d\n", boot_count); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
Detailed documentation (or at least as much detail as is currently available) |
||||
|
can be found in the comments in [lfs.h](lfs.h). |
||||
|
|
||||
|
littlefs takes in a configuration structure that defines how the filesystem |
||||
|
operates. The configuration struct provides the filesystem with the block |
||||
|
device operations and dimensions, tweakable parameters that tradeoff memory |
||||
|
usage for performance, and optional static buffers if the user wants to avoid |
||||
|
dynamic memory. |
||||
|
|
||||
|
The state of the littlefs is stored in the `lfs_t` type which is left up |
||||
|
to the user to allocate, allowing multiple filesystems to be in use |
||||
|
simultaneously. With the `lfs_t` and configuration struct, a user can |
||||
|
format a block device or mount the filesystem. |
||||
|
|
||||
|
Once mounted, the littlefs provides a full set of POSIX-like file and |
||||
|
directory functions, with the deviation that the allocation of filesystem |
||||
|
structures must be provided by the user. |
||||
|
|
||||
|
All POSIX operations, such as remove and rename, are atomic, even in event |
||||
|
of power-loss. Additionally, file updates are not actually committed to |
||||
|
the filesystem until sync or close is called on the file. |
||||
|
|
||||
|
## Other notes |
||||
|
|
||||
|
Littlefs is written in C, and specifically should compile with any compiler |
||||
|
that conforms to the `C99` standard. |
||||
|
|
||||
|
All littlefs calls have the potential to return a negative error code. The |
||||
|
errors can be either one of those found in the `enum lfs_error` in |
||||
|
[lfs.h](lfs.h), or an error returned by the user's block device operations. |
||||
|
|
||||
|
In the configuration struct, the `prog` and `erase` function provided by the |
||||
|
user may return a `LFS_ERR_CORRUPT` error if the implementation already can |
||||
|
detect corrupt blocks. However, the wear leveling does not depend on the return |
||||
|
code of these functions, instead all data is read back and checked for |
||||
|
integrity. |
||||
|
|
||||
|
If your storage caches writes, make sure that the provided `sync` function |
||||
|
flushes all the data to memory and ensures that the next read fetches the data |
||||
|
from memory, otherwise data integrity can not be guaranteed. If the `write` |
||||
|
function does not perform caching, and therefore each `read` or `write` call |
||||
|
hits the memory, the `sync` function can simply return 0. |
||||
|
|
||||
|
## Design |
||||
|
|
||||
|
At a high level, littlefs is a block based filesystem that uses small logs to |
||||
|
store metadata and larger copy-on-write (COW) structures to store file data. |
||||
|
|
||||
|
In littlefs, these ingredients form a sort of two-layered cake, with the small |
||||
|
logs (called metadata pairs) providing fast updates to metadata anywhere on |
||||
|
storage, while the COW structures store file data compactly and without any |
||||
|
wear amplification cost. |
||||
|
|
||||
|
Both of these data structures are built out of blocks, which are fed by a |
||||
|
common block allocator. By limiting the number of erases allowed on a block |
||||
|
per allocation, the allocator provides dynamic wear leveling over the entire |
||||
|
filesystem. |
||||
|
|
||||
|
``` |
||||
|
root |
||||
|
.--------.--------. |
||||
|
| A'| B'| | |
||||
|
| | |-> | |
||||
|
| | | | |
||||
|
'--------'--------' |
||||
|
.----' '--------------. |
||||
|
A v B v |
||||
|
.--------.--------. .--------.--------. |
||||
|
| C'| D'| | | E'|new| | |
||||
|
| | |-> | | | E'|-> | |
||||
|
| | | | | | | | |
||||
|
'--------'--------' '--------'--------' |
||||
|
.-' '--. | '------------------. |
||||
|
v v .-' v |
||||
|
.--------. .--------. v .--------. |
||||
|
| C | | D | .--------. write | new E | |
||||
|
| | | | | E | ==> | | |
||||
|
| | | | | | | | |
||||
|
'--------' '--------' | | '--------' |
||||
|
'--------' .-' | |
||||
|
.-' '-. .-------------|------' |
||||
|
v v v v |
||||
|
.--------. .--------. .--------. |
||||
|
| F | | G | | new F | |
||||
|
| | | | | | |
||||
|
| | | | | | |
||||
|
'--------' '--------' '--------' |
||||
|
``` |
||||
|
|
||||
|
More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and |
||||
|
[SPEC.md](SPEC.md). |
||||
|
|
||||
|
- [DESIGN.md](DESIGN.md) - A fully detailed dive into how littlefs works. |
||||
|
I would suggest reading it as the tradeoffs at work are quite interesting. |
||||
|
|
||||
|
- [SPEC.md](SPEC.md) - The on-disk specification of littlefs with all the |
||||
|
nitty-gritty details. May be useful for tooling development. |
||||
|
|
||||
|
## Testing |
||||
|
|
||||
|
The littlefs comes with a test suite designed to run on a PC using the |
||||
|
[emulated block device](bd/lfs_testbd.h) found in the `bd` directory. |
||||
|
The tests assume a Linux environment and can be started with make: |
||||
|
|
||||
|
``` bash |
||||
|
make test |
||||
|
``` |
||||
|
|
||||
|
Tests are implemented in C in the .toml files found in the `tests` directory. |
||||
|
When developing a feature or fixing a bug, it is frequently useful to run a |
||||
|
single test case or suite of tests: |
||||
|
|
||||
|
``` bash |
||||
|
./scripts/test.py -l runners/test_runner # list available test suites |
||||
|
./scripts/test.py -L runners/test_runner test_dirs # list available test cases |
||||
|
./scripts/test.py runners/test_runner test_dirs # run a specific test suite |
||||
|
``` |
||||
|
|
||||
|
If an assert fails in a test, test.py will try to print information about the |
||||
|
failure: |
||||
|
|
||||
|
``` bash |
||||
|
tests/test_dirs.toml:1:failure: test_dirs_root:1g12gg2 (PROG_SIZE=16, ERASE_SIZE=512) failed |
||||
|
tests/test_dirs.toml:5:assert: assert failed with 0, expected eq 42 |
||||
|
lfs_mount(&lfs, cfg) => 42; |
||||
|
``` |
||||
|
|
||||
|
This includes the test id, which can be passed to test.py to run only that |
||||
|
specific test permutation: |
||||
|
|
||||
|
``` bash |
||||
|
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 # run a specific test permutation |
||||
|
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 --gdb # drop into gdb on failure |
||||
|
``` |
||||
|
|
||||
|
Some other flags that may be useful: |
||||
|
|
||||
|
```bash |
||||
|
./scripts/test.py runners/test_runner -b -j # run tests in parallel |
||||
|
./scripts/test.py runners/test_runner -v -O- # redirect stdout to stdout |
||||
|
./scripts/test.py runners/test_runner -ddisk # capture resulting disk image |
||||
|
``` |
||||
|
|
||||
|
See `-h/--help` for a full list of available flags: |
||||
|
|
||||
|
``` bash |
||||
|
./scripts/test.py --help |
||||
|
``` |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
The littlefs is provided under the [BSD-3-Clause] license. See |
||||
|
[LICENSE.md](LICENSE.md) for more information. Contributions to this project |
||||
|
are accepted under the same license. |
||||
|
|
||||
|
Individual files contain the following tag instead of the full license text. |
||||
|
|
||||
|
SPDX-License-Identifier: BSD-3-Clause |
||||
|
|
||||
|
This enables machine processing of license information based on the SPDX |
||||
|
License Identifiers that are here available: http://spdx.org/licenses/ |
||||
|
|
||||
|
## Related projects |
||||
|
|
||||
|
- [littlefs-fuse] - A [FUSE] wrapper for littlefs. The project allows you to |
||||
|
mount littlefs directly on a Linux machine. Can be useful for debugging |
||||
|
littlefs if you have an SD card handy. |
||||
|
|
||||
|
- [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would |
||||
|
want this, but it is handy for demos. You can see it in action |
||||
|
[here][littlefs-js-demo]. |
||||
|
|
||||
|
- [littlefs-python] - A Python wrapper for littlefs. The project allows you |
||||
|
to create images of the filesystem on your PC. Check if littlefs will fit |
||||
|
your needs, create images for a later download to the target memory or |
||||
|
inspect the content of a binary image of the target memory. |
||||
|
|
||||
|
- [littlefs-toy] - A command-line tool for creating and working with littlefs |
||||
|
images. Uses syntax similar to tar command for ease of use. Supports working |
||||
|
on littlefs images embedded inside another file (firmware image, etc). |
||||
|
|
||||
|
- [littlefs2-rust] - A Rust wrapper for littlefs. This project allows you |
||||
|
to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory |
||||
|
safety and other guarantees. |
||||
|
|
||||
|
- [nim-littlefs] - A Nim wrapper and API for littlefs. Includes a fuse |
||||
|
implementation based on [littlefs-fuse] |
||||
|
|
||||
|
- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for |
||||
|
use with the MirageOS library operating system project. It is interoperable |
||||
|
with the reference implementation, with some caveats. |
||||
|
|
||||
|
- [littlefs-disk-img-viewer] - A memory-efficient web application for viewing |
||||
|
littlefs disk images in your web browser. |
||||
|
|
||||
|
- [mklfs] - A command line tool for creating littlefs images. Used in the Lua |
||||
|
RTOS ecosystem. |
||||
|
|
||||
|
- [mklittlefs] - A command line tool for creating littlefs images. Used in the |
||||
|
ESP8266 and RP2040 ecosystem. |
||||
|
|
||||
|
- [pico-littlefs-usb] - An interface for littlefs that emulates a FAT12 |
||||
|
filesystem over USB. Allows mounting littlefs on a host PC without additional |
||||
|
drivers. |
||||
|
|
||||
|
- [ramcrc32bd] - An example block device using littlefs's 32-bit CRC for |
||||
|
error-correction. |
||||
|
|
||||
|
- [ramrsbd] - An example block device using Reed-Solomon codes for |
||||
|
error-correction. |
||||
|
|
||||
|
- [Mbed OS] - The easiest way to get started with littlefs is to jump into Mbed |
||||
|
which already has block device drivers for most forms of embedded storage. |
||||
|
littlefs is available in Mbed OS as the [LittleFileSystem] class. |
||||
|
|
||||
|
- [SPIFFS] - Another excellent embedded filesystem for NOR flash. As a more |
||||
|
traditional logging filesystem with full static wear-leveling, SPIFFS will |
||||
|
likely outperform littlefs on small memories such as the internal flash on |
||||
|
microcontrollers. |
||||
|
|
||||
|
- [Dhara] - An interesting NAND flash translation layer designed for small |
||||
|
MCUs. It offers static wear-leveling and power-resilience with only a fixed |
||||
|
_O(|address|)_ pointer structure stored on each block and in RAM. |
||||
|
|
||||
|
- [ChaN's FatFs] - A lightweight reimplementation of the infamous FAT filesystem |
||||
|
for microcontroller-scale devices. Due to limitations of FAT it can't provide |
||||
|
power-loss resilience, but it does allow easy interop with PCs. |
||||
|
|
||||
|
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html |
||||
|
[littlefs-fuse]: https://github.com/geky/littlefs-fuse |
||||
|
[FUSE]: https://github.com/libfuse/libfuse |
||||
|
[littlefs-js]: https://github.com/geky/littlefs-js |
||||
|
[littlefs-js-demo]:http://littlefs.geky.net/demo.html |
||||
|
[littlefs-python]: https://pypi.org/project/littlefs-python/ |
||||
|
[littlefs-toy]: https://github.com/tjko/littlefs-toy |
||||
|
[littlefs2-rust]: https://crates.io/crates/littlefs2 |
||||
|
[nim-littlefs]: https://github.com/Graveflo/nim-littlefs |
||||
|
[chamelon]: https://github.com/yomimono/chamelon |
||||
|
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer |
||||
|
[mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src |
||||
|
[mklittlefs]: https://github.com/earlephilhower/mklittlefs |
||||
|
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb |
||||
|
[ramcrc32bd]: https://github.com/geky/ramcrc32bd |
||||
|
[ramrsbd]: https://github.com/geky/ramrsbd |
||||
|
[Mbed OS]: https://github.com/armmbed/mbed-os |
||||
|
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html |
||||
|
[SPIFFS]: https://github.com/pellepl/spiffs |
||||
|
[Dhara]: https://github.com/dlbeer/dhara |
||||
|
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html |
||||
@ -0,0 +1,25 @@ |
|||||
|
# RT-Thread building script for component |
||||
|
|
||||
|
import os |
||||
|
import shutil |
||||
|
|
||||
|
from building import * |
||||
|
|
||||
|
cwd = GetCurrentDir() |
||||
|
src = Glob('*.c') + Glob('*.cpp') |
||||
|
CPPPATH = [cwd] |
||||
|
CPPDEFINES = ['LFS_CONFIG=lfs_config.h'] |
||||
|
|
||||
|
#delate non-used files |
||||
|
try: |
||||
|
shutil.rmtree(os.path.join(cwd,'.github')) |
||||
|
shutil.rmtree(os.path.join(cwd,'bd')) |
||||
|
shutil.rmtree(os.path.join(cwd,'scripts')) |
||||
|
shutil.rmtree(os.path.join(cwd,'tests')) |
||||
|
os.remove(os.path.join(cwd,'Makefile')) |
||||
|
except: |
||||
|
pass |
||||
|
|
||||
|
group = DefineGroup('littlefs', src, depend = ['PKG_USING_LITTLEFS', 'RT_USING_DFS'], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) |
||||
|
|
||||
|
Return('group') |
||||
@ -0,0 +1,867 @@ |
|||||
|
## littlefs technical specification |
||||
|
|
||||
|
This is the technical specification of the little filesystem with on-disk |
||||
|
version lfs2.1. This document covers the technical details of how the littlefs |
||||
|
is stored on disk for introspection and tooling. This document assumes you are |
||||
|
familiar with the design of the littlefs, for more info on how littlefs works |
||||
|
check out [DESIGN.md](DESIGN.md). |
||||
|
|
||||
|
``` |
||||
|
| | | .---._____ |
||||
|
.-----. | | |
||||
|
--|o |---| littlefs | |
||||
|
--| |---| | |
||||
|
'-----' '----------' |
||||
|
| | | |
||||
|
``` |
||||
|
|
||||
|
## Some quick notes |
||||
|
|
||||
|
- littlefs is a block-based filesystem. The disk is divided into an array of |
||||
|
evenly sized blocks that are used as the logical unit of storage. |
||||
|
|
||||
|
- Block pointers are stored in 32 bits, with the special value `0xffffffff` |
||||
|
representing a null block address. |
||||
|
|
||||
|
- In addition to the logical block size (which usually matches the erase |
||||
|
block size), littlefs also uses a program block size and read block size. |
||||
|
These determine the alignment of block device operations, but don't need |
||||
|
to be consistent for portability. |
||||
|
|
||||
|
- By default, all values in littlefs are stored in little-endian byte order. |
||||
|
|
||||
|
## Directories / Metadata pairs |
||||
|
|
||||
|
Metadata pairs form the backbone of littlefs and provide a system for |
||||
|
distributed atomic updates. Even the superblock is stored in a metadata pair. |
||||
|
|
||||
|
As their name suggests, a metadata pair is stored in two blocks, with one block |
||||
|
providing a backup during erase cycles in case power is lost. These two blocks |
||||
|
are not necessarily sequential and may be anywhere on disk, so a "pointer" to a |
||||
|
metadata pair is stored as two block pointers. |
||||
|
|
||||
|
On top of this, each metadata block behaves as an appendable log, containing a |
||||
|
variable number of commits. Commits can be appended to the metadata log in |
||||
|
order to update the metadata without requiring an erase cycles. Note that |
||||
|
successive commits may supersede the metadata in previous commits. Only the |
||||
|
most recent metadata should be considered valid. |
||||
|
|
||||
|
The high-level layout of a metadata block is fairly simple: |
||||
|
|
||||
|
``` |
||||
|
.---------------------------------------. |
||||
|
.-| revision count | entries | \ |
||||
|
| |-------------------+ | | |
||||
|
| | | | |
||||
|
| | | +-- 1st commit |
||||
|
| | | | |
||||
|
| | +-------------------| | |
||||
|
| | | CRC | / |
||||
|
| |-------------------+-------------------| |
||||
|
| | entries | \ |
||||
|
| | | | |
||||
|
| | | +-- 2nd commit |
||||
|
| | +-------------------+--------------| | |
||||
|
| | | CRC | padding | / |
||||
|
| |----+-------------------+--------------| |
||||
|
| | entries | \ |
||||
|
| | | | |
||||
|
| | | +-- 3rd commit |
||||
|
| | +-------------------+---------| | |
||||
|
| | | CRC | | / |
||||
|
| |---------+-------------------+ | |
||||
|
| | unwritten storage | more commits |
||||
|
| | | | |
||||
|
| | | v |
||||
|
| | | |
||||
|
| | | |
||||
|
| '---------------------------------------' |
||||
|
'---------------------------------------' |
||||
|
``` |
||||
|
|
||||
|
Each metadata block contains a 32-bit revision count followed by a number of |
||||
|
commits. Each commit contains a variable number of metadata entries followed |
||||
|
by a 32-bit CRC. |
||||
|
|
||||
|
Note also that entries aren't necessarily word-aligned. This allows us to |
||||
|
store metadata more compactly, however we can only write to addresses that are |
||||
|
aligned to our program block size. This means each commit may have padding for |
||||
|
alignment. |
||||
|
|
||||
|
Metadata block fields: |
||||
|
|
||||
|
1. **Revision count (32-bits)** - Incremented every erase cycle. If both blocks |
||||
|
contain valid commits, only the block with the most recent revision count |
||||
|
should be used. Sequence comparison must be used to avoid issues with |
||||
|
integer overflow. |
||||
|
|
||||
|
2. **CRC (32-bits)** - Detects corruption from power-loss or other write |
||||
|
issues. Uses a CRC-32 with a polynomial of `0x04c11db7` initialized |
||||
|
with `0xffffffff`. |
||||
|
|
||||
|
Entries themselves are stored as a 32-bit tag followed by a variable length |
||||
|
blob of data. But exactly how these tags are stored is a little bit tricky. |
||||
|
|
||||
|
Metadata blocks support both forward and backward iteration. In order to do |
||||
|
this without duplicating the space for each tag, neighboring entries have their |
||||
|
tags XORed together, starting with `0xffffffff`. |
||||
|
|
||||
|
``` |
||||
|
Forward iteration Backward iteration |
||||
|
|
||||
|
.-------------------. 0xffffffff .-------------------. |
||||
|
| revision count | | | revision count | |
||||
|
|-------------------| v |-------------------| |
||||
|
| tag ~A |---> xor -> tag A | tag ~A |---> xor -> 0xffffffff |
||||
|
|-------------------| | |-------------------| ^ |
||||
|
| data A | | | data A | | |
||||
|
| | | | | | |
||||
|
| | | | | | |
||||
|
|-------------------| v |-------------------| | |
||||
|
| tag AxB |---> xor -> tag B | tag AxB |---> xor -> tag A |
||||
|
|-------------------| | |-------------------| ^ |
||||
|
| data B | | | data B | | |
||||
|
| | | | | | |
||||
|
| | | | | | |
||||
|
|-------------------| v |-------------------| | |
||||
|
| tag BxC |---> xor -> tag C | tag BxC |---> xor -> tag B |
||||
|
|-------------------| |-------------------| ^ |
||||
|
| data C | | data C | | |
||||
|
| | | | tag C |
||||
|
| | | | |
||||
|
| | | | |
||||
|
'-------------------' '-------------------' |
||||
|
``` |
||||
|
|
||||
|
Here's a more complete example of metadata block containing 4 entries: |
||||
|
|
||||
|
``` |
||||
|
.---------------------------------------. |
||||
|
.-| revision count | tag ~A | \ |
||||
|
| |-------------------+-------------------| | |
||||
|
| | data A | | |
||||
|
| | | | |
||||
|
| |-------------------+-------------------| | |
||||
|
| | tag AxB | data B | <--. | |
||||
|
| |-------------------+ | | | |
||||
|
| | | | +-- 1st commit |
||||
|
| | +-------------------+---------| | | |
||||
|
| | | tag BxC | | <-.| | |
||||
|
| |---------+-------------------+ | || | |
||||
|
| | data C | || | |
||||
|
| | | || | |
||||
|
| |-------------------+-------------------| || | |
||||
|
| | tag CxCRC | CRC | || / |
||||
|
| |-------------------+-------------------| || |
||||
|
| | tag CRCxA' | data A' | || \ |
||||
|
| |-------------------+ | || | |
||||
|
| | | || | |
||||
|
| | +-------------------+----| || +-- 2nd commit |
||||
|
| | | tag CRCxA' | | || | |
||||
|
| |--------------+-------------------+----| || | |
||||
|
| | CRC | padding | || / |
||||
|
| |--------------+----+-------------------| || |
||||
|
| | tag CRCxA'' | data A'' | <---. \ |
||||
|
| |-------------------+ | ||| | |
||||
|
| | | ||| | |
||||
|
| | +-------------------+---------| ||| | |
||||
|
| | | tag A''xD | | < ||| | |
||||
|
| |---------+-------------------+ | |||| +-- 3rd commit |
||||
|
| | data D | |||| | |
||||
|
| | +---------| |||| | |
||||
|
| | | tag Dx| |||| | |
||||
|
| |---------+-------------------+---------| |||| | |
||||
|
| |CRC | CRC | | |||| / |
||||
|
| |---------+-------------------+ | |||| |
||||
|
| | unwritten storage | |||| more commits |
||||
|
| | | |||| | |
||||
|
| | | |||| v |
||||
|
| | | |||| |
||||
|
| | | |||| |
||||
|
| '---------------------------------------' |||| |
||||
|
'---------------------------------------' |||'- most recent A |
||||
|
||'-- most recent B |
||||
|
|'--- most recent C |
||||
|
'---- most recent D |
||||
|
``` |
||||
|
|
||||
|
Two things to note before we get into the details around tag encoding: |
||||
|
|
||||
|
1. Each tag contains a valid bit used to indicate if the tag and containing |
||||
|
commit is valid. After XORing, this bit should always be zero. |
||||
|
|
||||
|
At the end of each commit, the valid bit of the previous tag is XORed |
||||
|
with the lowest bit in the type field of the CRC tag. This allows |
||||
|
the CRC tag to force the next commit to fail the valid bit test if it |
||||
|
has not yet been written to. |
||||
|
|
||||
|
2. The valid bit alone is not enough info to know if the next commit has been |
||||
|
erased. We don't know the order bits will be programmed in a program block, |
||||
|
so it's possible that the next commit had an attempted program that left the |
||||
|
valid bit unchanged. |
||||
|
|
||||
|
To ensure we only ever program erased bytes, each commit can contain an |
||||
|
optional forward-CRC (FCRC). An FCRC contains a checksum of some amount of |
||||
|
bytes in the next commit at the time it was erased. |
||||
|
|
||||
|
``` |
||||
|
.-------------------. \ \ |
||||
|
| revision count | | | |
||||
|
|-------------------| | | |
||||
|
| metadata | | | |
||||
|
| | +---. +-- current commit |
||||
|
| | | | | |
||||
|
|-------------------| | | | |
||||
|
| FCRC ---|-. | | |
||||
|
|-------------------| / | | | |
||||
|
| CRC -----|-' / |
||||
|
|-------------------| | |
||||
|
| padding | | padding (does't need CRC) |
||||
|
| | | |
||||
|
|-------------------| \ | \ |
||||
|
| erased? | +-' | |
||||
|
| | | | +-- next commit |
||||
|
| v | / | |
||||
|
| | / |
||||
|
| | |
||||
|
'-------------------' |
||||
|
``` |
||||
|
|
||||
|
If the FCRC is missing or the checksum does not match, we must assume a |
||||
|
commit was attempted but failed due to power-loss. |
||||
|
|
||||
|
Note that end-of-block commits do not need an FCRC. |
||||
|
|
||||
|
## Metadata tags |
||||
|
|
||||
|
So in littlefs, 32-bit tags describe every type of metadata. And this means |
||||
|
_every_ type of metadata, including file entries, directory fields, and |
||||
|
global state. Even the CRCs used to mark the end of commits get their own tag. |
||||
|
|
||||
|
Because of this, the tag format contains some densely packed information. Note |
||||
|
that there are multiple levels of types which break down into more info: |
||||
|
|
||||
|
``` |
||||
|
[---- 32 ----] |
||||
|
[1|-- 11 --|-- 10 --|-- 10 --] |
||||
|
^. ^ . ^ ^- length |
||||
|
|. | . '------------ id |
||||
|
|. '-----.------------------ type (type3) |
||||
|
'.-----------.------------------ valid bit |
||||
|
[-3-|-- 8 --] |
||||
|
^ ^- chunk |
||||
|
'------- type (type1) |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
Before we go further, there's one important thing to note. These tags are |
||||
|
**not** stored in little-endian. Tags stored in commits are actually stored |
||||
|
in big-endian (and is the only thing in littlefs stored in big-endian). This |
||||
|
little bit of craziness comes from the fact that the valid bit must be the |
||||
|
first bit in a commit, and when converted to little-endian, the valid bit finds |
||||
|
itself in byte 4. We could restructure the tag to store the valid bit lower, |
||||
|
but, because none of the fields are byte-aligned, this would be more |
||||
|
complicated than just storing the tag in big-endian. |
||||
|
|
||||
|
Another thing to note is that both the tags `0x00000000` and `0xffffffff` are |
||||
|
invalid and can be used for null values. |
||||
|
|
||||
|
Metadata tag fields: |
||||
|
|
||||
|
1. **Valid bit (1-bit)** - Indicates if the tag is valid. |
||||
|
|
||||
|
2. **Type3 (11-bits)** - Type of the tag. This field is broken down further |
||||
|
into a 3-bit abstract type and an 8-bit chunk field. Note that the value |
||||
|
`0x000` is invalid and not assigned a type. |
||||
|
|
||||
|
1. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into |
||||
|
8 categories that facilitate bitmasked lookups. |
||||
|
|
||||
|
2. **Chunk (8-bits)** - Chunk field used for various purposes by the different |
||||
|
abstract types. type1+chunk+id form a unique identifier for each tag in the |
||||
|
metadata block. |
||||
|
|
||||
|
3. **Id (10-bits)** - File id associated with the tag. Each file in a metadata |
||||
|
block gets a unique id which is used to associate tags with that file. The |
||||
|
special value `0x3ff` is used for any tags that are not associated with a |
||||
|
file, such as directory and global metadata. |
||||
|
|
||||
|
4. **Length (10-bits)** - Length of the data in bytes. The special value |
||||
|
`0x3ff` indicates that this tag has been deleted. |
||||
|
|
||||
|
## Metadata types |
||||
|
|
||||
|
What follows is an exhaustive list of metadata in littlefs. |
||||
|
|
||||
|
--- |
||||
|
#### `0x401` LFS_TYPE_CREATE |
||||
|
|
||||
|
Creates a new file with this id. Note that files in a metadata block |
||||
|
don't necessarily need a create tag. All a create does is move over any |
||||
|
files using this id. In this sense a create is similar to insertion into |
||||
|
an imaginary array of files. |
||||
|
|
||||
|
The create and delete tags allow littlefs to keep files in a directory |
||||
|
ordered alphabetically by filename. |
||||
|
|
||||
|
--- |
||||
|
#### `0x4ff` LFS_TYPE_DELETE |
||||
|
|
||||
|
Deletes the file with this id. An inverse to create, this tag moves over |
||||
|
any files neighboring this id similar to a deletion from an imaginary |
||||
|
array of files. |
||||
|
|
||||
|
--- |
||||
|
#### `0x0xx` LFS_TYPE_NAME |
||||
|
|
||||
|
Associates the id with a file name and file type. |
||||
|
|
||||
|
The data contains the file name stored as an ASCII string (may be expanded to |
||||
|
UTF8 in the future). |
||||
|
|
||||
|
The chunk field in this tag indicates an 8-bit file type which can be one of |
||||
|
the following. |
||||
|
|
||||
|
Currently, the name tag must precede any other tags associated with the id and |
||||
|
can not be reassigned without deleting the file. |
||||
|
|
||||
|
Layout of the name tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][--- variable length ---] |
||||
|
[1| 3| 8 | 10 | 10 ][--- (size * 8) ---] |
||||
|
^ ^ ^ ^ ^- size ^- file name |
||||
|
| | | '------ id |
||||
|
| | '----------- file type |
||||
|
| '-------------- type1 (0x0) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Name fields: |
||||
|
|
||||
|
1. **file type (8-bits)** - Type of the file. |
||||
|
|
||||
|
2. **file name** - File name stored as an ASCII string. |
||||
|
|
||||
|
--- |
||||
|
#### `0x001` LFS_TYPE_REG |
||||
|
|
||||
|
Initializes the id + name as a regular file. |
||||
|
|
||||
|
How each file is stored depends on its struct tag, which is described below. |
||||
|
|
||||
|
--- |
||||
|
#### `0x002` LFS_TYPE_DIR |
||||
|
|
||||
|
Initializes the id + name as a directory. |
||||
|
|
||||
|
Directories in littlefs are stored on disk as a linked-list of metadata pairs, |
||||
|
each pair containing any number of files in alphabetical order. A pointer to |
||||
|
the directory is stored in the struct tag, which is described below. |
||||
|
|
||||
|
--- |
||||
|
#### `0x0ff` LFS_TYPE_SUPERBLOCK |
||||
|
|
||||
|
Initializes the id as a superblock entry. |
||||
|
|
||||
|
The superblock entry is a special entry used to store format-time configuration |
||||
|
and identify the filesystem. |
||||
|
|
||||
|
The name is a bit of a misnomer. While the superblock entry serves the same |
||||
|
purpose as a superblock found in other filesystems, in littlefs the superblock |
||||
|
does not get a dedicated block. Instead, the superblock entry is duplicated |
||||
|
across a linked-list of metadata pairs rooted on the blocks 0 and 1. The last |
||||
|
metadata pair doubles as the root directory of the filesystem. |
||||
|
|
||||
|
``` |
||||
|
.--------. .--------. .--------. .--------. .--------. |
||||
|
.| super |->| super |->| super |->| super |->| file B | |
||||
|
|| block | || block | || block | || block | || file C | |
||||
|
|| | || | || | || file A | || file D | |
||||
|
|'--------' |'--------' |'--------' |'--------' |'--------' |
||||
|
'--------' '--------' '--------' '--------' '--------' |
||||
|
|
||||
|
\----------------+----------------/ \----------+----------/ |
||||
|
superblock pairs root directory |
||||
|
``` |
||||
|
|
||||
|
The filesystem starts with only the root directory. The superblock metadata |
||||
|
pairs grow every time the root pair is compacted in order to prolong the |
||||
|
life of the device exponentially. |
||||
|
|
||||
|
The contents of the superblock entry are stored in a name tag with the |
||||
|
superblock type and an inline-struct tag. The name tag contains the magic |
||||
|
string "littlefs", while the inline-struct tag contains version and |
||||
|
configuration information. |
||||
|
|
||||
|
Layout of the superblock name tag and inline-struct tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][--- 64 ---] |
||||
|
^ ^ ^ ^- size (8) ^- magic string ("littlefs") |
||||
|
| | '------ id (0) |
||||
|
| '------------ type (0x0ff) |
||||
|
'----------------- valid bit |
||||
|
|
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][-- 32 --|-- 32 --|-- 32 --] |
||||
|
^ ^ ^ ^ ^- version ^- block size ^- block count |
||||
|
| | | | [-- 32 --|-- 32 --|-- 32 --] |
||||
|
| | | | [-- 32 --|-- 32 --|-- 32 --] |
||||
|
| | | | ^- name max ^- file max ^- attr max |
||||
|
| | | '- size (24) |
||||
|
| | '------ id (0) |
||||
|
| '------------ type (0x201) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Superblock fields: |
||||
|
|
||||
|
1. **Magic string (8-bytes)** - Magic string indicating the presence of |
||||
|
littlefs on the device. Must be the string "littlefs". |
||||
|
|
||||
|
2. **Version (32-bits)** - The version of littlefs at format time. The version |
||||
|
is encoded in a 32-bit value with the upper 16-bits containing the major |
||||
|
version, and the lower 16-bits containing the minor version. |
||||
|
|
||||
|
This specification describes version 2.0 (`0x00020000`). |
||||
|
|
||||
|
3. **Block size (32-bits)** - Size of the logical block size used by the |
||||
|
filesystem in bytes. |
||||
|
|
||||
|
4. **Block count (32-bits)** - Number of blocks in the filesystem. |
||||
|
|
||||
|
5. **Name max (32-bits)** - Maximum size of file names in bytes. |
||||
|
|
||||
|
6. **File max (32-bits)** - Maximum size of files in bytes. |
||||
|
|
||||
|
7. **Attr max (32-bits)** - Maximum size of file attributes in bytes. |
||||
|
|
||||
|
The superblock must always be the first entry (id 0) in the metadata pair, and |
||||
|
the name tag must always be the first tag in the metadata pair. This makes it |
||||
|
so that the magic string "littlefs" will always reside at offset=8 in a valid |
||||
|
littlefs superblock. |
||||
|
|
||||
|
--- |
||||
|
#### `0x2xx` LFS_TYPE_STRUCT |
||||
|
|
||||
|
Associates the id with an on-disk data structure. |
||||
|
|
||||
|
The exact layout of the data depends on the data structure type stored in the |
||||
|
chunk field and can be one of the following. |
||||
|
|
||||
|
Any type of struct supersedes all other structs associated with the id. For |
||||
|
example, appending a ctz-struct replaces an inline-struct on the same file. |
||||
|
|
||||
|
--- |
||||
|
#### `0x200` LFS_TYPE_DIRSTRUCT |
||||
|
|
||||
|
Gives the id a directory data structure. |
||||
|
|
||||
|
Directories in littlefs are stored on disk as a linked-list of metadata pairs, |
||||
|
each pair containing any number of files in alphabetical order. |
||||
|
|
||||
|
``` |
||||
|
| |
||||
|
v |
||||
|
.--------. .--------. .--------. .--------. .--------. .--------. |
||||
|
.| file A |->| file D |->| file G |->| file I |->| file J |->| file M | |
||||
|
|| file B | || file E | || file H | || | || file K | || file N | |
||||
|
|| file C | || file F | || | || | || file L | || | |
||||
|
|'--------' |'--------' |'--------' |'--------' |'--------' |'--------' |
||||
|
'--------' '--------' '--------' '--------' '--------' '--------' |
||||
|
``` |
||||
|
|
||||
|
The dir-struct tag contains only the pointer to the first metadata-pair in the |
||||
|
directory. The directory size is not known without traversing the directory. |
||||
|
|
||||
|
The pointer to the next metadata-pair in the directory is stored in a tail tag, |
||||
|
which is described below. |
||||
|
|
||||
|
Layout of the dir-struct tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][--- 64 ---] |
||||
|
^ ^ ^ ^- size (8) ^- metadata pair |
||||
|
| | '------ id |
||||
|
| '------------ type (0x200) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Dir-struct fields: |
||||
|
|
||||
|
1. **Metadata pair (8-bytes)** - Pointer to the first metadata-pair |
||||
|
in the directory. |
||||
|
|
||||
|
--- |
||||
|
#### `0x201` LFS_TYPE_INLINESTRUCT |
||||
|
|
||||
|
Gives the id an inline data structure. |
||||
|
|
||||
|
Inline structs store small files that can fit in the metadata pair. In this |
||||
|
case, the file data is stored directly in the tag's data area. |
||||
|
|
||||
|
Layout of the inline-struct tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][--- variable length ---] |
||||
|
[1|- 11 -| 10 | 10 ][--- (size * 8) ---] |
||||
|
^ ^ ^ ^- size ^- inline data |
||||
|
| | '------ id |
||||
|
| '------------ type (0x201) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Inline-struct fields: |
||||
|
|
||||
|
1. **Inline data** - File data stored directly in the metadata-pair. |
||||
|
|
||||
|
--- |
||||
|
#### `0x202` LFS_TYPE_CTZSTRUCT |
||||
|
|
||||
|
Gives the id a CTZ skip-list data structure. |
||||
|
|
||||
|
CTZ skip-lists store files that can not fit in the metadata pair. These files |
||||
|
are stored in a skip-list in reverse, with a pointer to the head of the |
||||
|
skip-list. Note that the head of the skip-list and the file size is enough |
||||
|
information to read the file. |
||||
|
|
||||
|
How exactly CTZ skip-lists work is a bit complicated. A full explanation can be |
||||
|
found in the [DESIGN.md](DESIGN.md#ctz-skip-lists). |
||||
|
|
||||
|
A quick summary: For every _n_‍th block where _n_ is divisible by |
||||
|
2‍_ˣ_, that block contains a pointer to block _n_-2‍_ˣ_. |
||||
|
These pointers are stored in increasing order of _x_ in each block of the file |
||||
|
before the actual data. |
||||
|
|
||||
|
``` |
||||
|
| |
||||
|
v |
||||
|
.--------. .--------. .--------. .--------. .--------. .--------. |
||||
|
| A |<-| D |<-| G |<-| J |<-| M |<-| P | |
||||
|
| B |<-| E |--| H |<-| K |--| N | | Q | |
||||
|
| C |<-| F |--| I |--| L |--| O | | | |
||||
|
'--------' '--------' '--------' '--------' '--------' '--------' |
||||
|
block 0 block 1 block 2 block 3 block 4 block 5 |
||||
|
1 skip 2 skips 1 skip 3 skips 1 skip |
||||
|
``` |
||||
|
|
||||
|
Note that the maximum number of pointers in a block is bounded by the maximum |
||||
|
file size divided by the block size. With 32 bits for file size, this results |
||||
|
in a minimum block size of 104 bytes. |
||||
|
|
||||
|
Layout of the CTZ-struct tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][-- 32 --|-- 32 --] |
||||
|
^ ^ ^ ^ ^ ^- file size |
||||
|
| | | | '-------------------- file head |
||||
|
| | | '- size (8) |
||||
|
| | '------ id |
||||
|
| '------------ type (0x202) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
CTZ-struct fields: |
||||
|
|
||||
|
1. **File head (32-bits)** - Pointer to the block that is the head of the |
||||
|
file's CTZ skip-list. |
||||
|
|
||||
|
2. **File size (32-bits)** - Size of the file in bytes. |
||||
|
|
||||
|
--- |
||||
|
#### `0x3xx` LFS_TYPE_USERATTR |
||||
|
|
||||
|
Attaches a user attribute to an id. |
||||
|
|
||||
|
littlefs has a concept of "user attributes". These are small user-provided |
||||
|
attributes that can be used to store things like timestamps, hashes, |
||||
|
permissions, etc. |
||||
|
|
||||
|
Each user attribute is uniquely identified by an 8-bit type which is stored in |
||||
|
the chunk field, and the user attribute itself can be found in the tag's data. |
||||
|
|
||||
|
There are currently no standard user attributes and a portable littlefs |
||||
|
implementation should work with any user attributes missing. |
||||
|
|
||||
|
Layout of the user-attr tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][--- variable length ---] |
||||
|
[1| 3| 8 | 10 | 10 ][--- (size * 8) ---] |
||||
|
^ ^ ^ ^ ^- size ^- attr data |
||||
|
| | | '------ id |
||||
|
| | '----------- attr type |
||||
|
| '-------------- type1 (0x3) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
User-attr fields: |
||||
|
|
||||
|
1. **Attr type (8-bits)** - Type of the user attributes. |
||||
|
|
||||
|
2. **Attr data** - The data associated with the user attribute. |
||||
|
|
||||
|
--- |
||||
|
#### `0x6xx` LFS_TYPE_TAIL |
||||
|
|
||||
|
Provides the tail pointer for the metadata pair itself. |
||||
|
|
||||
|
The metadata pair's tail pointer is used in littlefs for a linked-list |
||||
|
containing all metadata pairs. The chunk field contains the type of the tail, |
||||
|
which indicates if the following metadata pair is a part of the directory |
||||
|
(hard-tail) or only used to traverse the filesystem (soft-tail). |
||||
|
|
||||
|
``` |
||||
|
.--------. |
||||
|
.| dir A |-. |
||||
|
||softtail| | |
||||
|
.--------| |-' |
||||
|
| |'--------' |
||||
|
| '---|--|-' |
||||
|
| .-' '-------------. |
||||
|
| v v |
||||
|
| .--------. .--------. .--------. |
||||
|
'->| dir B |->| dir B |->| dir C | |
||||
|
||hardtail| ||softtail| || | |
||||
|
|| | || | || | |
||||
|
|'--------' |'--------' |'--------' |
||||
|
'--------' '--------' '--------' |
||||
|
``` |
||||
|
|
||||
|
Currently any type supersedes any other preceding tails in the metadata pair, |
||||
|
but this may change if additional metadata pair state is added. |
||||
|
|
||||
|
A note about the metadata pair linked-list: Normally, this linked-list contains |
||||
|
every metadata pair in the filesystem. However, there are some operations that |
||||
|
can cause this linked-list to become out of sync if a power-loss were to occur. |
||||
|
When this happens, littlefs sets the "sync" flag in the global state. How |
||||
|
exactly this flag is stored is described below. |
||||
|
|
||||
|
When the sync flag is set: |
||||
|
|
||||
|
1. The linked-list may contain an orphaned directory that has been removed in |
||||
|
the filesystem. |
||||
|
2. The linked-list may contain a metadata pair with a bad block that has been |
||||
|
replaced in the filesystem. |
||||
|
|
||||
|
If the sync flag is set, the threaded linked-list must be checked for these |
||||
|
errors before it can be used reliably. Note that the threaded linked-list can |
||||
|
be ignored if littlefs is mounted read-only. |
||||
|
|
||||
|
Layout of the tail tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --] |
||||
|
[1| 3| 8 | 10 | 10 ][--- 64 ---] |
||||
|
^ ^ ^ ^ ^- size (8) ^- metadata pair |
||||
|
| | | '------ id |
||||
|
| | '---------- tail type |
||||
|
| '------------- type1 (0x6) |
||||
|
'---------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Tail fields: |
||||
|
|
||||
|
1. **Tail type (8-bits)** - Type of the tail pointer. |
||||
|
|
||||
|
2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair. |
||||
|
|
||||
|
--- |
||||
|
#### `0x600` LFS_TYPE_SOFTTAIL |
||||
|
|
||||
|
Provides a tail pointer that points to the next metadata pair in the |
||||
|
filesystem. |
||||
|
|
||||
|
In this case, the next metadata pair is not a part of our current directory |
||||
|
and should only be followed when traversing the entire filesystem. |
||||
|
|
||||
|
--- |
||||
|
#### `0x601` LFS_TYPE_HARDTAIL |
||||
|
|
||||
|
Provides a tail pointer that points to the next metadata pair in the |
||||
|
directory. |
||||
|
|
||||
|
In this case, the next metadata pair belongs to the current directory. Note |
||||
|
that because directories in littlefs are sorted alphabetically, the next |
||||
|
metadata pair should only contain filenames greater than any filename in the |
||||
|
current pair. |
||||
|
|
||||
|
--- |
||||
|
#### `0x7xx` LFS_TYPE_GSTATE |
||||
|
|
||||
|
Provides delta bits for global state entries. |
||||
|
|
||||
|
littlefs has a concept of "global state". This is a small set of state that |
||||
|
can be updated by a commit to _any_ metadata pair in the filesystem. |
||||
|
|
||||
|
The way this works is that the global state is stored as a set of deltas |
||||
|
distributed across the filesystem such that the global state can be found by |
||||
|
the xor-sum of these deltas. |
||||
|
|
||||
|
``` |
||||
|
.--------. .--------. .--------. .--------. .--------. |
||||
|
.| |->| gdelta |->| |->| gdelta |->| gdelta | |
||||
|
|| | || 0x23 | || | || 0xff | || 0xce | |
||||
|
|| | || | || | || | || | |
||||
|
|'--------' |'--------' |'--------' |'--------' |'--------' |
||||
|
'--------' '----|---' '--------' '----|---' '----|---' |
||||
|
v v v |
||||
|
0x00 --> xor ------------------> xor ------> xor --> gstate = 0x12 |
||||
|
``` |
||||
|
|
||||
|
Note that storing globals this way is very expensive in terms of storage usage, |
||||
|
so any global state should be kept very small. |
||||
|
|
||||
|
The size and format of each piece of global state depends on the type, which |
||||
|
is stored in the chunk field. Currently, the only global state is move state, |
||||
|
which is outlined below. |
||||
|
|
||||
|
--- |
||||
|
#### `0x7ff` LFS_TYPE_MOVESTATE |
||||
|
|
||||
|
Provides delta bits for the global move state. |
||||
|
|
||||
|
The move state in littlefs is used to store info about operations that could |
||||
|
cause to filesystem to go out of sync if the power is lost. The operations |
||||
|
where this could occur is moves of files between metadata pairs and any |
||||
|
operation that changes metadata pairs on the threaded linked-list. |
||||
|
|
||||
|
In the case of moves, the move state contains a tag + metadata pair describing |
||||
|
the source of the ongoing move. If this tag is non-zero, that means that power |
||||
|
was lost during a move, and the file exists in two different locations. If this |
||||
|
happens, the source of the move should be considered deleted, and the move |
||||
|
should be completed (the source should be deleted) before any other write |
||||
|
operations to the filesystem. |
||||
|
|
||||
|
In the case of operations to the threaded linked-list, a single "sync" bit is |
||||
|
used to indicate that a modification is ongoing. If this sync flag is set, the |
||||
|
threaded linked-list will need to be checked for errors before it can be used |
||||
|
reliably. The exact cases to check for are described above in the tail tag. |
||||
|
|
||||
|
Layout of the move state: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][1|- 11 -| 10 | 10 |--- 64 ---] |
||||
|
^ ^ ^ ^ ^ ^ ^ ^- padding (0) ^- metadata pair |
||||
|
| | | | | | '------ move id |
||||
|
| | | | | '------------ move type |
||||
|
| | | | '----------------- sync bit |
||||
|
| | | | |
||||
|
| | | '- size (12) |
||||
|
| | '------ id (0x3ff) |
||||
|
| '------------ type (0x7ff) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
Move state fields: |
||||
|
|
||||
|
1. **Sync bit (1-bit)** - Indicates if the metadata pair threaded linked-list |
||||
|
is in-sync. If set, the threaded linked-list should be checked for errors. |
||||
|
|
||||
|
2. **Move type (11-bits)** - Type of move being performed. Must be either |
||||
|
`0x000`, indicating no move, or `0x4ff` indicating the source file should |
||||
|
be deleted. |
||||
|
|
||||
|
3. **Move id (10-bits)** - The file id being moved. |
||||
|
|
||||
|
4. **Metadata pair (8-bytes)** - Pointer to the metadata-pair containing |
||||
|
the move. |
||||
|
|
||||
|
--- |
||||
|
#### `0x5xx` LFS_TYPE_CRC |
||||
|
|
||||
|
Last but not least, the CRC tag marks the end of a commit and provides a |
||||
|
checksum for any commits to the metadata block. |
||||
|
|
||||
|
The first 32-bits of the data contain a CRC-32 with a polynomial of |
||||
|
`0x04c11db7` initialized with `0xffffffff`. This CRC provides a checksum for |
||||
|
all metadata since the previous CRC tag, including the CRC tag itself. For |
||||
|
the first commit, this includes the revision count for the metadata block. |
||||
|
|
||||
|
However, the size of the data is not limited to 32-bits. The data field may |
||||
|
larger to pad the commit to the next program-aligned boundary. |
||||
|
|
||||
|
In addition, the CRC tag's chunk field contains a set of flags which can |
||||
|
change the behaviour of commits. Currently the only flag in use is the lowest |
||||
|
bit, which determines the expected state of the valid bit for any following |
||||
|
tags. This is used to guarantee that unwritten storage in a metadata block |
||||
|
will be detected as invalid. |
||||
|
|
||||
|
Layout of the CRC tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|--- variable length ---] |
||||
|
[1| 3| 8 | 10 | 10 ][-- 32 --|--- (size * 8 - 32) ---] |
||||
|
^ ^ ^ ^ ^ ^- crc ^- padding |
||||
|
| | | | '- size |
||||
|
| | | '------ id (0x3ff) |
||||
|
| | '----------- valid state |
||||
|
| '-------------- type1 (0x5) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
CRC fields: |
||||
|
|
||||
|
1. **Valid state (1-bit)** - Indicates the expected value of the valid bit for |
||||
|
any tags in the next commit. |
||||
|
|
||||
|
2. **CRC (32-bits)** - CRC-32 with a polynomial of `0x04c11db7` initialized |
||||
|
with `0xffffffff`. |
||||
|
|
||||
|
3. **Padding** - Padding to the next program-aligned boundary. No guarantees |
||||
|
are made about the contents. |
||||
|
|
||||
|
--- |
||||
|
#### `0x5ff` LFS_TYPE_FCRC |
||||
|
|
||||
|
Added in lfs2.1, the optional FCRC tag contains a checksum of some amount of |
||||
|
bytes in the next commit at the time it was erased. This allows us to ensure |
||||
|
that we only ever program erased bytes, even if a previous commit failed due |
||||
|
to power-loss. |
||||
|
|
||||
|
When programming a commit, the FCRC size must be at least as large as the |
||||
|
program block size. However, the program block is not saved on disk, and can |
||||
|
change between mounts, so the FCRC size on disk may be different than the |
||||
|
current program block size. |
||||
|
|
||||
|
If the FCRC is missing or the checksum does not match, we must assume a |
||||
|
commit was attempted but failed due to power-loss. |
||||
|
|
||||
|
Layout of the FCRC tag: |
||||
|
|
||||
|
``` |
||||
|
tag data |
||||
|
[-- 32 --][-- 32 --|-- 32 --] |
||||
|
[1|- 11 -| 10 | 10 ][-- 32 --|-- 32 --] |
||||
|
^ ^ ^ ^ ^- fcrc size ^- fcrc |
||||
|
| | | '- size (8) |
||||
|
| | '------ id (0x3ff) |
||||
|
| '------------ type (0x5ff) |
||||
|
'----------------- valid bit |
||||
|
``` |
||||
|
|
||||
|
FCRC fields: |
||||
|
|
||||
|
1. **FCRC size (32-bits)** - Number of bytes after this commit's CRC tag's |
||||
|
padding to include in the FCRC. |
||||
|
|
||||
|
2. **FCRC (32-bits)** - CRC of the bytes after this commit's CRC tag's padding |
||||
|
when erased. Like the CRC tag, this uses a CRC-32 with a polynomial of |
||||
|
`0x04c11db7` initialized with `0xffffffff`. |
||||
|
|
||||
|
--- |
||||
@ -0,0 +1,270 @@ |
|||||
|
[cases.bench_dir_open] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.N = 1024 |
||||
|
defines.FILE_SIZE = 8 |
||||
|
defines.CHUNK_SIZE = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
// first create the files |
||||
|
char name[256]; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
sprintf(name, "file%08x", i); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
|
||||
|
uint32_t file_prng = i; |
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
buffer[k] = BENCH_PRNG(&file_prng); |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
|
||||
|
// then read the files |
||||
|
BENCH_START(); |
||||
|
uint32_t prng = 42; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (N-1-i) |
||||
|
: BENCH_PRNG(&prng) % N; |
||||
|
sprintf(name, "file%08x", i_); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; |
||||
|
|
||||
|
uint32_t file_prng = i_; |
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
lfs_file_read(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
assert(buffer[k] == BENCH_PRNG(&file_prng)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_dir_creat] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.N = 1024 |
||||
|
defines.FILE_SIZE = 8 |
||||
|
defines.CHUNK_SIZE = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
uint32_t prng = 42; |
||||
|
char name[256]; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (N-1-i) |
||||
|
: BENCH_PRNG(&prng) % N; |
||||
|
sprintf(name, "file%08x", i_); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |
||||
|
|
||||
|
uint32_t file_prng = i_; |
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
buffer[k] = BENCH_PRNG(&file_prng); |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_dir_remove] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.N = 1024 |
||||
|
defines.FILE_SIZE = 8 |
||||
|
defines.CHUNK_SIZE = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
// first create the files |
||||
|
char name[256]; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
sprintf(name, "file%08x", i); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
|
||||
|
uint32_t file_prng = i; |
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
buffer[k] = BENCH_PRNG(&file_prng); |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
|
||||
|
// then remove the files |
||||
|
BENCH_START(); |
||||
|
uint32_t prng = 42; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (N-1-i) |
||||
|
: BENCH_PRNG(&prng) % N; |
||||
|
sprintf(name, "file%08x", i_); |
||||
|
int err = lfs_remove(&lfs, name); |
||||
|
assert(!err || err == LFS_ERR_NOENT); |
||||
|
} |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_dir_read] |
||||
|
defines.N = 1024 |
||||
|
defines.FILE_SIZE = 8 |
||||
|
defines.CHUNK_SIZE = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
// first create the files |
||||
|
char name[256]; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
sprintf(name, "file%08x", i); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
|
||||
|
uint32_t file_prng = i; |
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
buffer[k] = BENCH_PRNG(&file_prng); |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
|
||||
|
// then read the directory |
||||
|
BENCH_START(); |
||||
|
lfs_dir_t dir; |
||||
|
lfs_dir_open(&lfs, &dir, "/") => 0; |
||||
|
struct lfs_info info; |
||||
|
lfs_dir_read(&lfs, &dir, &info) => 1; |
||||
|
assert(info.type == LFS_TYPE_DIR); |
||||
|
assert(strcmp(info.name, ".") == 0); |
||||
|
lfs_dir_read(&lfs, &dir, &info) => 1; |
||||
|
assert(info.type == LFS_TYPE_DIR); |
||||
|
assert(strcmp(info.name, "..") == 0); |
||||
|
for (int i = 0; i < N; i++) { |
||||
|
sprintf(name, "file%08x", i); |
||||
|
lfs_dir_read(&lfs, &dir, &info) => 1; |
||||
|
assert(info.type == LFS_TYPE_REG); |
||||
|
assert(strcmp(info.name, name) == 0); |
||||
|
} |
||||
|
lfs_dir_read(&lfs, &dir, &info) => 0; |
||||
|
lfs_dir_close(&lfs, &dir) => 0; |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_dir_mkdir] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.N = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
uint32_t prng = 42; |
||||
|
char name[256]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (N-1-i) |
||||
|
: BENCH_PRNG(&prng) % N; |
||||
|
printf("hm %d\n", i); |
||||
|
sprintf(name, "dir%08x", i_); |
||||
|
int err = lfs_mkdir(&lfs, name); |
||||
|
assert(!err || err == LFS_ERR_EXIST); |
||||
|
} |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_dir_rmdir] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.N = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
|
||||
|
// first create the dirs |
||||
|
char name[256]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
sprintf(name, "dir%08x", i); |
||||
|
lfs_mkdir(&lfs, name) => 0; |
||||
|
} |
||||
|
|
||||
|
// then remove the dirs |
||||
|
BENCH_START(); |
||||
|
uint32_t prng = 42; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (N-1-i) |
||||
|
: BENCH_PRNG(&prng) % N; |
||||
|
sprintf(name, "dir%08x", i_); |
||||
|
int err = lfs_remove(&lfs, name); |
||||
|
assert(!err || err == LFS_ERR_NOENT); |
||||
|
} |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
|
||||
@ -0,0 +1,95 @@ |
|||||
|
[cases.bench_file_read] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.SIZE = '128*1024' |
||||
|
defines.CHUNK_SIZE = 64 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
lfs_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE; |
||||
|
|
||||
|
// first write the file |
||||
|
lfs_file_t file; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
lfs_file_open(&lfs, &file, "file", |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
for (lfs_size_t i = 0; i < chunks; i++) { |
||||
|
uint32_t chunk_prng = i; |
||||
|
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) { |
||||
|
buffer[j] = BENCH_PRNG(&chunk_prng); |
||||
|
} |
||||
|
|
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
|
||||
|
// then read the file |
||||
|
BENCH_START(); |
||||
|
lfs_file_open(&lfs, &file, "file", LFS_O_RDONLY) => 0; |
||||
|
|
||||
|
uint32_t prng = 42; |
||||
|
for (lfs_size_t i = 0; i < chunks; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (chunks-1-i) |
||||
|
: BENCH_PRNG(&prng) % chunks; |
||||
|
lfs_file_seek(&lfs, &file, i_*CHUNK_SIZE, LFS_SEEK_SET) |
||||
|
=> i_*CHUNK_SIZE; |
||||
|
lfs_file_read(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
|
||||
|
uint32_t chunk_prng = i_; |
||||
|
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) { |
||||
|
assert(buffer[j] == BENCH_PRNG(&chunk_prng)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_file_write] |
||||
|
# 0 = in-order |
||||
|
# 1 = reversed-order |
||||
|
# 2 = random-order |
||||
|
defines.ORDER = [0, 1, 2] |
||||
|
defines.SIZE = '128*1024' |
||||
|
defines.CHUNK_SIZE = 64 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
lfs_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, "file", |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
|
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
uint32_t prng = 42; |
||||
|
for (lfs_size_t i = 0; i < chunks; i++) { |
||||
|
lfs_off_t i_ |
||||
|
= (ORDER == 0) ? i |
||||
|
: (ORDER == 1) ? (chunks-1-i) |
||||
|
: BENCH_PRNG(&prng) % chunks; |
||||
|
uint32_t chunk_prng = i_; |
||||
|
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) { |
||||
|
buffer[j] = BENCH_PRNG(&chunk_prng); |
||||
|
} |
||||
|
|
||||
|
lfs_file_seek(&lfs, &file, i_*CHUNK_SIZE, LFS_SEEK_SET) |
||||
|
=> i_*CHUNK_SIZE; |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
@ -0,0 +1,56 @@ |
|||||
|
[cases.bench_superblocks_found] |
||||
|
# support benchmarking with files |
||||
|
defines.N = [0, 1024] |
||||
|
defines.FILE_SIZE = 8 |
||||
|
defines.CHUNK_SIZE = 8 |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
|
||||
|
// create files? |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
char name[256]; |
||||
|
uint8_t buffer[CHUNK_SIZE]; |
||||
|
for (lfs_size_t i = 0; i < N; i++) { |
||||
|
sprintf(name, "file%08x", i); |
||||
|
lfs_file_t file; |
||||
|
lfs_file_open(&lfs, &file, name, |
||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
||||
|
|
||||
|
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) { |
||||
|
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) { |
||||
|
buffer[k] = i+j+k; |
||||
|
} |
||||
|
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_file_close(&lfs, &file) => 0; |
||||
|
} |
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
lfs_mount(&lfs, cfg) => 0; |
||||
|
BENCH_STOP(); |
||||
|
|
||||
|
lfs_unmount(&lfs) => 0; |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_superblocks_missing] |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
int err = lfs_mount(&lfs, cfg); |
||||
|
assert(err != 0); |
||||
|
BENCH_STOP(); |
||||
|
''' |
||||
|
|
||||
|
[cases.bench_superblocks_format] |
||||
|
code = ''' |
||||
|
lfs_t lfs; |
||||
|
|
||||
|
BENCH_START(); |
||||
|
lfs_format(&lfs, cfg) => 0; |
||||
|
BENCH_STOP(); |
||||
|
''' |
||||
|
|
||||
@ -0,0 +1,977 @@ |
|||||
|
#include <rtdevice.h> |
||||
|
#include <rtthread.h> |
||||
|
|
||||
|
#include <dfs_file.h> |
||||
|
#include <dfs_fs.h> |
||||
|
|
||||
|
#include "lfs.h" |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#if defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 2)) |
||||
|
#define DFS_LFS_RW_RETURN_TYPE ssize_t |
||||
|
#define DFS_LFS_LSK_RETURN_TYPE off_t |
||||
|
#define DFS_LFS_MKFS(dev_id, fs_name) _dfs_lfs_mkfs(dev_id, fs_name) |
||||
|
#else |
||||
|
#define DFS_LFS_RW_RETURN_TYPE int |
||||
|
#define DFS_LFS_LSK_RETURN_TYPE int |
||||
|
#define DFS_LFS_MKFS(dev_id, fs_name) _dfs_lfs_mkfs(dev_id) |
||||
|
#endif |
||||
|
|
||||
|
#ifndef RT_DEF_LFS_DRIVERS |
||||
|
#define RT_DEF_LFS_DRIVERS 1 |
||||
|
#endif |
||||
|
|
||||
|
#if (RT_DEF_LFS_DRIVERS < 1) |
||||
|
#error "#define RT_DEF_LFS_DRIVERS must > 0" |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READ_SIZE |
||||
|
#define LFS_READ_SIZE 256 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_PROG_SIZE |
||||
|
#define LFS_PROG_SIZE 256 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_BLOCK_SIZE |
||||
|
#define LFS_BLOCK_SIZE 4096 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_CACHE_SIZE |
||||
|
#define LFS_CACHE_SIZE LFS_PROG_SIZE |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_BLOCK_CYCLES |
||||
|
#define LFS_BLOCK_CYCLES (-1) |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_LOOKAHEAD_MAX |
||||
|
#define LFS_LOOKAHEAD_MAX 128 |
||||
|
#endif |
||||
|
|
||||
|
#define ATTR_TIMESTAMP 0x74 |
||||
|
|
||||
|
typedef struct _dfs_lfs_s |
||||
|
{ |
||||
|
struct lfs lfs; |
||||
|
struct lfs_config cfg; |
||||
|
struct rt_mutex lock; |
||||
|
} dfs_lfs_t; |
||||
|
|
||||
|
typedef struct _dfs_lfs_fd_s |
||||
|
{ |
||||
|
struct lfs* lfs; |
||||
|
union |
||||
|
{ |
||||
|
struct lfs_file file; |
||||
|
struct lfs_dir dir; |
||||
|
} u; |
||||
|
} dfs_lfs_fd_t; |
||||
|
|
||||
|
static struct _dfs_lfs_s* _lfs_mount_tbl[RT_DEF_LFS_DRIVERS] = {0}; |
||||
|
|
||||
|
#ifdef LFS_THREADSAFE |
||||
|
// Lock the underlying block device. Negative error codes
|
||||
|
// are propogated to the user.
|
||||
|
int _lfs_lock(const struct lfs_config *c) |
||||
|
{ |
||||
|
dfs_lfs_t *dfs_lfs = rt_container_of(c, dfs_lfs_t, cfg); |
||||
|
|
||||
|
if (rt_mutex_take(&dfs_lfs->lock, RT_WAITING_FOREVER) != RT_EOK) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// Unlock the underlying block device. Negative error codes
|
||||
|
// are propogated to the user.
|
||||
|
int _lfs_unlock(const struct lfs_config *c) |
||||
|
{ |
||||
|
dfs_lfs_t *dfs_lfs = rt_container_of(c, dfs_lfs_t, cfg); |
||||
|
|
||||
|
if (rt_mutex_release(&dfs_lfs->lock) != RT_EOK) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
// Read a region in a block. Negative error codes are propogated
|
||||
|
// to the user.
|
||||
|
static int _lfs_flash_read(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) |
||||
|
{ |
||||
|
struct rt_mtd_nor_device* mtd_nor; |
||||
|
|
||||
|
RT_ASSERT(c != RT_NULL); |
||||
|
RT_ASSERT(c->context != RT_NULL); |
||||
|
|
||||
|
mtd_nor = (struct rt_mtd_nor_device*)c->context; |
||||
|
if (rt_mtd_nor_read(mtd_nor, block * c->block_size + off, buffer, size) != size) |
||||
|
{ |
||||
|
return LFS_ERR_IO; |
||||
|
} |
||||
|
|
||||
|
return LFS_ERR_OK; |
||||
|
} |
||||
|
|
||||
|
// Program a region in a block. The block must have previously
|
||||
|
// been erased. Negative error codes are propogated to the user.
|
||||
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
|
static int _lfs_flash_prog(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) |
||||
|
{ |
||||
|
struct rt_mtd_nor_device* mtd_nor; |
||||
|
|
||||
|
RT_ASSERT(c != RT_NULL); |
||||
|
RT_ASSERT(c->context != RT_NULL); |
||||
|
|
||||
|
mtd_nor = (struct rt_mtd_nor_device*)c->context; |
||||
|
if (rt_mtd_nor_write(mtd_nor, block * c->block_size + off, buffer, size) != size) |
||||
|
{ |
||||
|
return LFS_ERR_IO; |
||||
|
} |
||||
|
|
||||
|
return LFS_ERR_OK; |
||||
|
} |
||||
|
|
||||
|
// Erase a block. A block must be erased before being programmed.
|
||||
|
// The state of an erased block is undefined. Negative error codes
|
||||
|
// are propogated to the user.
|
||||
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
|
static int _lfs_flash_erase(const struct lfs_config* c, lfs_block_t block) |
||||
|
{ |
||||
|
struct rt_mtd_nor_device* mtd_nor; |
||||
|
|
||||
|
RT_ASSERT(c != RT_NULL); |
||||
|
RT_ASSERT(c->context != RT_NULL); |
||||
|
|
||||
|
mtd_nor = (struct rt_mtd_nor_device*)c->context; |
||||
|
if (rt_mtd_nor_erase_block(mtd_nor, block * c->block_size, c->block_size) != RT_EOK) |
||||
|
{ |
||||
|
return LFS_ERR_IO; |
||||
|
} |
||||
|
|
||||
|
return LFS_ERR_OK; |
||||
|
} |
||||
|
|
||||
|
// Sync the state of the underlying block device. Negative error codes
|
||||
|
// are propogated to the user.
|
||||
|
static int _lfs_flash_sync(const struct lfs_config* c) |
||||
|
{ |
||||
|
return LFS_ERR_OK; |
||||
|
} |
||||
|
|
||||
|
/* results:
|
||||
|
* -1, no space to install fatfs driver |
||||
|
* >= 0, there is an space to install littlefs driver |
||||
|
*/ |
||||
|
static int _get_disk(rt_device_t dev_id) |
||||
|
{ |
||||
|
int index; |
||||
|
|
||||
|
if (dev_id == RT_NULL) |
||||
|
{ |
||||
|
for (index = 0; index < RT_DEF_LFS_DRIVERS; index ++) |
||||
|
{ |
||||
|
if(_lfs_mount_tbl[index] == RT_NULL) |
||||
|
{ |
||||
|
return index; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
for (index = 0; index < RT_DEF_LFS_DRIVERS; index ++) |
||||
|
{ |
||||
|
if ((_lfs_mount_tbl[index] != RT_NULL) && (_lfs_mount_tbl[index]->cfg.context == (void *)dev_id)) |
||||
|
{ |
||||
|
return index; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
static int _lfs_result_to_dfs(int result) |
||||
|
{ |
||||
|
int status = 0; |
||||
|
|
||||
|
switch (result) |
||||
|
{ |
||||
|
case LFS_ERR_OK: |
||||
|
break; |
||||
|
|
||||
|
case LFS_ERR_IO: |
||||
|
status = -EIO; |
||||
|
break; // Error during device operation
|
||||
|
|
||||
|
case LFS_ERR_NOENT: |
||||
|
status = -ENOENT; |
||||
|
break; // No directory entry
|
||||
|
|
||||
|
case LFS_ERR_EXIST: |
||||
|
status = -EEXIST; |
||||
|
break; // Entry already exists
|
||||
|
|
||||
|
case LFS_ERR_NOTDIR: |
||||
|
status = -ENOTDIR; |
||||
|
break; // Entry is not a dir
|
||||
|
|
||||
|
case LFS_ERR_ISDIR: |
||||
|
status = -EISDIR; |
||||
|
break; // Entry is a dir
|
||||
|
|
||||
|
case LFS_ERR_NOTEMPTY: |
||||
|
status = -ENOTEMPTY; |
||||
|
break; // Dir is not empty
|
||||
|
|
||||
|
case LFS_ERR_BADF: |
||||
|
status = -EBADF; |
||||
|
break; // Bad file number
|
||||
|
|
||||
|
case LFS_ERR_INVAL: |
||||
|
status = -EINVAL; |
||||
|
break; // Invalid parameter
|
||||
|
|
||||
|
case LFS_ERR_NOSPC: |
||||
|
status = -ENOSPC; |
||||
|
break; // No space left on device
|
||||
|
|
||||
|
case LFS_ERR_NOMEM: |
||||
|
status = -ENOMEM; |
||||
|
break; // No more memory available
|
||||
|
|
||||
|
case LFS_ERR_CORRUPT: |
||||
|
status = -52; |
||||
|
break; // Corrupted
|
||||
|
|
||||
|
default: |
||||
|
status = -EIO; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
static void _lfs_load_config(struct lfs_config* lfs_cfg, struct rt_mtd_nor_device* mtd_nor) |
||||
|
{ |
||||
|
uint64_t mtd_size; |
||||
|
|
||||
|
lfs_cfg->context = (void*)mtd_nor; |
||||
|
|
||||
|
lfs_cfg->read_size = LFS_READ_SIZE; |
||||
|
lfs_cfg->prog_size = LFS_PROG_SIZE; |
||||
|
|
||||
|
lfs_cfg->block_size = mtd_nor->block_size; |
||||
|
if (lfs_cfg->block_size < LFS_BLOCK_SIZE) |
||||
|
{ |
||||
|
lfs_cfg->block_size = LFS_BLOCK_SIZE; |
||||
|
} |
||||
|
|
||||
|
lfs_cfg->cache_size = LFS_CACHE_SIZE; |
||||
|
lfs_cfg->block_cycles = LFS_BLOCK_CYCLES; |
||||
|
|
||||
|
mtd_size = mtd_nor->block_end - mtd_nor->block_start; |
||||
|
mtd_size *= mtd_nor->block_size; |
||||
|
lfs_cfg->block_count = mtd_size / lfs_cfg->block_size; |
||||
|
|
||||
|
lfs_cfg->lookahead_size = 32 * ((lfs_cfg->block_count + 31) / 32); |
||||
|
if (lfs_cfg->lookahead_size > LFS_LOOKAHEAD_MAX) |
||||
|
{ |
||||
|
lfs_cfg->lookahead_size = LFS_LOOKAHEAD_MAX; |
||||
|
} |
||||
|
#ifdef LFS_THREADSAFE |
||||
|
lfs_cfg->lock = _lfs_lock; |
||||
|
lfs_cfg->unlock = _lfs_unlock; |
||||
|
#endif |
||||
|
lfs_cfg->read = _lfs_flash_read; |
||||
|
lfs_cfg->prog = _lfs_flash_prog; |
||||
|
lfs_cfg->erase = _lfs_flash_erase; |
||||
|
lfs_cfg->sync = _lfs_flash_sync; |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_mount(struct dfs_filesystem* dfs, unsigned long rwflag, const void* data) |
||||
|
{ |
||||
|
int result; |
||||
|
int index; |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
|
||||
|
/* Check Device Type */ |
||||
|
if (dfs->dev_id->type != RT_Device_Class_MTD) |
||||
|
{ |
||||
|
rt_kprintf("The flash device type must be MTD!\n"); |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
/* get an empty position */ |
||||
|
index = _get_disk(RT_NULL); |
||||
|
if (index == -1) |
||||
|
{ |
||||
|
return -EIO; |
||||
|
} |
||||
|
|
||||
|
/*create lfs handle */ |
||||
|
dfs_lfs = (dfs_lfs_t*)rt_malloc(sizeof(dfs_lfs_t)); |
||||
|
if (dfs_lfs == RT_NULL) |
||||
|
{ |
||||
|
rt_kprintf("ERROR:no memory!\n"); |
||||
|
return -ENOMEM; |
||||
|
} |
||||
|
rt_memset(dfs_lfs, 0, sizeof(dfs_lfs_t)); |
||||
|
rt_mutex_init(&dfs_lfs->lock, "lfslock", RT_IPC_FLAG_PRIO); |
||||
|
_lfs_load_config(&dfs_lfs->cfg, (struct rt_mtd_nor_device*)dfs->dev_id); |
||||
|
|
||||
|
/* mount lfs*/ |
||||
|
result = lfs_mount(&dfs_lfs->lfs, &dfs_lfs->cfg); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
rt_mutex_detach(&dfs_lfs->lock); |
||||
|
/* release memory */ |
||||
|
rt_free(dfs_lfs); |
||||
|
|
||||
|
return -EIO; |
||||
|
} |
||||
|
|
||||
|
/* mount succeed! */ |
||||
|
dfs->data = (void*)dfs_lfs; |
||||
|
_lfs_mount_tbl[index] = dfs_lfs; |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_unmount(struct dfs_filesystem* dfs) |
||||
|
{ |
||||
|
int result; |
||||
|
int index; |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
|
||||
|
RT_ASSERT(dfs != RT_NULL); |
||||
|
RT_ASSERT(dfs->data != RT_NULL); |
||||
|
|
||||
|
/* find the device index and then umount it */ |
||||
|
index = _get_disk(dfs->dev_id); |
||||
|
if (index == -1) |
||||
|
{ |
||||
|
return -ENOENT; |
||||
|
} |
||||
|
_lfs_mount_tbl[index] = RT_NULL; |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
dfs->data = RT_NULL; |
||||
|
|
||||
|
result = lfs_unmount(&dfs_lfs->lfs); |
||||
|
rt_mutex_detach(&dfs_lfs->lock); |
||||
|
rt_free(dfs_lfs); |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
static int DFS_LFS_MKFS(rt_device_t dev_id, const char *fs_name) |
||||
|
{ |
||||
|
int result; |
||||
|
int index; |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
|
||||
|
if (dev_id == RT_NULL) |
||||
|
{ |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
/* Check Device Type */ |
||||
|
if (dev_id->type != RT_Device_Class_MTD) |
||||
|
{ |
||||
|
rt_kprintf("The flash device type must be MTD!\n"); |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
index = _get_disk(dev_id); |
||||
|
if (index == -1) |
||||
|
{ |
||||
|
/* create lfs handle */ |
||||
|
dfs_lfs = rt_malloc(sizeof(dfs_lfs_t)); |
||||
|
if (dfs_lfs == RT_NULL) |
||||
|
{ |
||||
|
rt_kprintf("ERROR:no memory!\n"); |
||||
|
return -ENOMEM; |
||||
|
} |
||||
|
rt_memset(dfs_lfs, 0, sizeof(dfs_lfs_t)); |
||||
|
rt_mutex_init(&dfs_lfs->lock, "lfslock", RT_IPC_FLAG_PRIO); |
||||
|
_lfs_load_config(&dfs_lfs->cfg, (struct rt_mtd_nor_device*)dev_id); |
||||
|
|
||||
|
/* format flash device */ |
||||
|
result = lfs_format(&dfs_lfs->lfs, &dfs_lfs->cfg); |
||||
|
rt_mutex_detach(&dfs_lfs->lock); |
||||
|
rt_free(dfs_lfs); |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
dfs_lfs = _lfs_mount_tbl[index]; |
||||
|
|
||||
|
/* unmount it */ |
||||
|
result = lfs_unmount(&dfs_lfs->lfs); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
_lfs_mount_tbl[index] = RT_NULL; |
||||
|
|
||||
|
/* format flash device */ |
||||
|
result = lfs_format(&dfs_lfs->lfs, &dfs_lfs->cfg); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
_lfs_load_config(&dfs_lfs->cfg, (struct rt_mtd_nor_device*)dev_id); |
||||
|
|
||||
|
/* mount lfs*/ |
||||
|
result = lfs_mount(&dfs_lfs->lfs, &dfs_lfs->cfg); |
||||
|
if (result == LFS_ERR_OK) |
||||
|
{ |
||||
|
_lfs_mount_tbl[index] = dfs_lfs; |
||||
|
} |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
static int _dfs_lfs_statfs_count(void* p, lfs_block_t b) |
||||
|
{ |
||||
|
*(lfs_size_t*)p += 1; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_statfs(struct dfs_filesystem* dfs, struct statfs* buf) |
||||
|
{ |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
int result; |
||||
|
lfs_size_t in_use = 0; |
||||
|
|
||||
|
RT_ASSERT(buf != RT_NULL); |
||||
|
RT_ASSERT(dfs != RT_NULL); |
||||
|
RT_ASSERT(dfs->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
|
||||
|
/* Get total sectors and free sectors */ |
||||
|
result = lfs_fs_traverse(&dfs_lfs->lfs, _dfs_lfs_statfs_count, &in_use); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
buf->f_bsize = dfs_lfs->cfg.block_size; |
||||
|
buf->f_blocks = dfs_lfs->cfg.block_count; |
||||
|
buf->f_bfree = dfs_lfs->cfg.block_count - in_use; |
||||
|
|
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
static int _dfs_lfs_unlink(struct dfs_filesystem* dfs, const char* path) |
||||
|
{ |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
int result; |
||||
|
|
||||
|
RT_ASSERT(dfs != RT_NULL); |
||||
|
RT_ASSERT(dfs->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
result = lfs_remove(&dfs_lfs->lfs, path); |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
static void _dfs_lfs_tostat(struct stat* st, struct lfs_info* info, time_t mtime) |
||||
|
{ |
||||
|
memset(st, 0, sizeof(struct stat)); |
||||
|
|
||||
|
/* convert to dfs stat structure */ |
||||
|
st->st_dev = 0; |
||||
|
st->st_size = info->size; |
||||
|
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO; |
||||
|
|
||||
|
switch (info->type) |
||||
|
{ |
||||
|
case LFS_TYPE_DIR: |
||||
|
st->st_mode |= S_IFDIR; |
||||
|
break; |
||||
|
|
||||
|
case LFS_TYPE_REG: |
||||
|
st->st_mode |= S_IFREG; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
st->st_mtime = mtime; |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_stat(struct dfs_filesystem* dfs, const char* path, struct stat* st) |
||||
|
{ |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
int result; |
||||
|
struct lfs_info info; |
||||
|
|
||||
|
RT_ASSERT(dfs != RT_NULL); |
||||
|
RT_ASSERT(dfs->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
result = lfs_stat(&dfs_lfs->lfs, path, &info); |
||||
|
|
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
time_t mtime = 0; |
||||
|
lfs_getattr(&dfs_lfs->lfs, path, ATTR_TIMESTAMP, &mtime, sizeof(time_t)); |
||||
|
|
||||
|
_dfs_lfs_tostat(st, &info, mtime); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
static int _dfs_lfs_rename(struct dfs_filesystem* dfs, const char* from, const char* to) |
||||
|
{ |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
int result; |
||||
|
|
||||
|
RT_ASSERT(dfs != RT_NULL); |
||||
|
RT_ASSERT(dfs->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
result = lfs_rename(&dfs_lfs->lfs, from, to); |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
/******************************************************************************
|
||||
|
* file operations |
||||
|
******************************************************************************/ |
||||
|
static int _dfs_lfs_open(struct dfs_file* file) |
||||
|
{ |
||||
|
struct dfs_filesystem* dfs; |
||||
|
dfs_lfs_t* dfs_lfs; |
||||
|
int result; |
||||
|
int flags = 0; |
||||
|
|
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
|
||||
|
dfs = (struct dfs_filesystem*)file->vnode->fs; |
||||
|
|
||||
|
RT_ASSERT(file->vnode->ref_count > 0); |
||||
|
if (file->vnode->ref_count > 1) |
||||
|
{ |
||||
|
if (file->vnode->type == FT_DIRECTORY |
||||
|
&& !(file->flags & O_DIRECTORY)) |
||||
|
{ |
||||
|
return -ENOENT; |
||||
|
} |
||||
|
file->pos = 0; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
dfs_lfs = (dfs_lfs_t*)dfs->data; |
||||
|
|
||||
|
if (file->flags & O_DIRECTORY) |
||||
|
{ |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd = rt_malloc(sizeof(dfs_lfs_fd_t)); |
||||
|
if (dfs_lfs_fd == RT_NULL) |
||||
|
{ |
||||
|
rt_kprintf("ERROR:no memory!\n"); |
||||
|
result = -ENOMEM; |
||||
|
|
||||
|
goto _error_dir; |
||||
|
} |
||||
|
rt_memset(dfs_lfs_fd, 0, sizeof(dfs_lfs_fd_t)); |
||||
|
dfs_lfs_fd->lfs = &dfs_lfs->lfs; |
||||
|
|
||||
|
if (file->flags & O_CREAT) |
||||
|
{ |
||||
|
#ifndef LFS_READONLY |
||||
|
result = lfs_mkdir(dfs_lfs_fd->lfs, file->vnode->path); |
||||
|
#else |
||||
|
result = -EINVAL; |
||||
|
#endif |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
goto _error_dir; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
time_t now = time(RT_NULL); |
||||
|
lfs_setattr(dfs_lfs_fd->lfs, file->vnode->path, ATTR_TIMESTAMP, &now, sizeof(time_t)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
result = lfs_dir_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, file->vnode->path); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
goto _error_dir; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
file->data = (void*)dfs_lfs_fd; |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
_error_dir: |
||||
|
if (dfs_lfs_fd != RT_NULL) |
||||
|
{ |
||||
|
rt_free(dfs_lfs_fd); |
||||
|
} |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd = rt_malloc(sizeof(dfs_lfs_fd_t)); |
||||
|
if (dfs_lfs_fd == RT_NULL) |
||||
|
{ |
||||
|
rt_kprintf("ERROR:no memory!\n"); |
||||
|
result = -ENOMEM; |
||||
|
|
||||
|
goto _error_file; |
||||
|
} |
||||
|
rt_memset(dfs_lfs_fd, 0, sizeof(dfs_lfs_fd_t)); |
||||
|
dfs_lfs_fd->lfs = &dfs_lfs->lfs; |
||||
|
|
||||
|
if ((file->flags & 3) == O_RDONLY) |
||||
|
flags |= LFS_O_RDONLY; |
||||
|
if ((file->flags & 3) == O_WRONLY) |
||||
|
flags |= LFS_O_WRONLY; |
||||
|
if ((file->flags & 3) == O_RDWR) |
||||
|
flags |= LFS_O_RDWR; |
||||
|
if (file->flags & O_CREAT) |
||||
|
flags |= LFS_O_CREAT; |
||||
|
if (file->flags & O_EXCL) |
||||
|
flags |= LFS_O_EXCL; |
||||
|
if (file->flags & O_TRUNC) |
||||
|
flags |= LFS_O_TRUNC; |
||||
|
if (file->flags & O_APPEND) |
||||
|
flags |= LFS_O_APPEND; |
||||
|
|
||||
|
result = lfs_file_open(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->vnode->path, flags); |
||||
|
if (result != LFS_ERR_OK) |
||||
|
{ |
||||
|
goto _error_file; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
file->data = (void*)dfs_lfs_fd; |
||||
|
file->pos = dfs_lfs_fd->u.file.pos; |
||||
|
file->vnode->size = dfs_lfs_fd->u.file.ctz.size; |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
_error_file: |
||||
|
if (dfs_lfs_fd != RT_NULL) |
||||
|
{ |
||||
|
rt_free(dfs_lfs_fd); |
||||
|
} |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_close(struct dfs_file* file) |
||||
|
{ |
||||
|
int result; |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
uint8_t need_time_update; |
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
RT_ASSERT(file->vnode->ref_count > 0); |
||||
|
if (file->vnode->ref_count > 1) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)file->data; |
||||
|
|
||||
|
if (file->vnode->type == FT_DIRECTORY) |
||||
|
{ |
||||
|
result = lfs_dir_close(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
need_time_update = (dfs_lfs_fd->u.file.flags & LFS_F_DIRTY) || (dfs_lfs_fd->u.file.flags & LFS_F_WRITING); |
||||
|
result = lfs_file_close(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file); |
||||
|
if (result == LFS_ERR_OK && need_time_update) |
||||
|
{ |
||||
|
time_t now = time(RT_NULL); |
||||
|
lfs_setattr(dfs_lfs_fd->lfs, file->vnode->path, ATTR_TIMESTAMP, &now, sizeof(time_t)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
rt_free(dfs_lfs_fd); |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_ioctl(struct dfs_file* file, int cmd, void* args) |
||||
|
{ |
||||
|
return -ENOSYS; |
||||
|
} |
||||
|
|
||||
|
static DFS_LFS_RW_RETURN_TYPE _dfs_lfs_read(struct dfs_file* file, void* buf, size_t len) |
||||
|
{ |
||||
|
lfs_ssize_t ssize; |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
|
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
if (file->vnode->type == FT_DIRECTORY) |
||||
|
{ |
||||
|
return -EISDIR; |
||||
|
} |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)file->data; |
||||
|
|
||||
|
#if 0 |
||||
|
if (lfs_file_tell(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file) != file->pos) |
||||
|
{ |
||||
|
lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET); |
||||
|
if (soff < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(soff); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
ssize = lfs_file_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, buf, len); |
||||
|
if (ssize < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(ssize); |
||||
|
} |
||||
|
|
||||
|
/* update position */ |
||||
|
file->pos = dfs_lfs_fd->u.file.pos; |
||||
|
|
||||
|
return ssize; |
||||
|
} |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
static DFS_LFS_RW_RETURN_TYPE _dfs_lfs_write(struct dfs_file* file, const void* buf, size_t len) |
||||
|
{ |
||||
|
lfs_ssize_t ssize; |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
if (file->vnode->type == FT_DIRECTORY) |
||||
|
{ |
||||
|
return -EISDIR; |
||||
|
} |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)file->data; |
||||
|
|
||||
|
#if 0 |
||||
|
if (lfs_file_tell(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file) != file->pos) |
||||
|
{ |
||||
|
lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, file->pos, LFS_SEEK_SET); |
||||
|
if (soff < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(soff); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
ssize = lfs_file_write(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, buf, len); |
||||
|
if (ssize < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(ssize); |
||||
|
} |
||||
|
|
||||
|
/* update position and file size */ |
||||
|
file->pos = dfs_lfs_fd->u.file.pos; |
||||
|
file->vnode->size = dfs_lfs_fd->u.file.ctz.size; |
||||
|
|
||||
|
return ssize; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
static int _dfs_lfs_flush(struct dfs_file* file) |
||||
|
{ |
||||
|
int result; |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
uint8_t need_time_update; |
||||
|
|
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)file->data; |
||||
|
need_time_update = (dfs_lfs_fd->u.file.flags & LFS_F_DIRTY) || (dfs_lfs_fd->u.file.flags & LFS_F_WRITING); |
||||
|
result = lfs_file_sync(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file); |
||||
|
if (result == LFS_ERR_OK && need_time_update) |
||||
|
{ |
||||
|
time_t now = time(RT_NULL); |
||||
|
lfs_setattr(dfs_lfs_fd->lfs, file->vnode->path, ATTR_TIMESTAMP, &now, sizeof(time_t)); |
||||
|
} |
||||
|
|
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
static DFS_LFS_LSK_RETURN_TYPE _dfs_lfs_lseek(struct dfs_file* file, rt_off_t offset) |
||||
|
{ |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
|
||||
|
RT_ASSERT(file != RT_NULL); |
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)file->data; |
||||
|
|
||||
|
if (file->vnode->type == FT_REGULAR) |
||||
|
{ |
||||
|
lfs_soff_t soff = lfs_file_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.file, offset, LFS_SEEK_SET); |
||||
|
if (soff < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(soff); |
||||
|
} |
||||
|
|
||||
|
file->pos = dfs_lfs_fd->u.file.pos; |
||||
|
} |
||||
|
else if (file->vnode->type == FT_DIRECTORY) |
||||
|
{ |
||||
|
lfs_soff_t soff = lfs_dir_seek(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, offset); |
||||
|
if (soff < 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(soff); |
||||
|
} |
||||
|
|
||||
|
file->pos = dfs_lfs_fd->u.dir.pos; |
||||
|
} |
||||
|
|
||||
|
return (file->pos); |
||||
|
} |
||||
|
|
||||
|
static int _dfs_lfs_getdents(struct dfs_file* file, struct dirent* dirp, uint32_t count) |
||||
|
{ |
||||
|
dfs_lfs_fd_t* dfs_lfs_fd; |
||||
|
int result; |
||||
|
int index; |
||||
|
struct dirent* d; |
||||
|
struct lfs_info info; |
||||
|
|
||||
|
RT_ASSERT(file->data != RT_NULL); |
||||
|
|
||||
|
dfs_lfs_fd = (dfs_lfs_fd_t*)(file->data); |
||||
|
|
||||
|
/* make integer count */ |
||||
|
count = (count / sizeof(struct dirent)) * sizeof(struct dirent); |
||||
|
if (count == 0) |
||||
|
{ |
||||
|
return -EINVAL; |
||||
|
} |
||||
|
|
||||
|
index = 0; |
||||
|
while (1) |
||||
|
{ |
||||
|
d = dirp + index; |
||||
|
|
||||
|
result = lfs_dir_read(dfs_lfs_fd->lfs, &dfs_lfs_fd->u.dir, &info); |
||||
|
if ((result != 1) || (info.name[0] == 0)) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (rt_strcmp(info.name, ".") == 0) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
else if (rt_strcmp(info.name, "..") == 0) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
d->d_type = DT_UNKNOWN; |
||||
|
|
||||
|
switch (info.type) |
||||
|
{ |
||||
|
case LFS_TYPE_DIR: |
||||
|
d->d_type |= DT_DIR; |
||||
|
break; |
||||
|
|
||||
|
case LFS_TYPE_REG: |
||||
|
d->d_type |= DT_REG; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
d->d_namlen = (rt_uint8_t)rt_strlen(info.name); |
||||
|
d->d_reclen = (rt_uint16_t)sizeof(struct dirent); |
||||
|
rt_strncpy(d->d_name, info.name, DFS_PATH_MAX); |
||||
|
|
||||
|
index++; |
||||
|
if (index * sizeof(struct dirent) >= count) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (index == 0) |
||||
|
{ |
||||
|
return _lfs_result_to_dfs(result); |
||||
|
} |
||||
|
|
||||
|
file->pos += index * sizeof(struct dirent); |
||||
|
|
||||
|
return index * sizeof(struct dirent); |
||||
|
} |
||||
|
|
||||
|
static const struct dfs_file_ops _dfs_lfs_fops = { |
||||
|
_dfs_lfs_open, |
||||
|
_dfs_lfs_close, |
||||
|
_dfs_lfs_ioctl, |
||||
|
_dfs_lfs_read, |
||||
|
#ifndef LFS_READONLY |
||||
|
_dfs_lfs_write, |
||||
|
#else |
||||
|
NULL, |
||||
|
#endif |
||||
|
_dfs_lfs_flush, |
||||
|
_dfs_lfs_lseek, |
||||
|
_dfs_lfs_getdents, |
||||
|
// RT_NULL, /* poll interface */
|
||||
|
}; |
||||
|
|
||||
|
static const struct dfs_filesystem_ops _dfs_lfs_ops = { |
||||
|
"lfs", |
||||
|
DFS_FS_FLAG_DEFAULT, |
||||
|
&_dfs_lfs_fops, |
||||
|
_dfs_lfs_mount, |
||||
|
_dfs_lfs_unmount, |
||||
|
#ifndef LFS_READONLY |
||||
|
_dfs_lfs_mkfs, |
||||
|
#else |
||||
|
NULL, |
||||
|
#endif |
||||
|
_dfs_lfs_statfs, |
||||
|
#ifndef LFS_READONLY |
||||
|
_dfs_lfs_unlink, |
||||
|
#else |
||||
|
NULL, |
||||
|
#endif |
||||
|
_dfs_lfs_stat, |
||||
|
#ifndef LFS_READONLY |
||||
|
_dfs_lfs_rename, |
||||
|
#else |
||||
|
NULL, |
||||
|
#endif |
||||
|
}; |
||||
|
|
||||
|
int dfs_lfs_init(void) |
||||
|
{ |
||||
|
/* register ram file system */ |
||||
|
return dfs_register(&_dfs_lfs_ops); |
||||
|
} |
||||
|
INIT_COMPONENT_EXPORT(dfs_lfs_init); |
||||
File diff suppressed because it is too large
@ -0,0 +1,801 @@ |
|||||
|
/*
|
||||
|
* The little filesystem |
||||
|
* |
||||
|
* Copyright (c) 2022, The littlefs authors. |
||||
|
* Copyright (c) 2017, Arm Limited. All rights reserved. |
||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||
|
*/ |
||||
|
#ifndef LFS_H |
||||
|
#define LFS_H |
||||
|
|
||||
|
#include "lfs_util.h" |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" |
||||
|
{ |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/// Version info ///
|
||||
|
|
||||
|
// Software library version
|
||||
|
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
|
// Minor (bottom-nibble), incremented on feature additions
|
||||
|
#define LFS_VERSION 0x0002000b |
||||
|
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) |
||||
|
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) |
||||
|
|
||||
|
// Version of On-disk data structures
|
||||
|
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
|
// Minor (bottom-nibble), incremented on feature additions
|
||||
|
#define LFS_DISK_VERSION 0x00020001 |
||||
|
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) |
||||
|
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) |
||||
|
|
||||
|
|
||||
|
/// Definitions ///
|
||||
|
|
||||
|
// Type definitions
|
||||
|
typedef uint32_t lfs_size_t; |
||||
|
typedef uint32_t lfs_off_t; |
||||
|
|
||||
|
typedef int32_t lfs_ssize_t; |
||||
|
typedef int32_t lfs_soff_t; |
||||
|
|
||||
|
typedef uint32_t lfs_block_t; |
||||
|
|
||||
|
// Maximum name size in bytes, may be redefined to reduce the size of the
|
||||
|
// info struct. Limited to <= 1022. Stored in superblock and must be
|
||||
|
// respected by other littlefs drivers.
|
||||
|
#ifndef LFS_NAME_MAX |
||||
|
#define LFS_NAME_MAX 255 |
||||
|
#endif |
||||
|
|
||||
|
// Maximum size of a file in bytes, may be redefined to limit to support other
|
||||
|
// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be
|
||||
|
// respected by other littlefs drivers.
|
||||
|
#ifndef LFS_FILE_MAX |
||||
|
#define LFS_FILE_MAX 2147483647 |
||||
|
#endif |
||||
|
|
||||
|
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
||||
|
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored
|
||||
|
// in superblock and must be respected by other littlefs drivers.
|
||||
|
#ifndef LFS_ATTR_MAX |
||||
|
#define LFS_ATTR_MAX 1022 |
||||
|
#endif |
||||
|
|
||||
|
// Possible error codes, these are negative to allow
|
||||
|
// valid positive return values
|
||||
|
enum lfs_error { |
||||
|
LFS_ERR_OK = 0, // No error
|
||||
|
LFS_ERR_IO = -5, // Error during device operation
|
||||
|
LFS_ERR_CORRUPT = -84, // Corrupted
|
||||
|
LFS_ERR_NOENT = -2, // No directory entry
|
||||
|
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
|
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
|
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
|
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
|
LFS_ERR_BADF = -9, // Bad file number
|
||||
|
LFS_ERR_FBIG = -27, // File too large
|
||||
|
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
|
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
|
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
|
LFS_ERR_NOATTR = -61, // No data/attr available
|
||||
|
LFS_ERR_NAMETOOLONG = -36, // File name too long
|
||||
|
}; |
||||
|
|
||||
|
// File types
|
||||
|
enum lfs_type { |
||||
|
// file types
|
||||
|
LFS_TYPE_REG = 0x001, |
||||
|
LFS_TYPE_DIR = 0x002, |
||||
|
|
||||
|
// internally used types
|
||||
|
LFS_TYPE_SPLICE = 0x400, |
||||
|
LFS_TYPE_NAME = 0x000, |
||||
|
LFS_TYPE_STRUCT = 0x200, |
||||
|
LFS_TYPE_USERATTR = 0x300, |
||||
|
LFS_TYPE_FROM = 0x100, |
||||
|
LFS_TYPE_TAIL = 0x600, |
||||
|
LFS_TYPE_GLOBALS = 0x700, |
||||
|
LFS_TYPE_CRC = 0x500, |
||||
|
|
||||
|
// internally used type specializations
|
||||
|
LFS_TYPE_CREATE = 0x401, |
||||
|
LFS_TYPE_DELETE = 0x4ff, |
||||
|
LFS_TYPE_SUPERBLOCK = 0x0ff, |
||||
|
LFS_TYPE_DIRSTRUCT = 0x200, |
||||
|
LFS_TYPE_CTZSTRUCT = 0x202, |
||||
|
LFS_TYPE_INLINESTRUCT = 0x201, |
||||
|
LFS_TYPE_SOFTTAIL = 0x600, |
||||
|
LFS_TYPE_HARDTAIL = 0x601, |
||||
|
LFS_TYPE_MOVESTATE = 0x7ff, |
||||
|
LFS_TYPE_CCRC = 0x500, |
||||
|
LFS_TYPE_FCRC = 0x5ff, |
||||
|
|
||||
|
// internal chip sources
|
||||
|
LFS_FROM_NOOP = 0x000, |
||||
|
LFS_FROM_MOVE = 0x101, |
||||
|
LFS_FROM_USERATTRS = 0x102, |
||||
|
}; |
||||
|
|
||||
|
// File open flags
|
||||
|
enum lfs_open_flags { |
||||
|
// open flags
|
||||
|
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
|
#ifndef LFS_READONLY |
||||
|
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
|
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
|
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
|
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
|
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
|
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
|
#endif |
||||
|
|
||||
|
// internally used flags
|
||||
|
#ifndef LFS_READONLY |
||||
|
LFS_F_DIRTY = 0x010000, // File does not match storage
|
||||
|
LFS_F_WRITING = 0x020000, // File has been written since last flush
|
||||
|
#endif |
||||
|
LFS_F_READING = 0x040000, // File has been read since last flush
|
||||
|
#ifndef LFS_READONLY |
||||
|
LFS_F_ERRED = 0x080000, // An error occurred during write
|
||||
|
#endif |
||||
|
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
|
||||
|
}; |
||||
|
|
||||
|
// File seek flags
|
||||
|
enum lfs_whence_flags { |
||||
|
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
|
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
|
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Configuration provided during initialization of the littlefs
|
||||
|
struct lfs_config { |
||||
|
// Opaque user provided context that can be used to pass
|
||||
|
// information to the block device operations
|
||||
|
void *context; |
||||
|
|
||||
|
// Read a region in a block. Negative error codes are propagated
|
||||
|
// to the user.
|
||||
|
int (*read)(const struct lfs_config *c, lfs_block_t block, |
||||
|
lfs_off_t off, void *buffer, lfs_size_t size); |
||||
|
|
||||
|
// Program a region in a block. The block must have previously
|
||||
|
// been erased. Negative error codes are propagated to the user.
|
||||
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
|
int (*prog)(const struct lfs_config *c, lfs_block_t block, |
||||
|
lfs_off_t off, const void *buffer, lfs_size_t size); |
||||
|
|
||||
|
// Erase a block. A block must be erased before being programmed.
|
||||
|
// The state of an erased block is undefined. Negative error codes
|
||||
|
// are propagated to the user.
|
||||
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
|
int (*erase)(const struct lfs_config *c, lfs_block_t block); |
||||
|
|
||||
|
// Sync the state of the underlying block device. Negative error codes
|
||||
|
// are propagated to the user.
|
||||
|
int (*sync)(const struct lfs_config *c); |
||||
|
|
||||
|
#ifdef LFS_THREADSAFE |
||||
|
// Lock the underlying block device. Negative error codes
|
||||
|
// are propagated to the user.
|
||||
|
int (*lock)(const struct lfs_config *c); |
||||
|
|
||||
|
// Unlock the underlying block device. Negative error codes
|
||||
|
// are propagated to the user.
|
||||
|
int (*unlock)(const struct lfs_config *c); |
||||
|
#endif |
||||
|
|
||||
|
// Minimum size of a block read in bytes. All read operations will be a
|
||||
|
// multiple of this value.
|
||||
|
lfs_size_t read_size; |
||||
|
|
||||
|
// Minimum size of a block program in bytes. All program operations will be
|
||||
|
// a multiple of this value.
|
||||
|
lfs_size_t prog_size; |
||||
|
|
||||
|
// Size of an erasable block in bytes. This does not impact ram consumption
|
||||
|
// and may be larger than the physical erase size. However, non-inlined
|
||||
|
// files take up at minimum one block. Must be a multiple of the read and
|
||||
|
// program sizes.
|
||||
|
lfs_size_t block_size; |
||||
|
|
||||
|
// Number of erasable blocks on the device. Defaults to block_count stored
|
||||
|
// on disk when zero.
|
||||
|
lfs_size_t block_count; |
||||
|
|
||||
|
// Number of erase cycles before littlefs evicts metadata logs and moves
|
||||
|
// the metadata to another block. Suggested values are in the
|
||||
|
// range 100-1000, with large values having better performance at the cost
|
||||
|
// of less consistent wear distribution.
|
||||
|
//
|
||||
|
// Set to -1 to disable block-level wear-leveling.
|
||||
|
int32_t block_cycles; |
||||
|
|
||||
|
// Size of block caches in bytes. Each cache buffers a portion of a block in
|
||||
|
// RAM. The littlefs needs a read cache, a program cache, and one additional
|
||||
|
// cache per file. Larger caches can improve performance by storing more
|
||||
|
// data and reducing the number of disk accesses. Must be a multiple of the
|
||||
|
// read and program sizes, and a factor of the block size.
|
||||
|
lfs_size_t cache_size; |
||||
|
|
||||
|
// Size of the lookahead buffer in bytes. A larger lookahead buffer
|
||||
|
// increases the number of blocks found during an allocation pass. The
|
||||
|
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
|
||||
|
// can track 8 blocks.
|
||||
|
lfs_size_t lookahead_size; |
||||
|
|
||||
|
// Threshold for metadata compaction during lfs_fs_gc in bytes. Metadata
|
||||
|
// pairs that exceed this threshold will be compacted during lfs_fs_gc.
|
||||
|
// Defaults to ~88% block_size when zero, though the default may change
|
||||
|
// in the future.
|
||||
|
//
|
||||
|
// Note this only affects lfs_fs_gc. Normal compactions still only occur
|
||||
|
// when full.
|
||||
|
//
|
||||
|
// Set to -1 to disable metadata compaction during lfs_fs_gc.
|
||||
|
lfs_size_t compact_thresh; |
||||
|
|
||||
|
// Optional statically allocated read buffer. Must be cache_size.
|
||||
|
// By default lfs_malloc is used to allocate this buffer.
|
||||
|
void *read_buffer; |
||||
|
|
||||
|
// Optional statically allocated program buffer. Must be cache_size.
|
||||
|
// By default lfs_malloc is used to allocate this buffer.
|
||||
|
void *prog_buffer; |
||||
|
|
||||
|
// Optional statically allocated lookahead buffer. Must be lookahead_size.
|
||||
|
// By default lfs_malloc is used to allocate this buffer.
|
||||
|
void *lookahead_buffer; |
||||
|
|
||||
|
// Optional upper limit on length of file names in bytes. No downside for
|
||||
|
// larger names except the size of the info struct which is controlled by
|
||||
|
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on
|
||||
|
// disk when zero.
|
||||
|
lfs_size_t name_max; |
||||
|
|
||||
|
// Optional upper limit on files in bytes. No downside for larger files
|
||||
|
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored
|
||||
|
// on disk when zero.
|
||||
|
lfs_size_t file_max; |
||||
|
|
||||
|
// Optional upper limit on custom attributes in bytes. No downside for
|
||||
|
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
||||
|
// LFS_ATTR_MAX or attr_max stored on disk when zero.
|
||||
|
lfs_size_t attr_max; |
||||
|
|
||||
|
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||
|
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
|
||||
|
// can help bound the metadata compaction time. Must be <= block_size.
|
||||
|
// Defaults to block_size when zero.
|
||||
|
lfs_size_t metadata_max; |
||||
|
|
||||
|
// Optional upper limit on inlined files in bytes. Inlined files live in
|
||||
|
// metadata and decrease storage requirements, but may be limited to
|
||||
|
// improve metadata-related performance. Must be <= cache_size, <=
|
||||
|
// attr_max, and <= block_size/8. Defaults to the largest possible
|
||||
|
// inline_max when zero.
|
||||
|
//
|
||||
|
// Set to -1 to disable inlined files.
|
||||
|
lfs_size_t inline_max; |
||||
|
|
||||
|
#ifdef LFS_MULTIVERSION |
||||
|
// On-disk version to use when writing in the form of 16-bit major version
|
||||
|
// + 16-bit minor version. This limiting metadata to what is supported by
|
||||
|
// older minor versions. Note that some features will be lost. Defaults to
|
||||
|
// to the most recent minor version when zero.
|
||||
|
uint32_t disk_version; |
||||
|
#endif |
||||
|
}; |
||||
|
|
||||
|
// File info structure
|
||||
|
struct lfs_info { |
||||
|
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
|
uint8_t type; |
||||
|
|
||||
|
// Size of the file, only valid for REG files. Limited to 32-bits.
|
||||
|
lfs_size_t size; |
||||
|
|
||||
|
// Name of the file stored as a null-terminated string. Limited to
|
||||
|
// LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
|
||||
|
// reduce RAM. LFS_NAME_MAX is stored in superblock and must be
|
||||
|
// respected by other littlefs drivers.
|
||||
|
char name[LFS_NAME_MAX+1]; |
||||
|
}; |
||||
|
|
||||
|
// Filesystem info structure
|
||||
|
struct lfs_fsinfo { |
||||
|
// On-disk version.
|
||||
|
uint32_t disk_version; |
||||
|
|
||||
|
// Size of a logical block in bytes.
|
||||
|
lfs_size_t block_size; |
||||
|
|
||||
|
// Number of logical blocks in filesystem.
|
||||
|
lfs_size_t block_count; |
||||
|
|
||||
|
// Upper limit on the length of file names in bytes.
|
||||
|
lfs_size_t name_max; |
||||
|
|
||||
|
// Upper limit on the size of files in bytes.
|
||||
|
lfs_size_t file_max; |
||||
|
|
||||
|
// Upper limit on the size of custom attributes in bytes.
|
||||
|
lfs_size_t attr_max; |
||||
|
}; |
||||
|
|
||||
|
// Custom attribute structure, used to describe custom attributes
|
||||
|
// committed atomically during file writes.
|
||||
|
struct lfs_attr { |
||||
|
// 8-bit type of attribute, provided by user and used to
|
||||
|
// identify the attribute
|
||||
|
uint8_t type; |
||||
|
|
||||
|
// Pointer to buffer containing the attribute
|
||||
|
void *buffer; |
||||
|
|
||||
|
// Size of attribute in bytes, limited to LFS_ATTR_MAX
|
||||
|
lfs_size_t size; |
||||
|
}; |
||||
|
|
||||
|
// Optional configuration provided during lfs_file_opencfg
|
||||
|
struct lfs_file_config { |
||||
|
// Optional statically allocated file buffer. Must be cache_size.
|
||||
|
// By default lfs_malloc is used to allocate this buffer.
|
||||
|
void *buffer; |
||||
|
|
||||
|
// Optional list of custom attributes related to the file. If the file
|
||||
|
// is opened with read access, these attributes will be read from disk
|
||||
|
// during the open call. If the file is opened with write access, the
|
||||
|
// attributes will be written to disk every file sync or close. This
|
||||
|
// write occurs atomically with update to the file's contents.
|
||||
|
//
|
||||
|
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
|
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
|
||||
|
// than the buffer, it will be padded with zeros. If the stored attribute
|
||||
|
// is larger, then it will be silently truncated. If the attribute is not
|
||||
|
// found, it will be created implicitly.
|
||||
|
struct lfs_attr *attrs; |
||||
|
|
||||
|
// Number of custom attributes in the list
|
||||
|
lfs_size_t attr_count; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/// internal littlefs data structures ///
|
||||
|
typedef struct lfs_cache { |
||||
|
lfs_block_t block; |
||||
|
lfs_off_t off; |
||||
|
lfs_size_t size; |
||||
|
uint8_t *buffer; |
||||
|
} lfs_cache_t; |
||||
|
|
||||
|
typedef struct lfs_mdir { |
||||
|
lfs_block_t pair[2]; |
||||
|
uint32_t rev; |
||||
|
lfs_off_t off; |
||||
|
uint32_t etag; |
||||
|
uint16_t count; |
||||
|
bool erased; |
||||
|
bool split; |
||||
|
lfs_block_t tail[2]; |
||||
|
} lfs_mdir_t; |
||||
|
|
||||
|
// littlefs directory type
|
||||
|
typedef struct lfs_dir { |
||||
|
struct lfs_dir *next; |
||||
|
uint16_t id; |
||||
|
uint8_t type; |
||||
|
lfs_mdir_t m; |
||||
|
|
||||
|
lfs_off_t pos; |
||||
|
lfs_block_t head[2]; |
||||
|
} lfs_dir_t; |
||||
|
|
||||
|
// littlefs file type
|
||||
|
typedef struct lfs_file { |
||||
|
struct lfs_file *next; |
||||
|
uint16_t id; |
||||
|
uint8_t type; |
||||
|
lfs_mdir_t m; |
||||
|
|
||||
|
struct lfs_ctz { |
||||
|
lfs_block_t head; |
||||
|
lfs_size_t size; |
||||
|
} ctz; |
||||
|
|
||||
|
uint32_t flags; |
||||
|
lfs_off_t pos; |
||||
|
lfs_block_t block; |
||||
|
lfs_off_t off; |
||||
|
lfs_cache_t cache; |
||||
|
|
||||
|
const struct lfs_file_config *cfg; |
||||
|
} lfs_file_t; |
||||
|
|
||||
|
typedef struct lfs_superblock { |
||||
|
uint32_t version; |
||||
|
lfs_size_t block_size; |
||||
|
lfs_size_t block_count; |
||||
|
lfs_size_t name_max; |
||||
|
lfs_size_t file_max; |
||||
|
lfs_size_t attr_max; |
||||
|
} lfs_superblock_t; |
||||
|
|
||||
|
typedef struct lfs_gstate { |
||||
|
uint32_t tag; |
||||
|
lfs_block_t pair[2]; |
||||
|
} lfs_gstate_t; |
||||
|
|
||||
|
// The littlefs filesystem type
|
||||
|
typedef struct lfs { |
||||
|
lfs_cache_t rcache; |
||||
|
lfs_cache_t pcache; |
||||
|
|
||||
|
lfs_block_t root[2]; |
||||
|
struct lfs_mlist { |
||||
|
struct lfs_mlist *next; |
||||
|
uint16_t id; |
||||
|
uint8_t type; |
||||
|
lfs_mdir_t m; |
||||
|
} *mlist; |
||||
|
uint32_t seed; |
||||
|
|
||||
|
lfs_gstate_t gstate; |
||||
|
lfs_gstate_t gdisk; |
||||
|
lfs_gstate_t gdelta; |
||||
|
|
||||
|
struct lfs_lookahead { |
||||
|
lfs_block_t start; |
||||
|
lfs_block_t size; |
||||
|
lfs_block_t next; |
||||
|
lfs_block_t ckpoint; |
||||
|
uint8_t *buffer; |
||||
|
} lookahead; |
||||
|
|
||||
|
const struct lfs_config *cfg; |
||||
|
lfs_size_t block_count; |
||||
|
lfs_size_t name_max; |
||||
|
lfs_size_t file_max; |
||||
|
lfs_size_t attr_max; |
||||
|
lfs_size_t inline_max; |
||||
|
|
||||
|
#ifdef LFS_MIGRATE |
||||
|
struct lfs1 *lfs1; |
||||
|
#endif |
||||
|
} lfs_t; |
||||
|
|
||||
|
|
||||
|
/// Filesystem functions ///
|
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Format a block device with the littlefs
|
||||
|
//
|
||||
|
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
|
// object, and does not leave the filesystem mounted. The config struct must
|
||||
|
// be zeroed for defaults and backwards compatibility.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_format(lfs_t *lfs, const struct lfs_config *config); |
||||
|
#endif |
||||
|
|
||||
|
// Mounts a littlefs
|
||||
|
//
|
||||
|
// Requires a littlefs object and config struct. Multiple filesystems
|
||||
|
// may be mounted simultaneously with multiple littlefs objects. Both
|
||||
|
// lfs and config must be allocated while mounted. The config struct must
|
||||
|
// be zeroed for defaults and backwards compatibility.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_mount(lfs_t *lfs, const struct lfs_config *config); |
||||
|
|
||||
|
// Unmounts a littlefs
|
||||
|
//
|
||||
|
// Does nothing besides releasing any allocated resources.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_unmount(lfs_t *lfs); |
||||
|
|
||||
|
/// General operations ///
|
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Removes a file or directory
|
||||
|
//
|
||||
|
// If removing a directory, the directory must be empty.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_remove(lfs_t *lfs, const char *path); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Rename or move a file or directory
|
||||
|
//
|
||||
|
// If the destination exists, it must match the source in type.
|
||||
|
// If the destination is a directory, the directory must be empty.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); |
||||
|
#endif |
||||
|
|
||||
|
// Find info about a file or directory
|
||||
|
//
|
||||
|
// Fills out the info structure, based on the specified file or directory.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); |
||||
|
|
||||
|
// Get a custom attribute
|
||||
|
//
|
||||
|
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
|
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
|
||||
|
// the buffer, it will be padded with zeros. If the stored attribute is larger,
|
||||
|
// then it will be silently truncated. If no attribute is found, the error
|
||||
|
// LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
|
||||
|
//
|
||||
|
// Returns the size of the attribute, or a negative error code on failure.
|
||||
|
// Note, the returned size is the size of the attribute on disk, irrespective
|
||||
|
// of the size of the buffer. This can be used to dynamically allocate a buffer
|
||||
|
// or check for existence.
|
||||
|
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, |
||||
|
uint8_t type, void *buffer, lfs_size_t size); |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Set custom attributes
|
||||
|
//
|
||||
|
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||
|
// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be
|
||||
|
// implicitly created.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_setattr(lfs_t *lfs, const char *path, |
||||
|
uint8_t type, const void *buffer, lfs_size_t size); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Removes a custom attribute
|
||||
|
//
|
||||
|
// If an attribute is not found, nothing happens.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/// File operations ///
|
||||
|
|
||||
|
#ifndef LFS_NO_MALLOC |
||||
|
// Open a file
|
||||
|
//
|
||||
|
// The mode that the file is opened in is determined by the flags, which
|
||||
|
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_open(lfs_t *lfs, lfs_file_t *file, |
||||
|
const char *path, int flags); |
||||
|
|
||||
|
// if LFS_NO_MALLOC is defined, lfs_file_open() will fail with LFS_ERR_NOMEM
|
||||
|
// thus use lfs_file_opencfg() with config.buffer set.
|
||||
|
#endif |
||||
|
|
||||
|
// Open a file with extra configuration
|
||||
|
//
|
||||
|
// The mode that the file is opened in is determined by the flags, which
|
||||
|
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
|
//
|
||||
|
// The config struct provides additional config options per file as described
|
||||
|
// above. The config struct must remain allocated while the file is open, and
|
||||
|
// the config struct must be zeroed for defaults and backwards compatibility.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, |
||||
|
const char *path, int flags, |
||||
|
const struct lfs_file_config *config); |
||||
|
|
||||
|
// Close a file
|
||||
|
//
|
||||
|
// Any pending writes are written out to storage as though
|
||||
|
// sync had been called and releases any allocated resources.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_close(lfs_t *lfs, lfs_file_t *file); |
||||
|
|
||||
|
// Synchronize a file on storage
|
||||
|
//
|
||||
|
// Any pending writes are written out to storage.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); |
||||
|
|
||||
|
// Read data from file
|
||||
|
//
|
||||
|
// Takes a buffer and size indicating where to store the read data.
|
||||
|
// Returns the number of bytes read, or a negative error code on failure.
|
||||
|
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, |
||||
|
void *buffer, lfs_size_t size); |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Write data to file
|
||||
|
//
|
||||
|
// Takes a buffer and size indicating the data to write. The file will not
|
||||
|
// actually be updated on the storage until either sync or close is called.
|
||||
|
//
|
||||
|
// Returns the number of bytes written, or a negative error code on failure.
|
||||
|
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, |
||||
|
const void *buffer, lfs_size_t size); |
||||
|
#endif |
||||
|
|
||||
|
// Change the position of the file
|
||||
|
//
|
||||
|
// The change in position is determined by the offset and whence flag.
|
||||
|
// Returns the new position of the file, or a negative error code on failure.
|
||||
|
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, |
||||
|
lfs_soff_t off, int whence); |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Truncates the size of the file to the specified size
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); |
||||
|
#endif |
||||
|
|
||||
|
// Return the position of the file
|
||||
|
//
|
||||
|
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
|
||||
|
// Returns the position of the file, or a negative error code on failure.
|
||||
|
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); |
||||
|
|
||||
|
// Change the position of the file to the beginning of the file
|
||||
|
//
|
||||
|
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); |
||||
|
|
||||
|
// Return the size of the file
|
||||
|
//
|
||||
|
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
|
||||
|
// Returns the size of the file, or a negative error code on failure.
|
||||
|
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); |
||||
|
|
||||
|
|
||||
|
/// Directory operations ///
|
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Create a directory
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_mkdir(lfs_t *lfs, const char *path); |
||||
|
#endif |
||||
|
|
||||
|
// Open a directory
|
||||
|
//
|
||||
|
// Once open a directory can be used with read to iterate over files.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); |
||||
|
|
||||
|
// Close a directory
|
||||
|
//
|
||||
|
// Releases any allocated resources.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); |
||||
|
|
||||
|
// Read an entry in the directory
|
||||
|
//
|
||||
|
// Fills out the info structure, based on the specified file or directory.
|
||||
|
// Returns a positive value on success, 0 at the end of directory,
|
||||
|
// or a negative error code on failure.
|
||||
|
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); |
||||
|
|
||||
|
// Change the position of the directory
|
||||
|
//
|
||||
|
// The new off must be a value previous returned from tell and specifies
|
||||
|
// an absolute offset in the directory seek.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); |
||||
|
|
||||
|
// Return the position of the directory
|
||||
|
//
|
||||
|
// The returned offset is only meant to be consumed by seek and may not make
|
||||
|
// sense, but does indicate the current position in the directory iteration.
|
||||
|
//
|
||||
|
// Returns the position of the directory, or a negative error code on failure.
|
||||
|
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); |
||||
|
|
||||
|
// Change the position of the directory to the beginning of the directory
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); |
||||
|
|
||||
|
|
||||
|
/// Filesystem-level filesystem operations
|
||||
|
|
||||
|
// Find on-disk info about the filesystem
|
||||
|
//
|
||||
|
// Fills out the fsinfo structure based on the filesystem found on-disk.
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo); |
||||
|
|
||||
|
// Finds the current size of the filesystem
|
||||
|
//
|
||||
|
// Note: Result is best effort. If files share COW structures, the returned
|
||||
|
// size may be larger than the filesystem actually is.
|
||||
|
//
|
||||
|
// Returns the number of allocated blocks, or a negative error code on failure.
|
||||
|
lfs_ssize_t lfs_fs_size(lfs_t *lfs); |
||||
|
|
||||
|
// Traverse through all blocks in use by the filesystem
|
||||
|
//
|
||||
|
// The provided callback will be called with each block address that is
|
||||
|
// currently in use by the filesystem. This can be used to determine which
|
||||
|
// blocks are in use or how much of the storage is available.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Attempt to make the filesystem consistent and ready for writing
|
||||
|
//
|
||||
|
// Calling this function is not required, consistency will be implicitly
|
||||
|
// enforced on the first operation that writes to the filesystem, but this
|
||||
|
// function allows the work to be performed earlier and without other
|
||||
|
// filesystem changes.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_fs_mkconsistent(lfs_t *lfs); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Attempt any janitorial work
|
||||
|
//
|
||||
|
// This currently:
|
||||
|
// 1. Calls mkconsistent if not already consistent
|
||||
|
// 2. Compacts metadata > compact_thresh
|
||||
|
// 3. Populates the block allocator
|
||||
|
//
|
||||
|
// Though additional janitorial work may be added in the future.
|
||||
|
//
|
||||
|
// Calling this function is not required, but may allow the offloading of
|
||||
|
// expensive janitorial work to a less time-critical code path.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure. Accomplishing nothing is not
|
||||
|
// an error.
|
||||
|
int lfs_fs_gc(lfs_t *lfs); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
// Grows the filesystem to a new size, updating the superblock with the new
|
||||
|
// block count.
|
||||
|
//
|
||||
|
// If LFS_SHRINKNONRELOCATING is defined, this function will also accept
|
||||
|
// block_counts smaller than the current configuration, after checking
|
||||
|
// that none of the blocks that are being removed are in use.
|
||||
|
// Note that littlefs's pseudorandom block allocation means that
|
||||
|
// this is very unlikely to work in the general case.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_READONLY |
||||
|
#ifdef LFS_MIGRATE |
||||
|
// Attempts to migrate a previous version of littlefs
|
||||
|
//
|
||||
|
// Behaves similarly to the lfs_format function. Attempts to mount
|
||||
|
// the previous version of littlefs and update the filesystem so it can be
|
||||
|
// mounted with the current version of littlefs.
|
||||
|
//
|
||||
|
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
|
// object, and does not leave the filesystem mounted. The config struct must
|
||||
|
// be zeroed for defaults and backwards compatibility.
|
||||
|
//
|
||||
|
// Returns a negative error code on failure.
|
||||
|
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,202 @@ |
|||||
|
#ifndef _LFS_CONFIG_H_ |
||||
|
#define _LFS_CONFIG_H_ |
||||
|
|
||||
|
#include <rtthread.h> |
||||
|
|
||||
|
// System includes
|
||||
|
#include <stdint.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <string.h> |
||||
|
#include <inttypes.h> |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" |
||||
|
{ |
||||
|
#endif |
||||
|
// Macros, may be replaced by system specific wrappers. Arguments to these
|
||||
|
// macros must not have side-effects as the macros can be removed for a smaller
|
||||
|
// code footprint
|
||||
|
|
||||
|
// Logging functions
|
||||
|
#ifdef LFS_YES_TRACE |
||||
|
#define LFS_TRACE(fmt, ...) \ |
||||
|
rt_kprintf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_TRACE(...) |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_NO_DEBUG |
||||
|
#define LFS_DEBUG_(fmt, ...) \ |
||||
|
rt_kprintf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_DEBUG(...) |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_NO_WARN |
||||
|
#define LFS_WARN_(fmt, ...) \ |
||||
|
rt_kprintf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_WARN(...) |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_NO_ERROR |
||||
|
#define LFS_ERROR_(fmt, ...) \ |
||||
|
rt_kprintf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_ERROR(...) |
||||
|
#endif |
||||
|
|
||||
|
// Runtime assertions
|
||||
|
#ifndef LFS_NO_ASSERT |
||||
|
#define LFS_ASSERT(test) RT_ASSERT(test) |
||||
|
#else |
||||
|
#define LFS_ASSERT(test) |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
// Builtin functions, these may be replaced by more efficient
|
||||
|
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
||||
|
// expensive basic C implementation for debugging purposes
|
||||
|
|
||||
|
// Min/max functions for unsigned 32-bit numbers
|
||||
|
static inline uint32_t lfs_max(uint32_t a, uint32_t b) { |
||||
|
return (a > b) ? a : b; |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_min(uint32_t a, uint32_t b) { |
||||
|
return (a < b) ? a : b; |
||||
|
} |
||||
|
|
||||
|
// Align to nearest multiple of a size
|
||||
|
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { |
||||
|
return a - (a % alignment); |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { |
||||
|
return lfs_aligndown(a + alignment-1, alignment); |
||||
|
} |
||||
|
|
||||
|
// Find the smallest power of 2 greater than or equal to a
|
||||
|
static inline uint32_t lfs_npw2(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) |
||||
|
return 32 - __builtin_clz(a-1); |
||||
|
#else |
||||
|
uint32_t r = 0; |
||||
|
uint32_t s; |
||||
|
a -= 1; |
||||
|
s = (a > 0xffff) << 4; a >>= s; r |= s; |
||||
|
s = (a > 0xff ) << 3; a >>= s; r |= s; |
||||
|
s = (a > 0xf ) << 2; a >>= s; r |= s; |
||||
|
s = (a > 0x3 ) << 1; a >>= s; r |= s; |
||||
|
return (r | (a >> 1)) + 1; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Count the number of trailing binary zeros in a
|
||||
|
// lfs_ctz(0) may be undefined
|
||||
|
static inline uint32_t lfs_ctz(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) |
||||
|
return __builtin_ctz(a); |
||||
|
#else |
||||
|
return lfs_npw2((a & -a) + 1) - 1; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Count the number of binary ones in a
|
||||
|
static inline uint32_t lfs_popc(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) |
||||
|
return __builtin_popcount(a); |
||||
|
#else |
||||
|
a = a - ((a >> 1) & 0x55555555); |
||||
|
a = (a & 0x33333333) + ((a >> 2) & 0x33333333); |
||||
|
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Find the sequence comparison of a and b, this is the distance
|
||||
|
// between a and b ignoring overflow
|
||||
|
static inline int lfs_scmp(uint32_t a, uint32_t b) { |
||||
|
return (int)(unsigned)(a - b); |
||||
|
} |
||||
|
|
||||
|
// Convert between 32-bit little-endian and native order
|
||||
|
static inline uint32_t lfs_fromle32(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
||||
|
return a; |
||||
|
#elif !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) |
||||
|
return __builtin_bswap32(a); |
||||
|
#else |
||||
|
return (((uint8_t*)&a)[0] << 0) | |
||||
|
(((uint8_t*)&a)[1] << 8) | |
||||
|
(((uint8_t*)&a)[2] << 16) | |
||||
|
(((uint8_t*)&a)[3] << 24); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_tole32(uint32_t a) { |
||||
|
return lfs_fromle32(a); |
||||
|
} |
||||
|
|
||||
|
// Convert between 32-bit big-endian and native order
|
||||
|
static inline uint32_t lfs_frombe32(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
||||
|
return __builtin_bswap32(a); |
||||
|
#elif !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) |
||||
|
return a; |
||||
|
#else |
||||
|
return (((uint8_t*)&a)[0] << 24) | |
||||
|
(((uint8_t*)&a)[1] << 16) | |
||||
|
(((uint8_t*)&a)[2] << 8) | |
||||
|
(((uint8_t*)&a)[3] << 0); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_tobe32(uint32_t a) { |
||||
|
return lfs_frombe32(a); |
||||
|
} |
||||
|
|
||||
|
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
|
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); |
||||
|
|
||||
|
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
|
// Note, memory must be 64-bit aligned
|
||||
|
static inline void *lfs_malloc(size_t size) { |
||||
|
#ifndef LFS_NO_MALLOC |
||||
|
return rt_malloc(size); |
||||
|
#else |
||||
|
(void)size; |
||||
|
return NULL; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
|
static inline void lfs_free(void *p) { |
||||
|
#ifndef LFS_NO_MALLOC |
||||
|
rt_free(p); |
||||
|
#else |
||||
|
(void)p; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,20 @@ |
|||||
|
#include "lfs_util.h" |
||||
|
|
||||
|
// Software CRC implementation with small lookup table
|
||||
|
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { |
||||
|
static const uint32_t rtable[16] = { |
||||
|
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
||||
|
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
||||
|
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
||||
|
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, |
||||
|
}; |
||||
|
|
||||
|
const uint8_t *data = buffer; |
||||
|
|
||||
|
for (size_t i = 0; i < size; i++) { |
||||
|
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; |
||||
|
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; |
||||
|
} |
||||
|
|
||||
|
return crc; |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
* lfs util functions |
||||
|
* |
||||
|
* Copyright (c) 2022, The littlefs authors. |
||||
|
* Copyright (c) 2017, Arm Limited. All rights reserved. |
||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||
|
*/ |
||||
|
#include "lfs_util.h" |
||||
|
|
||||
|
// Only compile if user does not provide custom config
|
||||
|
#ifndef LFS_CONFIG |
||||
|
|
||||
|
|
||||
|
// If user provides their own CRC impl we don't need this
|
||||
|
#ifndef LFS_CRC |
||||
|
// Software CRC implementation with small lookup table
|
||||
|
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { |
||||
|
static const uint32_t rtable[16] = { |
||||
|
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
||||
|
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
||||
|
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
||||
|
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, |
||||
|
}; |
||||
|
|
||||
|
const uint8_t *data = buffer; |
||||
|
|
||||
|
for (size_t i = 0; i < size; i++) { |
||||
|
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; |
||||
|
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; |
||||
|
} |
||||
|
|
||||
|
return crc; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,273 @@ |
|||||
|
/*
|
||||
|
* lfs utility functions |
||||
|
* |
||||
|
* Copyright (c) 2022, The littlefs authors. |
||||
|
* Copyright (c) 2017, Arm Limited. All rights reserved. |
||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||
|
*/ |
||||
|
#ifndef LFS_UTIL_H |
||||
|
#define LFS_UTIL_H |
||||
|
|
||||
|
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) |
||||
|
#define LFS_STRINGIZE2(x) #x |
||||
|
|
||||
|
// Users can override lfs_util.h with their own configuration by defining
|
||||
|
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
|
||||
|
//
|
||||
|
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
|
||||
|
// provided by the config file. To start, I would suggest copying lfs_util.h
|
||||
|
// and modifying as needed.
|
||||
|
#ifdef LFS_CONFIG |
||||
|
#include LFS_STRINGIZE(LFS_CONFIG) |
||||
|
#else |
||||
|
|
||||
|
// Alternatively, users can provide a header file which defines
|
||||
|
// macros and other things consumed by littlefs.
|
||||
|
//
|
||||
|
// For example, provide my_defines.h, which contains
|
||||
|
// something like:
|
||||
|
//
|
||||
|
// #include <stddef.h>
|
||||
|
// extern void *my_malloc(size_t sz);
|
||||
|
// #define LFS_MALLOC(sz) my_malloc(sz)
|
||||
|
//
|
||||
|
// And build littlefs with the header by defining LFS_DEFINES.
|
||||
|
// (-DLFS_DEFINES=my_defines.h)
|
||||
|
|
||||
|
#ifdef LFS_DEFINES |
||||
|
#include LFS_STRINGIZE(LFS_DEFINES) |
||||
|
#endif |
||||
|
|
||||
|
// System includes
|
||||
|
#include <stdint.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <string.h> |
||||
|
#include <inttypes.h> |
||||
|
|
||||
|
#ifndef LFS_NO_MALLOC |
||||
|
#include <stdlib.h> |
||||
|
#endif |
||||
|
#ifndef LFS_NO_ASSERT |
||||
|
#include <assert.h> |
||||
|
#endif |
||||
|
#if !defined(LFS_NO_DEBUG) || \ |
||||
|
!defined(LFS_NO_WARN) || \ |
||||
|
!defined(LFS_NO_ERROR) || \ |
||||
|
defined(LFS_YES_TRACE) |
||||
|
#include <stdio.h> |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" |
||||
|
{ |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
// Macros, may be replaced by system specific wrappers. Arguments to these
|
||||
|
// macros must not have side-effects as the macros can be removed for a smaller
|
||||
|
// code footprint
|
||||
|
|
||||
|
// Logging functions
|
||||
|
#ifndef LFS_TRACE |
||||
|
#ifdef LFS_YES_TRACE |
||||
|
#define LFS_TRACE_(fmt, ...) \ |
||||
|
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_TRACE(...) |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_DEBUG |
||||
|
#ifndef LFS_NO_DEBUG |
||||
|
#define LFS_DEBUG_(fmt, ...) \ |
||||
|
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_DEBUG(...) |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_WARN |
||||
|
#ifndef LFS_NO_WARN |
||||
|
#define LFS_WARN_(fmt, ...) \ |
||||
|
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_WARN(...) |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef LFS_ERROR |
||||
|
#ifndef LFS_NO_ERROR |
||||
|
#define LFS_ERROR_(fmt, ...) \ |
||||
|
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |
||||
|
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") |
||||
|
#else |
||||
|
#define LFS_ERROR(...) |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
// Runtime assertions
|
||||
|
#ifndef LFS_ASSERT |
||||
|
#ifndef LFS_NO_ASSERT |
||||
|
#define LFS_ASSERT(test) assert(test) |
||||
|
#else |
||||
|
#define LFS_ASSERT(test) |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
// Builtin functions, these may be replaced by more efficient
|
||||
|
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
||||
|
// expensive basic C implementation for debugging purposes
|
||||
|
|
||||
|
// Min/max functions for unsigned 32-bit numbers
|
||||
|
static inline uint32_t lfs_max(uint32_t a, uint32_t b) { |
||||
|
return (a > b) ? a : b; |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_min(uint32_t a, uint32_t b) { |
||||
|
return (a < b) ? a : b; |
||||
|
} |
||||
|
|
||||
|
// Align to nearest multiple of a size
|
||||
|
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { |
||||
|
return a - (a % alignment); |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { |
||||
|
return lfs_aligndown(a + alignment-1, alignment); |
||||
|
} |
||||
|
|
||||
|
// Find the smallest power of 2 greater than or equal to a
|
||||
|
static inline uint32_t lfs_npw2(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) |
||||
|
return 32 - __builtin_clz(a-1); |
||||
|
#else |
||||
|
uint32_t r = 0; |
||||
|
uint32_t s; |
||||
|
a -= 1; |
||||
|
s = (a > 0xffff) << 4; a >>= s; r |= s; |
||||
|
s = (a > 0xff ) << 3; a >>= s; r |= s; |
||||
|
s = (a > 0xf ) << 2; a >>= s; r |= s; |
||||
|
s = (a > 0x3 ) << 1; a >>= s; r |= s; |
||||
|
return (r | (a >> 1)) + 1; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Count the number of trailing binary zeros in a
|
||||
|
// lfs_ctz(0) may be undefined
|
||||
|
static inline uint32_t lfs_ctz(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) |
||||
|
return __builtin_ctz(a); |
||||
|
#else |
||||
|
return lfs_npw2((a & -a) + 1) - 1; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Count the number of binary ones in a
|
||||
|
static inline uint32_t lfs_popc(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) |
||||
|
return __builtin_popcount(a); |
||||
|
#else |
||||
|
a = a - ((a >> 1) & 0x55555555); |
||||
|
a = (a & 0x33333333) + ((a >> 2) & 0x33333333); |
||||
|
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Find the sequence comparison of a and b, this is the distance
|
||||
|
// between a and b ignoring overflow
|
||||
|
static inline int lfs_scmp(uint32_t a, uint32_t b) { |
||||
|
return (int)(unsigned)(a - b); |
||||
|
} |
||||
|
|
||||
|
// Convert between 32-bit little-endian and native order
|
||||
|
static inline uint32_t lfs_fromle32(uint32_t a) { |
||||
|
#if (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
||||
|
return a; |
||||
|
#elif !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) |
||||
|
return __builtin_bswap32(a); |
||||
|
#else |
||||
|
return ((uint32_t)((uint8_t*)&a)[0] << 0) | |
||||
|
((uint32_t)((uint8_t*)&a)[1] << 8) | |
||||
|
((uint32_t)((uint8_t*)&a)[2] << 16) | |
||||
|
((uint32_t)((uint8_t*)&a)[3] << 24); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_tole32(uint32_t a) { |
||||
|
return lfs_fromle32(a); |
||||
|
} |
||||
|
|
||||
|
// Convert between 32-bit big-endian and native order
|
||||
|
static inline uint32_t lfs_frombe32(uint32_t a) { |
||||
|
#if !defined(LFS_NO_INTRINSICS) && ( \ |
||||
|
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
||||
|
return __builtin_bswap32(a); |
||||
|
#elif (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ |
||||
|
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
||||
|
return a; |
||||
|
#else |
||||
|
return ((uint32_t)((uint8_t*)&a)[0] << 24) | |
||||
|
((uint32_t)((uint8_t*)&a)[1] << 16) | |
||||
|
((uint32_t)((uint8_t*)&a)[2] << 8) | |
||||
|
((uint32_t)((uint8_t*)&a)[3] << 0); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static inline uint32_t lfs_tobe32(uint32_t a) { |
||||
|
return lfs_frombe32(a); |
||||
|
} |
||||
|
|
||||
|
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
|
#ifdef LFS_CRC |
||||
|
static inline uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { |
||||
|
return LFS_CRC(crc, buffer, size); |
||||
|
} |
||||
|
#else |
||||
|
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); |
||||
|
#endif |
||||
|
|
||||
|
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
|
//
|
||||
|
// littlefs current has no alignment requirements, as it only allocates
|
||||
|
// byte-level buffers.
|
||||
|
static inline void *lfs_malloc(size_t size) { |
||||
|
#if defined(LFS_MALLOC) |
||||
|
return LFS_MALLOC(size); |
||||
|
#elif !defined(LFS_NO_MALLOC) |
||||
|
return malloc(size); |
||||
|
#else |
||||
|
(void)size; |
||||
|
return NULL; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
|
static inline void lfs_free(void *p) { |
||||
|
#if defined(LFS_FREE) |
||||
|
LFS_FREE(p); |
||||
|
#elif !defined(LFS_NO_MALLOC) |
||||
|
free(p); |
||||
|
#else |
||||
|
(void)p; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
#endif |
||||
File diff suppressed because it is too large
@ -0,0 +1,146 @@ |
|||||
|
/*
|
||||
|
* Runner for littlefs benchmarks |
||||
|
* |
||||
|
* Copyright (c) 2022, The littlefs authors. |
||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||
|
*/ |
||||
|
#ifndef BENCH_RUNNER_H |
||||
|
#define BENCH_RUNNER_H |
||||
|
|
||||
|
|
||||
|
// override LFS_TRACE
|
||||
|
void bench_trace(const char *fmt, ...); |
||||
|
|
||||
|
#define LFS_TRACE_(fmt, ...) \ |
||||
|
bench_trace("%s:%d:trace: " fmt "%s\n", \ |
||||
|
__FILE__, \ |
||||
|
__LINE__, \ |
||||
|
__VA_ARGS__) |
||||
|
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
#define LFS_EMUBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
|
||||
|
// provide BENCH_START/BENCH_STOP macros
|
||||
|
void bench_start(void); |
||||
|
void bench_stop(void); |
||||
|
|
||||
|
#define BENCH_START() bench_start() |
||||
|
#define BENCH_STOP() bench_stop() |
||||
|
|
||||
|
|
||||
|
// note these are indirectly included in any generated files
|
||||
|
#include "bd/lfs_emubd.h" |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
// give source a chance to define feature macros
|
||||
|
#undef _FEATURES_H |
||||
|
#undef _STDIO_H |
||||
|
|
||||
|
|
||||
|
// generated bench configurations
|
||||
|
struct lfs_config; |
||||
|
|
||||
|
enum bench_flags { |
||||
|
BENCH_REENTRANT = 0x1, |
||||
|
}; |
||||
|
typedef uint8_t bench_flags_t; |
||||
|
|
||||
|
typedef struct bench_define { |
||||
|
intmax_t (*cb)(void *data); |
||||
|
void *data; |
||||
|
} bench_define_t; |
||||
|
|
||||
|
struct bench_case { |
||||
|
const char *name; |
||||
|
const char *path; |
||||
|
bench_flags_t flags; |
||||
|
size_t permutations; |
||||
|
|
||||
|
const bench_define_t *defines; |
||||
|
|
||||
|
bool (*filter)(void); |
||||
|
void (*run)(struct lfs_config *cfg); |
||||
|
}; |
||||
|
|
||||
|
struct bench_suite { |
||||
|
const char *name; |
||||
|
const char *path; |
||||
|
bench_flags_t flags; |
||||
|
|
||||
|
const char *const *define_names; |
||||
|
size_t define_count; |
||||
|
|
||||
|
const struct bench_case *cases; |
||||
|
size_t case_count; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// deterministic prng for pseudo-randomness in benches
|
||||
|
uint32_t bench_prng(uint32_t *state); |
||||
|
|
||||
|
#define BENCH_PRNG(state) bench_prng(state) |
||||
|
|
||||
|
|
||||
|
// access generated bench defines
|
||||
|
intmax_t bench_define(size_t define); |
||||
|
|
||||
|
#define BENCH_DEFINE(i) bench_define(i) |
||||
|
|
||||
|
// a few preconfigured defines that control how benches run
|
||||
|
|
||||
|
#define READ_SIZE_i 0 |
||||
|
#define PROG_SIZE_i 1 |
||||
|
#define ERASE_SIZE_i 2 |
||||
|
#define ERASE_COUNT_i 3 |
||||
|
#define BLOCK_SIZE_i 4 |
||||
|
#define BLOCK_COUNT_i 5 |
||||
|
#define CACHE_SIZE_i 6 |
||||
|
#define LOOKAHEAD_SIZE_i 7 |
||||
|
#define COMPACT_THRESH_i 8 |
||||
|
#define METADATA_MAX_i 9 |
||||
|
#define INLINE_MAX_i 10 |
||||
|
#define BLOCK_CYCLES_i 11 |
||||
|
#define ERASE_VALUE_i 12 |
||||
|
#define ERASE_CYCLES_i 13 |
||||
|
#define BADBLOCK_BEHAVIOR_i 14 |
||||
|
#define POWERLOSS_BEHAVIOR_i 15 |
||||
|
|
||||
|
#define READ_SIZE bench_define(READ_SIZE_i) |
||||
|
#define PROG_SIZE bench_define(PROG_SIZE_i) |
||||
|
#define ERASE_SIZE bench_define(ERASE_SIZE_i) |
||||
|
#define ERASE_COUNT bench_define(ERASE_COUNT_i) |
||||
|
#define BLOCK_SIZE bench_define(BLOCK_SIZE_i) |
||||
|
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i) |
||||
|
#define CACHE_SIZE bench_define(CACHE_SIZE_i) |
||||
|
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) |
||||
|
#define COMPACT_THRESH bench_define(COMPACT_THRESH_i) |
||||
|
#define METADATA_MAX bench_define(METADATA_MAX_i) |
||||
|
#define INLINE_MAX bench_define(INLINE_MAX_i) |
||||
|
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) |
||||
|
#define ERASE_VALUE bench_define(ERASE_VALUE_i) |
||||
|
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i) |
||||
|
#define BADBLOCK_BEHAVIOR bench_define(BADBLOCK_BEHAVIOR_i) |
||||
|
#define POWERLOSS_BEHAVIOR bench_define(POWERLOSS_BEHAVIOR_i) |
||||
|
|
||||
|
#define BENCH_IMPLICIT_DEFINES \ |
||||
|
BENCH_DEF(READ_SIZE, PROG_SIZE) \ |
||||
|
BENCH_DEF(PROG_SIZE, ERASE_SIZE) \ |
||||
|
BENCH_DEF(ERASE_SIZE, 0) \ |
||||
|
BENCH_DEF(ERASE_COUNT, (1024*1024)/BLOCK_SIZE) \ |
||||
|
BENCH_DEF(BLOCK_SIZE, ERASE_SIZE) \ |
||||
|
BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\ |
||||
|
BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ |
||||
|
BENCH_DEF(LOOKAHEAD_SIZE, 16) \ |
||||
|
BENCH_DEF(COMPACT_THRESH, 0) \ |
||||
|
BENCH_DEF(METADATA_MAX, 0) \ |
||||
|
BENCH_DEF(INLINE_MAX, 0) \ |
||||
|
BENCH_DEF(BLOCK_CYCLES, -1) \ |
||||
|
BENCH_DEF(ERASE_VALUE, 0xff) \ |
||||
|
BENCH_DEF(ERASE_CYCLES, 0) \ |
||||
|
BENCH_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR) \ |
||||
|
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) |
||||
|
|
||||
|
#define BENCH_GEOMETRY_DEFINE_COUNT 4 |
||||
|
#define BENCH_IMPLICIT_DEFINE_COUNT 16 |
||||
|
|
||||
|
|
||||
|
#endif |
||||
File diff suppressed because it is too large
@ -0,0 +1,142 @@ |
|||||
|
/*
|
||||
|
* Runner for littlefs tests |
||||
|
* |
||||
|
* Copyright (c) 2022, The littlefs authors. |
||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||
|
*/ |
||||
|
#ifndef TEST_RUNNER_H |
||||
|
#define TEST_RUNNER_H |
||||
|
|
||||
|
|
||||
|
// override LFS_TRACE
|
||||
|
void test_trace(const char *fmt, ...); |
||||
|
|
||||
|
#define LFS_TRACE_(fmt, ...) \ |
||||
|
test_trace("%s:%d:trace: " fmt "%s\n", \ |
||||
|
__FILE__, \ |
||||
|
__LINE__, \ |
||||
|
__VA_ARGS__) |
||||
|
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
#define LFS_EMUBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |
||||
|
|
||||
|
|
||||
|
// note these are indirectly included in any generated files
|
||||
|
#include "bd/lfs_emubd.h" |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
// give source a chance to define feature macros
|
||||
|
#undef _FEATURES_H |
||||
|
#undef _STDIO_H |
||||
|
|
||||
|
|
||||
|
// generated test configurations
|
||||
|
struct lfs_config; |
||||
|
|
||||
|
enum test_flags { |
||||
|
TEST_REENTRANT = 0x1, |
||||
|
}; |
||||
|
typedef uint8_t test_flags_t; |
||||
|
|
||||
|
typedef struct test_define { |
||||
|
intmax_t (*cb)(void *data); |
||||
|
void *data; |
||||
|
} test_define_t; |
||||
|
|
||||
|
struct test_case { |
||||
|
const char *name; |
||||
|
const char *path; |
||||
|
test_flags_t flags; |
||||
|
size_t permutations; |
||||
|
|
||||
|
const test_define_t *defines; |
||||
|
|
||||
|
bool (*filter)(void); |
||||
|
void (*run)(struct lfs_config *cfg); |
||||
|
}; |
||||
|
|
||||
|
struct test_suite { |
||||
|
const char *name; |
||||
|
const char *path; |
||||
|
test_flags_t flags; |
||||
|
|
||||
|
const char *const *define_names; |
||||
|
size_t define_count; |
||||
|
|
||||
|
const struct test_case *cases; |
||||
|
size_t case_count; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// deterministic prng for pseudo-randomness in testes
|
||||
|
uint32_t test_prng(uint32_t *state); |
||||
|
|
||||
|
#define TEST_PRNG(state) test_prng(state) |
||||
|
|
||||
|
|
||||
|
// access generated test defines
|
||||
|
intmax_t test_define(size_t define); |
||||
|
|
||||
|
#define TEST_DEFINE(i) test_define(i) |
||||
|
|
||||
|
// a few preconfigured defines that control how tests run
|
||||
|
|
||||
|
#define READ_SIZE_i 0 |
||||
|
#define PROG_SIZE_i 1 |
||||
|
#define ERASE_SIZE_i 2 |
||||
|
#define ERASE_COUNT_i 3 |
||||
|
#define BLOCK_SIZE_i 4 |
||||
|
#define BLOCK_COUNT_i 5 |
||||
|
#define CACHE_SIZE_i 6 |
||||
|
#define LOOKAHEAD_SIZE_i 7 |
||||
|
#define COMPACT_THRESH_i 8 |
||||
|
#define METADATA_MAX_i 9 |
||||
|
#define INLINE_MAX_i 10 |
||||
|
#define BLOCK_CYCLES_i 11 |
||||
|
#define ERASE_VALUE_i 12 |
||||
|
#define ERASE_CYCLES_i 13 |
||||
|
#define BADBLOCK_BEHAVIOR_i 14 |
||||
|
#define POWERLOSS_BEHAVIOR_i 15 |
||||
|
#define DISK_VERSION_i 16 |
||||
|
|
||||
|
#define READ_SIZE TEST_DEFINE(READ_SIZE_i) |
||||
|
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) |
||||
|
#define ERASE_SIZE TEST_DEFINE(ERASE_SIZE_i) |
||||
|
#define ERASE_COUNT TEST_DEFINE(ERASE_COUNT_i) |
||||
|
#define BLOCK_SIZE TEST_DEFINE(BLOCK_SIZE_i) |
||||
|
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i) |
||||
|
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) |
||||
|
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) |
||||
|
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i) |
||||
|
#define METADATA_MAX TEST_DEFINE(METADATA_MAX_i) |
||||
|
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i) |
||||
|
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) |
||||
|
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) |
||||
|
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) |
||||
|
#define BADBLOCK_BEHAVIOR TEST_DEFINE(BADBLOCK_BEHAVIOR_i) |
||||
|
#define POWERLOSS_BEHAVIOR TEST_DEFINE(POWERLOSS_BEHAVIOR_i) |
||||
|
#define DISK_VERSION TEST_DEFINE(DISK_VERSION_i) |
||||
|
|
||||
|
#define TEST_IMPLICIT_DEFINES \ |
||||
|
TEST_DEF(READ_SIZE, PROG_SIZE) \ |
||||
|
TEST_DEF(PROG_SIZE, ERASE_SIZE) \ |
||||
|
TEST_DEF(ERASE_SIZE, 0) \ |
||||
|
TEST_DEF(ERASE_COUNT, (1024*1024)/ERASE_SIZE) \ |
||||
|
TEST_DEF(BLOCK_SIZE, ERASE_SIZE) \ |
||||
|
TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \ |
||||
|
TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ |
||||
|
TEST_DEF(LOOKAHEAD_SIZE, 16) \ |
||||
|
TEST_DEF(COMPACT_THRESH, 0) \ |
||||
|
TEST_DEF(METADATA_MAX, 0) \ |
||||
|
TEST_DEF(INLINE_MAX, 0) \ |
||||
|
TEST_DEF(BLOCK_CYCLES, -1) \ |
||||
|
TEST_DEF(ERASE_VALUE, 0xff) \ |
||||
|
TEST_DEF(ERASE_CYCLES, 0) \ |
||||
|
TEST_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR) \ |
||||
|
TEST_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) \ |
||||
|
TEST_DEF(DISK_VERSION, 0) |
||||
|
|
||||
|
#define TEST_GEOMETRY_DEFINE_COUNT 4 |
||||
|
#define TEST_IMPLICIT_DEFINE_COUNT 17 |
||||
|
|
||||
|
|
||||
|
#endif |
||||
Binary file not shown.
Loading…
Reference in new issue