@@ -1,215 +1,36 @@
-#################
-## Eclipse
-
-*.pydevproject
-.project
-.metadata
-bin/
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.classpath
-.settings/
-.loadpath
-# External tool builders
-.externalToolBuilders/
-# Locally stored "Eclipse launch configurations"
-*.launch
-# CDT-specific
-.cproject
-# PDT-specific
-.buildpath
-## Visual Studio
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-# User-specific files
-*.suo
-*.user
-*.sln.docstates
-# Build results
-[Dd]ebug/
-[Rr]elease/
-x64/
-build/
-[Bb]in/
-[Oo]bj/
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-*_i.c
-*_p.c
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.scc
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-*.cachefile
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-# Guidance Automation Toolkit
-*.gpState
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-# TeamCity is a build add-in
-_TeamCity*
-# DotCover is a Code Coverage Tool
-*.dotCover
-# NCrunch
-*.ncrunch*
-.*crunch*.local.xml
-# Installshield output folder
-[Ee]xpress/
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-# Click-Once directory
-publish/
-# Publish Web Output
-*.Publish.xml
-*.pubxml
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-#packages/
-# Windows Azure Build Output
-csx
-*.build.csdef
-# Windows Store app package directory
-AppPackages/
-# Others
-sql/
-*.Cache
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.[Pp]ublish.xml
-*.pfx
-*.publishsettings
-# RIA/Silverlight projects
-Generated_Code/
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-# SQL Server files
-App_Data/*.mdf
-App_Data/*.ldf
-#############
-## Windows detritus
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
-# Folder config file
-Desktop.ini
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-# Mac crap
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+# =========================
+# Operating System Files
+# OSX
.DS_Store
+.AppleDouble
+.LSOverride
+# Icon must ends with two \r.
+Icon
-## Python
-*.py[co]
-# Packages
-*.egg
-*.egg-info
-dist/
-eggs/
-parts/
-var/
-sdist/
-develop-eggs/
-.installed.cfg
-# Installer logs
-pip-log.txt
-# Unit test / coverage reports
-.coverage
-.tox
-#Translations
-*.mo
+# Thumbnails
+._*
-#Mr Developer
-.mr.developer.cfg
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
@@ -1,8 +1,13 @@
-### Warning: This is SdFat Version 2.
+### Warning: Major Reformat of Source in 2.2.2
-Earlier releases of Version 1 are here:
+There are a huge number of changes in 2.2.2 since I decided to use clang-format
+to force Google style formatting.
-https://github.com/greiman/SdFat/releases
+I did this to avoid warnings from the static analysis programs Cppcheck and
+cpplint.
+clang-format is aggressive so it may actually cause code to fail. For example
+clang-format rearranges the order of includes according to the selected style.
UTF-8 encoded filenames are supported in v2.1.0 or later.
@@ -1,4 +1,4 @@
-# Doxyfile 1.9.2
+# Doxyfile 1.9.6
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
@@ -60,16 +70,28 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY = .
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+CREATE_SUBDIRS_LEVEL = 8
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@@ -452,7 +474,7 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
-# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
@@ -546,7 +568,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
@@ -577,14 +600,15 @@ INTERNAL_DOCS = NO
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
-# are not case sensitive the option should be be set to NO to properly deal with
+# are not case sensitive the option should be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
-# The default value is: system dependent.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
CASE_SENSE_NAMES = NO
@@ -836,6 +860,14 @@ WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = YES
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+WARN_IF_UNDOC_ENUM_VAL = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
@@ -851,13 +883,27 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+WARN_LINE_FORMAT = "at line $line of file $file"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
-# error (stderr).
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
WARN_LOGFILE =
@@ -887,10 +933,21 @@ INPUT = ../src \
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+INPUT_FILE_ENCODING =
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@@ -981,7 +1038,7 @@ EXCLUDE_PATTERNS =
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
+# ANamespace::AClass, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
@@ -1029,6 +1086,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@@ -1070,6 +1132,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+FORTRAN_COMMENT_AFTER = 72
# Configuration options related to source browsing
@@ -1207,10 +1278,11 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = NO
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@@ -1289,7 +1361,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -1304,6 +1381,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+HTML_COLORSTYLE = AUTO_LIGHT
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
@@ -1398,6 +1488,13 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+DOCSET_FEEDURL =
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@@ -1602,7 +1699,7 @@ GENERATE_TREEVIEW = NO
# area (value NO) or if it should extend to the full height of the window (value
# YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the
-# project logo, title, and description. If either GENERATOR_TREEVIEW or
+# project logo, title, and description. If either GENERATE_TREEVIEW or
# DISABLE_INDEX is set to NO, this option has no effect.
@@ -1633,6 +1730,13 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+OBFUSCATE_EMAILS = YES
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
@@ -1653,17 +1757,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
@@ -2258,7 +2351,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
-# preprocessor.
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@@ -2354,15 +2448,6 @@ EXTERNAL_PAGES = YES
# Configuration options related to the dot tool
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-CLASS_DIAGRAMS = YES
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2395,35 +2480,50 @@ HAVE_DOT = YES
DOT_NUM_THREADS = 0
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTNAME = Helvetica
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
-DOT_FONTSIZE = 10
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
DOT_FONTPATH =
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
@@ -2437,7 +2537,8 @@ CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
@@ -2552,6 +2653,13 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+DIR_GRAPH_MAX_DEPTH = 1
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
@@ -2605,10 +2713,10 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
PLANTUML_JAR_PATH =
@@ -2646,18 +2754,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 1000
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-DOT_TRANSPARENT = YES
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
@@ -2670,6 +2766,8 @@ DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
@@ -3,7 +3,8 @@
const size_t BLOCK_SIZE = 64;
//------------------------------------------------------------------------------
// First block of file.
-const size_t PIN_NUM_DIM = BLOCK_SIZE - 3*sizeof(uint32_t) - 2*sizeof(uint8_t);
+const size_t PIN_NUM_DIM =
+ BLOCK_SIZE - 3 * sizeof(uint32_t) - 2 * sizeof(uint8_t);
struct metadata_t {
uint32_t adcFrequency; // ADC clock frequency
uint32_t cpuFrequency; // CPU clock frequency
@@ -14,15 +15,16 @@ struct metadata_t {
};
// Data block for 8-bit ADC mode.
-const size_t DATA_DIM8 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint8_t);
+const size_t DATA_DIM8 = (BLOCK_SIZE - 2 * sizeof(uint16_t)) / sizeof(uint8_t);
struct block8_t {
uint16_t count; // count of data values
uint16_t overrun; // count of overruns since last block
- uint8_t data[DATA_DIM8];
+ uint8_t data[DATA_DIM8];
// Data block for 10-bit ADC mode.
-const size_t DATA_DIM16 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint16_t);
+const size_t DATA_DIM16 =
+ (BLOCK_SIZE - 2 * sizeof(uint16_t)) / sizeof(uint16_t);
struct block16_t {
unsigned short count; // count of data values
unsigned short overrun; // count of overruns since last block
@@ -20,10 +20,11 @@
*/
#ifdef __AVR__
#include <SPI.h>
-#include "SdFat.h"
+#include "AvrAdcLogger.h"
#include "BufferedPrint.h"
#include "FreeStack.h"
-#include "AvrAdcLogger.h"
+#include "SdFat.h"
// Save SRAM if 328.
#ifdef __AVR_ATmega328P__
@@ -73,7 +74,7 @@ const float SAMPLE_RATE = 5000; // Must be 0.25 or greater.
// constant instead of being calculated from SAMPLE_RATE. SAMPLE_RATE is not
// used in the code below. For example, setting SAMPLE_INTERVAL = 2.0e-4
// will result in a 200 microsecond sample interval.
-const float SAMPLE_INTERVAL = 1.0/SAMPLE_RATE;
+const float SAMPLE_INTERVAL = 1.0 / SAMPLE_RATE;
// Setting ROUND_SAMPLE_INTERVAL non-zero will cause the sample interval to
// be rounded to a a multiple of the ADC clock period and will reduce sample
@@ -109,11 +110,11 @@ const size_t NAME_DIM = 40;
#elif RAMEND < 0X10FF
const size_t FIFO_SIZE_BYTES = 512;
#elif RAMEND < 0X20FF
-const size_t FIFO_SIZE_BYTES = 4*512;
+const size_t FIFO_SIZE_BYTES = 4 * 512;
#elif RAMEND < 0X40FF
-const size_t FIFO_SIZE_BYTES = 12*512;
-#else // RAMEND
-const size_t FIFO_SIZE_BYTES = 16*512;
+const size_t FIFO_SIZE_BYTES = 12 * 512;
+#else // RAMEND
+const size_t FIFO_SIZE_BYTES = 16 * 512;
#endif // RAMEND
// ADC clock rate.
@@ -136,7 +137,7 @@ const size_t FIFO_SIZE_BYTES = 16*512;
#define TMP_FILE_NAME "tmp_adc.bin"
// Number of analog pins to log.
-const uint8_t PIN_COUNT = sizeof(PIN_LIST)/sizeof(PIN_LIST[0]);
+const uint8_t PIN_COUNT = sizeof(PIN_LIST) / sizeof(PIN_LIST[0]);
// Minimum ADC clock cycles per sample interval
const uint16_t MIN_ADC_CYCLES = 15;
@@ -181,19 +182,19 @@ file_t csvFile;
char binName[] = LOG_FILE_NAME;
#if RECORD_EIGHT_BITS
-const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM8/PIN_COUNT);
+const size_t BLOCK_MAX_COUNT = PIN_COUNT * (DATA_DIM8 / PIN_COUNT);
typedef block8_t block_t;
-#else // RECORD_EIGHT_BITS
-const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM16/PIN_COUNT);
+#else // RECORD_EIGHT_BITS
+const size_t BLOCK_MAX_COUNT = PIN_COUNT * (DATA_DIM16 / PIN_COUNT);
typedef block16_t block_t;
-#endif // RECORD_EIGHT_BITS
+#endif // RECORD_EIGHT_BITS
// Size of FIFO in blocks.
-size_t const FIFO_DIM = FIFO_SIZE_BYTES/sizeof(block_t);
+size_t const FIFO_DIM = FIFO_SIZE_BYTES / sizeof(block_t);
block_t* fifoData;
-volatile size_t fifoCount = 0; // volatile - shared, ISR and background.
-size_t fifoHead = 0; // Only accessed by ISR during logging.
-size_t fifoTail = 0; // Only accessed by writer during logging.
+volatile size_t fifoCount = 0; // volatile - shared, ISR and background.
+size_t fifoHead = 0; // Only accessed by ISR during logging.
+size_t fifoTail = 0; // Only accessed by writer during logging.
//==============================================================================
// Interrupt Service Routines
@@ -220,7 +221,7 @@ ISR(ADC_vect) {
// Read ADC data.
uint8_t d = ADCH;
// This will access ADCL first.
uint16_t d = ADC;
#endif // RECORD_EIGHT_BITS
@@ -246,7 +247,7 @@ ISR(ADC_vect) {
if (adcindex == 0) {
timerFlag = false;
}
- adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
+ adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
} else {
@@ -278,7 +279,7 @@ ISR(TIMER1_COMPB_vect) {
// Error messages stored in flash.
-#define error(msg) (Serial.println(F(msg)),errorHalt())
+#define error(msg) (Serial.println(F(msg)), errorHalt())
#define assert(e) ((e) ? (void)0 : error("assert: " #e))
//
@@ -337,12 +338,13 @@ void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
#error unexpected ADC prescaler bits
#endif
-inline bool adcActive() {return (1 << ADIE) & ADCSRA;}
+inline bool adcActive() { return (1 << ADIE) & ADCSRA; }
// initialize ADC and timer1
void adcInit(metadata_t* meta) {
uint8_t adps; // prescaler bits for ADCSRA
- uint32_t ticks = F_CPU*SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.
+ uint32_t ticks =
+ F_CPU * SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.
if (ADC_REF & ~((1 << REFS0) | (1 << REFS1))) {
error("Invalid ADC reference");
@@ -352,9 +354,9 @@ void adcInit(metadata_t* meta) {
error("Invalid ADC prescaler");
adps = ADC_PRESCALER;
-#else // ADC_PRESCALER
+#else // ADC_PRESCALER
// Allow extra cpu cycles to change ADC settings if more than one pin.
- int32_t adcCycles = (ticks - ISR_TIMER0)/PIN_COUNT - ISR_SETUP_ADC;
+ int32_t adcCycles = (ticks - ISR_TIMER0) / PIN_COUNT - ISR_SETUP_ADC;
for (adps = 7; adps > 0; adps--) {
if (adcCycles >= (MIN_ADC_CYCLES << adps)) {
@@ -411,19 +413,19 @@ void adcInit(metadata_t* meta) {
// no prescale, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
tshift = 0;
- } else if (ticks < 0X10000*8) {
+ } else if (ticks < 0X10000 * 8) {
// prescale 8, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
tshift = 3;
- } else if (ticks < 0X10000*64) {
+ } else if (ticks < 0X10000 * 64) {
// prescale 64, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10);
tshift = 6;
- } else if (ticks < 0X10000*256) {
+ } else if (ticks < 0X10000 * 256) {
// prescale 256, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);
tshift = 8;
- } else if (ticks < 0X10000*1024) {
+ } else if (ticks < 0X10000 * 1024) {
// prescale 1024, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
tshift = 10;
@@ -443,7 +445,7 @@ void adcInit(metadata_t* meta) {
// Sample interval in CPU clock ticks.
meta->sampleInterval = ticks;
meta->cpuFrequency = F_CPU;
- float sampleRate = (float)meta->cpuFrequency/meta->sampleInterval;
+ float sampleRate = (float)meta->cpuFrequency / meta->sampleInterval;
Serial.print(F("Sample pins:"));
for (uint8_t i = 0; i < meta->pinCount; i++) {
Serial.print(' ');
@@ -453,11 +455,11 @@ void adcInit(metadata_t* meta) {
Serial.print(F("ADC bits: "));
Serial.println(meta->recordEightBits ? 8 : 10);
Serial.print(F("ADC clock kHz: "));
- Serial.println(meta->adcFrequency/1000);
+ Serial.println(meta->adcFrequency / 1000);
Serial.print(F("Sample Rate: "));
Serial.println(sampleRate);
Serial.print(F("Sample interval usec: "));
- Serial.println(1000000.0/sampleRate);
+ Serial.println(1000000.0 / sampleRate);
// enable ADC and timer1 interrupts
@@ -509,7 +511,7 @@ void binaryToCsv() {
if (nb < 0) {
error("read binFile failed");
- size_t nd = nb/sizeof(block_t);
+ size_t nd = nb / sizeof(block_t);
if (nd < 1) {
break;
@@ -520,7 +522,8 @@ void binaryToCsv() {
error("Invalid pinCount");
bp.print(F("Interval,"));
- float intervalMicros = 1.0e6*pm->sampleInterval/(float)pm->cpuFrequency;
+ float intervalMicros =
+ 1.0e6 * pm->sampleInterval / (float)pm->cpuFrequency;
bp.print(intervalMicros, 4);
bp.println(F(",usec"));
for (uint8_t i = 0; i < PIN_COUNT; i++) {
@@ -542,14 +545,15 @@ void binaryToCsv() {
for (size_t j = 0; j < pd->count; j += PIN_COUNT) {
for (size_t i = 0; i < PIN_COUNT; i++) {
- if (!bp.printField(pd->data[i + j], i == (PIN_COUNT-1) ? '\n' : ',')) {
+ if (!bp.printField(pd->data[i + j],
+ i == (PIN_COUNT - 1) ? '\n' : ',')) {
error("printField failed");
if ((millis() - tPct) > 1000) {
- uint8_t pct = binFile.curPosition()/(binFile.fileSize()/100);
+ uint8_t pct = binFile.curPosition() / (binFile.fileSize() / 100);
if (pct != lastPct) {
tPct = millis();
lastPct = pct;
@@ -562,7 +566,7 @@ void binaryToCsv() {
error("close csvFile failed");
Serial.print(F("Done: "));
- Serial.print(0.001*(millis() - t0));
+ Serial.print(0.001 * (millis() - t0));
Serial.println(F(" Seconds"));
@@ -620,7 +624,7 @@ bool createCsvFile() {
error("no dot in binName");
strcpy(dot + 1, "csv");
- if (!csvFile.open(csvName, O_WRONLY|O_CREAT|O_TRUNC)) {
+ if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
Serial.print(F("Writing: "));
@@ -633,7 +637,7 @@ bool createCsvFile() {
void logData() {
uint32_t t0;
uint32_t t1;
- uint32_t overruns =0;
+ uint32_t overruns = 0;
uint32_t count = 0;
uint32_t maxLatencyUsec = 0;
size_t maxFifoUse = 0;
@@ -677,7 +681,7 @@ void logData() {
if (m > maxLatencyUsec) {
maxLatencyUsec = m;
- if (tmpFifoCount >maxFifoUse) {
+ if (tmpFifoCount > maxFifoUse) {
maxFifoUse = tmpFifoCount;
count += pBlock->count;
@@ -712,7 +716,7 @@ void logData() {
isrStop = true;
if (fifoCount == 0 && !adcActive()) {
- break;
+ break;
Serial.println();
@@ -727,9 +731,9 @@ void logData() {
Serial.print(F("Max write latency usec: "));
Serial.println(maxLatencyUsec);
Serial.print(F("Record time sec: "));
- Serial.println(0.001*(t1 - t0), 3);
+ Serial.println(0.001 * (t1 - t0), 3);
Serial.print(F("Sample count: "));
- Serial.println(count/PIN_COUNT);
+ Serial.println(count / PIN_COUNT);
Serial.print(F("Overruns: "));
Serial.println(overruns);
Serial.print(F("FIFO_DIM: "));
@@ -768,13 +772,13 @@ void printData() {
return;
binFile.rewind();
- if (binFile.read(&buf , sizeof(buf)) != sizeof(buf)) {
+ if (binFile.read(&buf, sizeof(buf)) != sizeof(buf)) {
error("Read metadata failed");
Serial.println(F("Type any character to stop"));
delay(1000);
while (!Serial.available() &&
- binFile.read(&buf , sizeof(buf)) == sizeof(buf)) {
+ binFile.read(&buf, sizeof(buf)) == sizeof(buf)) {
if (buf.count == 0) {
@@ -784,7 +788,7 @@ void printData() {
for (size_t i = 0; i < buf.count; i++) {
Serial.print(buf.data[i], DEC);
- if ((i+1)%PIN_COUNT) {
+ if ((i + 1) % PIN_COUNT) {
Serial.print(',');
@@ -796,7 +800,7 @@ void printData() {
bool serialReadLine(char* str, size_t size) {
size_t n = 0;
- while(!Serial.available()) {
+ while (!Serial.available()) {
while (true) {
int c = Serial.read();
@@ -807,7 +811,8 @@ bool serialReadLine(char* str, size_t size) {
return false;
uint32_t m = millis();
- while (!Serial.available() && (millis() - m) < 100){}
+ while (!Serial.available() && (millis() - m) < 100) {
+ }
if (!Serial.available()) break;
str[n] = 0;
@@ -819,9 +824,11 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
Serial.begin(9600);
- while(!Serial) {}
+ while (!Serial) {
Serial.println(F("Type any character to begin."));
- while(!Serial.available()) {}
FillStack();
@@ -829,9 +836,9 @@ void setup(void) {
analogRead(PIN_LIST[0]);
#if !ENABLE_DEDICATED_SPI
- Serial.println(F(
- "\nFor best performance edit SdFatConfig.h\n"
- "and set ENABLE_DEDICATED_SPI nonzero"));
+ Serial.println(
+ F("\nFor best performance edit SdFatConfig.h\n"
+ "and set ENABLE_DEDICATED_SPI nonzero"));
#endif // !ENABLE_DEDICATED_SPI
// Initialize SD.
if (!sd.begin(SD_CONFIG)) {
@@ -865,7 +872,7 @@ void loop(void) {
Serial.println(F("p - print data to Serial"));
Serial.println(F("r - record ADC data"));
yield();
char c = tolower(Serial.read());
@@ -28,11 +28,12 @@ File myFile;
void setup() {
- while (!Serial) {}
#if USE_SD_H
Serial.println(F("Using SD.h. Set USE_SD_H zero to use SdFat.h."));
-#else // USE_SD_H
+#else // USE_SD_H
Serial.println(F("Using SdFat.h. Set USE_SD_H nonzero to use SD.h."));
#endif // USE_SD_H
Serial.println(F("\nType any character to begin."));
@@ -1,8 +1,8 @@
// Test and benchmark of the fast bufferedPrint class.
// Mainly for AVR but may improve print performance with other CPUs.
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
@@ -19,7 +19,7 @@
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
-#else // SDCARD_SS_PIN
+#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN
@@ -30,7 +30,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
-#elif ENABLE_DEDICATED_SPI
+#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
@@ -71,49 +71,48 @@ void benchmark() {
bp.begin(&file);
uint32_t t = millis();
- switch(test) {
- case 0:
- Serial.println(F("Test of println(uint16_t)"));
- for (uint16_t i = 0; i < N_PRINT; i++) {
- file.println(i);
- }
- case 1:
- Serial.println(F("Test of printField(uint16_t, char)"));
- bp.printField(i, '\n');
+ switch (test) {
+ case 0:
+ Serial.println(F("Test of println(uint16_t)"));
+ for (uint16_t i = 0; i < N_PRINT; i++) {
+ file.println(i);
- case 2:
- Serial.println(F("Test of println(uint32_t)"));
- file.println(12345678UL + i);
+ case 1:
+ Serial.println(F("Test of printField(uint16_t, char)"));
+ bp.printField(i, '\n');
- case 3:
- Serial.println(F("Test of printField(uint32_t, char)"));
- bp.printField(12345678UL + i, '\n');
+ case 2:
+ Serial.println(F("Test of println(uint32_t)"));
+ file.println(12345678UL + i);
- case 4:
- Serial.println(F("Test of println(double)"));
- file.println((double)0.01*i);
+ case 3:
+ Serial.println(F("Test of printField(uint32_t, char)"));
+ bp.printField(12345678UL + i, '\n');
- case 5:
- Serial.println(F("Test of printField(double, char)"));
- bp.printField((double)0.01*i, '\n');
+ case 4:
+ Serial.println(F("Test of println(double)"));
+ file.println((double)0.01 * i);
+ case 5:
+ Serial.println(F("Test of printField(double, char)"));
+ bp.printField((double)0.01 * i, '\n');
if (test & 1) {
bp.sync();
@@ -125,13 +124,13 @@ void benchmark() {
file.close();
t = millis() - t;
Serial.print(F("Time "));
- Serial.print(0.001*t, 3);
+ Serial.print(0.001 * t, 3);
Serial.println(F(" sec"));
Serial.print(F("File size "));
- Serial.print(0.001*s);
+ Serial.print(0.001 * s);
Serial.println(F(" KB"));
Serial.print(F("Write "));
- Serial.print(s/t);
+ Serial.print(s / t);
Serial.println(F(" KB/sec"));
@@ -139,23 +138,23 @@ void benchmark() {
void testMemberFunctions() {
BufferedPrint<Print, 32> bp(&Serial);
- char c = 'c'; // char
+ char c = 'c'; // char
//#define BASIC_TYPES
#ifdef BASIC_TYPES
- signed char sc = -1; // signed 8-bit
- unsigned char uc = 1; // unsiged 8-bit
- signed short ss = -2; // signed 16-bit
- unsigned short us = 2; // unsigned 16-bit
- signed long sl = -4; // signed 32-bit
- unsigned long ul = 4; // unsigned 32-bit
-#else // BASIC_TYPES
- int8_t sc = -1; // signed 8-bit
- uint8_t uc = 1; // unsiged 8-bit
- int16_t ss = -2; // signed 16-bit
- uint16_t us = 2; // unsigned 16-bit
- int32_t sl = -4; // signed 32-bit
- uint32_t ul = 4; // unsigned 32-bit
-#endif // BASIC_TYPES
+ signed char sc = -1; // signed 8-bit
+ unsigned char uc = 1; // unsiged 8-bit
+ signed short ss = -2; // signed 16-bit
+ unsigned short us = 2; // unsigned 16-bit
+ signed long sl = -4; // signed 32-bit
+ unsigned long ul = 4; // unsigned 32-bit
+#else // BASIC_TYPES
+ int8_t sc = -1; // signed 8-bit
+ uint8_t uc = 1; // unsiged 8-bit
+ int16_t ss = -2; // signed 16-bit
+ uint16_t us = 2; // unsigned 16-bit
+ int32_t sl = -4; // signed 32-bit
+ uint32_t ul = 4; // unsigned 32-bit
+#endif // BASIC_TYPES
float f = -1.234;
double d = -5.678;
bp.println();
@@ -216,9 +215,11 @@ void testMemberFunctions() {
Serial.println("Type any character to begin.");
sd.initErrorHalt(&Serial);
@@ -226,10 +227,10 @@ void setup() {
Serial.println(F("Test member funcions:"));
testMemberFunctions();
- Serial.println(F("Benchmark performance for uint16_t, uint32_t, and double:"));
+ F("Benchmark performance for uint16_t, uint32_t, and double:"));
benchmark();
Serial.println("Done");
-void loop() {
-}
+void loop() {}
@@ -78,9 +78,8 @@ void setup() {
- if (sd.exists("Folder1")
- || sd.exists("Folder1/file1.txt")
- || sd.exists("Folder1/File2.txt")) {
+ if (sd.exists("Folder1") || sd.exists("Folder1/file1.txt") ||
+ sd.exists("Folder1/File2.txt")) {
error("Please remove existing Folder1, file1.txt, and File2.txt");
@@ -3,9 +3,9 @@
// The maximum data rate will depend on the quality of your SD,
// the size of the FIFO, and using dedicated SPI.
-#include "FreeStack.h"
#include "ExFatLogger.h"
+#include "FreeStack.h"
// This example was designed for exFAT but will support FAT16/FAT32.
// Note: Uno will not support SD_FAT_TYPE = 3.
@@ -45,7 +45,7 @@ const uint32_t LOG_INTERVAL_USEC = 2000;
@@ -71,7 +71,7 @@ const uint32_t PREALLOCATE_SIZE_MiB = 1024UL;
@@ -127,11 +127,11 @@ void printRecord(Print* pr, data_t* data) {
-const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
+const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
// Max length of file name including zero byte.
#define FILE_NAME_DIM 40
// Max number of records to buffer while SD is busy.
-const size_t FIFO_DIM = 512*FIFO_SIZE_SECTORS/sizeof(data_t);
+const size_t FIFO_DIM = 512 * FIFO_SIZE_SECTORS / sizeof(data_t);
#if SD_FAT_TYPE == 0
typedef SdFat sd_t;
@@ -191,22 +191,22 @@ void binaryToCsv() {
data_t binData[FIFO_DIM];
if (!binFile.seekSet(512)) {
- error("binFile.seek failed");
+ error("binFile.seek failed");
uint32_t tPct = millis();
printRecord(&csvFile, nullptr);
while (!Serial.available() && binFile.available()) {
int nb = binFile.read(binData, sizeof(binData));
- if (nb <= 0 ) {
+ if (nb <= 0) {
- size_t nr = nb/sizeof(data_t);
+ size_t nr = nb / sizeof(data_t);
for (size_t i = 0; i < nr; i++) {
printRecord(&csvFile, &binData[i]);
@@ -221,7 +221,7 @@ void binaryToCsv() {
csvFile.close();
@@ -302,7 +302,7 @@ void logData() {
uint16_t overrun = 0;
uint16_t maxOverrun = 0;
uint32_t totalOverrun = 0;
- uint32_t fifoBuf[128*FIFO_SIZE_SECTORS];
+ uint32_t fifoBuf[128 * FIFO_SIZE_SECTORS];
data_t* fifoData = (data_t*)fifoBuf;
// Write dummy sector to start multi-block write.
@@ -315,7 +315,8 @@ void logData() {
// Wait until SD is not busy.
- while (sd.card()->isBusy()) {}
+ while (sd.card()->isBusy()) {
// Start time for log file.
@@ -370,9 +371,9 @@ void logData() {
if (!sd.card()->isBusy()) {
size_t nw = fifoHead > fifoTail ? fifoCount : FIFO_DIM - fifoTail;
// Limit write time by not writing more than 512 bytes.
- const size_t MAX_WRITE = 512/sizeof(data_t);
+ const size_t MAX_WRITE = 512 / sizeof(data_t);
if (nw > MAX_WRITE) nw = MAX_WRITE;
- size_t nb = nw*sizeof(data_t);
+ size_t nb = nw * sizeof(data_t);
uint32_t usec = micros();
if (nb != binFile.write(fifoData + fifoTail, nb)) {
error("write binFile failed");
@@ -392,7 +393,7 @@ void logData() {
Serial.print(F("\nLog time: "));
- Serial.print(0.001*(millis() - m));
+ Serial.print(0.001 * (millis() - m));
binFile.truncate();
binFile.sync();
@@ -469,7 +470,7 @@ void printUnusedStack() {
@@ -481,7 +482,8 @@ bool serialReadLine(char* str, size_t size) {
@@ -525,9 +527,9 @@ void setup() {
Serial.print(FIFO_DIM);
@@ -567,7 +569,7 @@ void loop() {
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
@@ -14,7 +14,8 @@ File file;
#include "SdFat.h"
// Setting ENABLE_DEDICATED_SPI to zero saves over 200 more bytes.
#if ENABLE_DEDICATED_SPI
-#warning "Set ENABLE_DEDICATED_SPI zero in SdFat/src/SdFatConfig.h for minimum size"
+#warning \
+ "Set ENABLE_DEDICATED_SPI zero in SdFat/src/SdFatConfig.h for minimum size"
#endif // ENABLE_DEDICATED_SPI
// Insure FAT16/FAT32 only.
SdFat32 SD;
@@ -24,17 +25,19 @@ FatFile file;
void error(const char* msg) {
Serial.println(msg);
- while(true);
+ while (true) {
int n;
char buf[4];
Serial.println("Type any character to begin");
- while (!Serial.available()) {}
if (!SD.begin(CS_PIN)) error("SD.begin");
@@ -47,12 +50,11 @@ void setup() {
if (!file.openExistingSFN(SFN_PATH)) error("open");
while ((n = file.read(buf, sizeof(buf)))) {
- Serial.write(buf, n);
+ Serial.write(buf, n);
-// close() is only needed if you write to the file. For example, read
-// config data, modify the data, rewind the file and write the data.
-// file.close();
+ // close() is only needed if you write to the file. For example, read
+ // config data, modify the data, rewind the file and write the data.
+ // file.close();
@@ -18,7 +18,7 @@
@@ -29,7 +29,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -76,7 +76,7 @@ void setup() {
// Open root directory
- if (!dir.open("/")){
+ if (!dir.open("/")) {
error("dir.open failed");
// Open next file in root.
@@ -1,6 +1,7 @@
// Quick hardware test for SPI card access.
#include "sdios.h"
@@ -81,17 +82,17 @@ void setup() {
if (DISABLE_CHIP_SELECT < 0) {
cout << F(
- "\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
- "a second SPI device. For example, with the Ethernet\n"
- "shield, DISABLE_CHIP_SELECT should be set to 10\n"
- "to disable the Ethernet controller.\n");
+ "\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
+ "a second SPI device. For example, with the Ethernet\n"
+ "shield, DISABLE_CHIP_SELECT should be set to 10\n"
+ "to disable the Ethernet controller.\n");
- "\nSD chip select is the key hardware option.\n"
- "Common values are:\n"
- "Arduino Ethernet shield, pin 4\n"
- "Sparkfun SD shield, pin 8\n"
- "Adafruit SD shields and modules, pin 10\n");
+ "\nSD chip select is the key hardware option.\n"
+ "Common values are:\n"
+ "Arduino Ethernet shield, pin 4\n"
+ "Sparkfun SD shield, pin 8\n"
+ "Adafruit SD shields and modules, pin 10\n");
bool firstTry = true;
@@ -117,8 +118,8 @@ void loop() {
- "\nAssuming the SD is the only SPI device.\n"
- "Edit DISABLE_CHIP_SELECT to disable another device.\n");
+ "\nAssuming the SD is the only SPI device.\n"
+ "Edit DISABLE_CHIP_SELECT to disable another device.\n");
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
@@ -128,12 +129,12 @@ void loop() {
if (!sd.begin(chipSelect, SPI_SPEED)) {
if (sd.card()->errorCode()) {
- "\nSD initialization failed.\n"
- "Do not reformat the card!\n"
- "Is the card correctly inserted?\n"
- "Is chipSelect set to the correct value?\n"
- "Does another SPI device need to be disabled?\n"
- "Is there a wiring/soldering problem?\n");
+ "\nSD initialization failed.\n"
+ "Do not reformat the card!\n"
+ "Is the card correctly inserted?\n"
+ "Is chipSelect set to the correct value?\n"
+ "Does another SPI device need to be disabled?\n"
+ "Is there a wiring/soldering problem?\n");
cout << F("\nerrorCode: ") << hex << showbase;
cout << int(sd.card()->errorCode());
cout << F(", errorData: ") << int(sd.card()->errorData());
@@ -169,8 +170,8 @@ void loop() {
cout << F("Files found (date time size name):\n");
sd.ls(LS_R | LS_DATE | LS_SIZE);
- if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64)
- || (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
+ if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64) ||
+ (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
cout << F("\nThis card should be reformatted for best performance.\n");
cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
@@ -15,7 +15,7 @@
@@ -26,7 +26,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -127,10 +127,10 @@ void setup() {
error("open failed");
// Write test data.
- file.print(F(
- "abc,123,456,7.89\r\n"
- "def,-321,654,-9.87\r\n"
- "ghi,333,0xff,5.55"));
+ file.print(
+ F("abc,123,456,7.89\r\n"
+ "def,-321,654,-9.87\r\n"
+ "ghi,333,0xff,5.55"));
// Rewind file for read.
file.rewind();
@@ -140,7 +140,7 @@ void setup() {
if (n <= 0) {
error("fgets failed");
- if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
+ if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
error("line too long");
if (!parseLine(line)) {
@@ -152,5 +152,4 @@ void setup() {
Serial.println(F("Done"));
@@ -26,7 +26,7 @@
@@ -37,7 +37,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -59,7 +59,6 @@ FsFile file;
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
#if RTC_TYPE == 0
RTC_Millis rtc;
#elif RTC_TYPE == 1
@@ -108,12 +107,12 @@ void getLine(char* line, size_t size) {
t = millis() + 10;
while (!Serial.available()) {
- if (millis() > t){
+ if (millis() > t) {
- if (i >= (size - 1) || c == '\r' || c == '\n' ) {
+ if (i >= (size - 1) || c == '\r' || c == '\n') {
line[i++] = c;
@@ -134,11 +133,11 @@ void printField(Print* pr, char sep, uint8_t v) {
void printNow(Print* pr) {
DateTime now = rtc.now();
pr->print(now.year());
- printField(pr, '-',now.month());
- printField(pr, '-',now.day());
- printField(pr, ' ',now.hour());
- printField(pr, ':',now.minute());
- printField(pr, ':',now.second());
+ printField(pr, '-', now.month());
+ printField(pr, '-', now.day());
+ printField(pr, ' ', now.hour());
+ printField(pr, ':', now.minute());
+ printField(pr, ':', now.second());
bool setRtc() {
@@ -180,7 +179,7 @@ void setup() {
rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
-#else // RTC_TYPE
+#else // RTC_TYPE
if (!rtc.begin()) {
Serial.println(F("rtc.begin failed"));
@@ -201,7 +200,8 @@ void setup() {
clearSerialInput();
Serial.println(F("Type Y to set RTC, any other character to continue"));
if (Serial.read() != 'Y') break;
if (setRtc()) break;
@@ -232,5 +232,4 @@ void setup() {
@@ -2,7 +2,8 @@
Serial.println(F("Code,Symbol - failed operation"));
@@ -31,7 +31,7 @@ const int8_t DISABLE_CS_PIN = -1;
@@ -42,7 +42,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -52,14 +52,18 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
ArduinoOutStream cout(Serial);
uint32_t cardSectorCount = 0;
-uint8_t sectorBuffer[512];
+uint8_t sectorBuffer[512];
// SdCardFactory constructs and initializes the appropriate card.
SdCardFactory cardFactory;
// Pointer to generic SD card.
SdCard* m_card = nullptr;
-#define sdError(msg) {cout << F("error: ") << F(msg) << endl; sdErrorHalt();}
+#define sdError(msg) \
+ { \
+ cout << F("error: ") << F(msg) << endl; \
+ sdErrorHalt(); \
void sdErrorHalt() {
if (!m_card) {
@@ -73,7 +77,8 @@ void sdErrorHalt() {
cout << F(" = ") << int(m_card->errorCode()) << endl;
cout << F("SD errorData = ") << int(m_card->errorData()) << endl;
- while (true) {}
void clearSerialInput() {
@@ -102,7 +107,7 @@ void eraseCard() {
sdError("erase failed");
cout << '.';
- if ((n++)%64 == 63) {
+ if ((n++) % 64 == 63) {
cout << endl;
firstBlock += ERASE_SIZE;
@@ -123,9 +128,9 @@ void formatCard() {
FatFormatter fatFormatter;
// Format exFAT if larger than 32GB.
- bool rtn = cardSectorCount > 67108864 ?
- exFatFormatter.format(m_card, sectorBuffer, &Serial) :
- fatFormatter.format(m_card, sectorBuffer, &Serial);
+ bool rtn = cardSectorCount > 67108864
+ ? exFatFormatter.format(m_card, sectorBuffer, &Serial)
+ : fatFormatter.format(m_card, sectorBuffer, &Serial);
if (!rtn) {
sdErrorHalt();
@@ -136,8 +141,8 @@ void formatCard() {
void printConfig(SdSpiConfig config) {
if (DISABLE_CS_PIN < 0) {
- "Edit DISABLE_CS_PIN to disable an SPI device.\n");
+ "Edit DISABLE_CS_PIN to disable an SPI device.\n");
cout << int(DISABLE_CS_PIN) << endl;
@@ -169,19 +174,19 @@ void setup() {
- "\n"
- "This program can erase and/or format SD/SDHC/SDXC cards.\n"
- "Erase uses the card's fast flash erase command.\n"
- "Flash erase sets all data to 0X00 for most cards\n"
- "and 0XFF for a few vendor's cards.\n"
- "Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
- "Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
- "FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
- "Warning, all data on the card will be erased.\n"
- "Enter 'Y' to continue: ");
+ "\n"
+ "This program can erase and/or format SD/SDHC/SDXC cards.\n"
+ "Erase uses the card's fast flash erase command.\n"
+ "Flash erase sets all data to 0X00 for most cards\n"
+ "and 0XFF for a few vendor's cards.\n"
+ "Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
+ "Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
+ "FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
+ "Warning, all data on the card will be erased.\n"
+ "Enter 'Y' to continue: ");
@@ -207,9 +212,9 @@ void setup() {
- cout << F("\nCard size: ") << cardSectorCount*5.12e-7;
+ cout << F("\nCard size: ") << cardSectorCount * 5.12e-7;
cout << F(" GB (GB = 1E9 bytes)\n");
- cout << F("Card size: ") << cardSectorCount/2097152.0;
+ cout << F("Card size: ") << cardSectorCount / 2097152.0;
cout << F(" GiB (GiB = 2^30 bytes)\n");
cout << F("Card will be formated ");
@@ -221,13 +226,13 @@ void setup() {
cout << F("FAT16\n");
- "Options are:\n"
- "E - erase the card and skip formatting.\n"
- "F - erase and then format the card. (recommended)\n"
- "Q - quick format the card without erase.\n"
- "Enter option: ");
+ "Options are:\n"
+ "E - erase the card and skip formatting.\n"
+ "F - erase and then format the card. (recommended)\n"
+ "Q - quick format the card without erase.\n"
+ "Enter option: ");
@@ -245,5 +250,4 @@ void setup() {
formatCard();
@@ -20,7 +20,7 @@ const int8_t DISABLE_CS_PIN = -1;
@@ -99,7 +99,7 @@ void errorPrint() {
bool mbrDmp() {
MbrSector_t mbr;
bool valid = true;
- if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
+ if (!sd.card()->readSector(0, (uint8_t *)&mbr)) {
cout << F("\nread MBR failed.\n");
errorPrint();
@@ -114,11 +114,11 @@ bool mbrDmp() {
cout << int(ip) << ',' << uppercase << showbase << hex;
cout << int(pt->boot) << ',';
- for (int i = 0; i < 3; i++ ) {
+ for (int i = 0; i < 3; i++) {
cout << int(pt->beginCHS[i]) << ',';
cout << int(pt->type) << ',';
cout << int(pt->endCHS[i]) << ',';
cout << dec << getLe32(pt->relativeSectors) << ',';
@@ -141,18 +141,17 @@ void dmpVol() {
cout << F("sectorsPerCluster: ") << sd.sectorsPerCluster() << endl;
cout << F("fatStartSector: ") << sd.fatStartSector() << endl;
cout << F("dataStartSector: ") << sd.dataStartSector() << endl;
- cout << F("clusterCount: ") << sd.clusterCount() << endl;
+ cout << F("clusterCount: ") << sd.clusterCount() << endl;
cout << F("freeClusterCount: ");
if (freeClusterCount >= 0) {
cout << freeClusterCount << endl;
cout << F("failed\n");
- errorPrint();
+ errorPrint();
void printCardType() {
cout << F("\nCard type: ");
switch (sd.card()->type()) {
@@ -180,8 +179,8 @@ void printCardType() {
@@ -205,7 +204,6 @@ void setup() {
cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
printConfig(SD_CONFIG);
void loop() {
@@ -220,15 +218,14 @@ void loop() {
if (!sd.cardBegin(SD_CONFIG)) {
if (isSpi(SD_CONFIG)) {
- "Is SD_CS_PIN set to the correct value?\n"
- );
+ "Is SD_CS_PIN set to the correct value?\n"
+ "Does another SPI device need to be disabled?\n");
@@ -236,23 +233,21 @@ void loop() {
cout << F("init time: ") << dec << t << " ms" << endl;
- if (!sd.card()->readCID(&cid) ||
- !sd.card()->readCSD(&csd) ||
- !sd.card()->readOCR(&ocr) ||
- !sd.card()->readSCR(&scr)) {
+ if (!sd.card()->readCID(&cid) || !sd.card()->readCSD(&csd) ||
+ !sd.card()->readOCR(&ocr) || !sd.card()->readSCR(&scr)) {
cout << F("readInfo failed\n");
printCardType();
- cout << F("sdSpecVer: ") << 0.01*scr.sdSpecVer() << endl;
+ cout << F("sdSpecVer: ") << 0.01 * scr.sdSpecVer() << endl;
cout << F("HighSpeedMode: ");
- if (scr.sdSpecVer() &&
- sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) && (2 & cmd6Data[13])) {
+ if (scr.sdSpecVer() && sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) &&
+ (2 & cmd6Data[13])) {
cout << F("true\n");
cout << F("false\n");
cidDmp();
csdDmp();
cout << F("\nOCR: ") << uppercase << showbase;
@@ -16,7 +16,7 @@ const uint8_t SD_CS_PIN = 10;
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
const uint8_t SOFT_MOSI_PIN = 11;
-const uint8_t SOFT_SCK_PIN = 13;
+const uint8_t SOFT_SCK_PIN = 13;
// SdFat software SPI template
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
@@ -77,4 +77,4 @@ void setup() {
void loop() {}
#else // SPI_DRIVER_SELECT
#error SPI_DRIVER_SELECT must be two in SdFat/SdFatConfig.h
-#endif //SPI_DRIVER_SELECT
+#endif // SPI_DRIVER_SELECT
@@ -1,14 +1,20 @@
// Test of Teensy exFAT DMA ADC logger.
// This is mainly to test use of RingBuf in an ISR.
+// This example only supports pins on the first ADC.
+// it has only been tested on Teensy 3.6 and 4.1.
// You should modify it for serious use as a data logger.
+#include "ADC.h"
#include "DMAChannel.h"
#include "RingBuf.h"
+// Pin must be on first ADC.
+#define ADC_PIN A0
// 400 sector RingBuf - could be larger on Teensy 4.1.
-const size_t RING_BUF_SIZE = 400*512;
+const size_t RING_BUF_SIZE = 400 * 512;
// Preallocate 8GiB file.
const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;
@@ -16,15 +22,19 @@ const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;
// Use FIFO SDIO.
+ADC adc;
DMAChannel dma(true);
SdFs sd;
FsFile file;
-//------------------------------------------------------------------------------
// Ping-pong DMA buffer.
DMAMEM static uint16_t __attribute__((aligned(32))) dmaBuf[2][256];
-size_t dmaCount;
+// Count of DMA interrupts.
+volatile size_t dmaCount;
// RingBuf for 512 byte sectors.
RingBuf<FsFile, RING_BUF_SIZE> rb;
@@ -32,18 +42,26 @@ RingBuf<FsFile, RING_BUF_SIZE> rb;
// Shared between ISR and background.
volatile size_t maxBytesUsed;
+// Overrun error for write to RingBuf.
volatile bool overrun;
-//ISR.
+// ISR for DMA.
static void isr() {
- if (rb.bytesFreeIsr() >= 512 && !overrun) {
- rb.memcpyIn(dmaBuf[dmaCount & 1], 512);
- dmaCount++;
- if (rb.bytesUsed() > maxBytesUsed) {
- maxBytesUsed = rb.bytesUsed();
+ if (!overrun) {
+ // Clear cache for buffer filled by DMA to insure read from DMA memory.
+ arm_dcache_delete((void*)dmaBuf[dmaCount & 1], 512);
+ // Enable RingBuf functions to be called in ISR.
+ rb.beginISR();
+ if (rb.write(dmaBuf[dmaCount & 1], 512) == 512) {
+ dmaCount++;
+ if (rb.bytesUsed() > maxBytesUsed) {
+ maxBytesUsed = rb.bytesUsed();
+ } else {
+ overrun = true;
- } else {
- overrun = true;
+ // End use of RingBuf functions in ISR.
+ rb.endISR();
dma.clearComplete();
dma.clearInterrupt();
@@ -53,39 +71,7 @@ static void isr() {
#endif // defined(__IMXRT1062__)
-// Over-clocking will degrade quality - use only for stress testing.
-void overclock() {
-#if defined(__IMXRT1062__) // Teensy 4.0
- ADC1_CFG =
- // High Speed Configuration
- ADC_CFG_ADHSC |
- // Sample period 3 clocks
- ADC_CFG_ADSTS(0) |
- // Input clock
- ADC_CFG_ADIV(0) |
- // Not selected - Long Sample Time Configuration
- // ADC_CFG_ADLSMP |
- // 12-bit
- ADC_CFG_MODE(2) |
- // Asynchronous clock
- ADC_CFG_ADICLK(3);
-#else // defined(__IMXRT1062__)
- // Set 12 bit mode and max over-clock
- ADC0_CFG1 =
- // Clock divide select, 0=direct, 1=div2, 2=div4, 3=div8
- ADC_CFG1_ADIV(0) |
- // Sample time configuration, 0=Short, 1=Long
- // ADC_CFG1_ADLSMP |
- // Conversion mode, 0=8 bit, 1=12 bit, 2=10 bit, 3=16 bit
- ADC_CFG1_MODE(1) |
- // Input clock, 0=bus, 1=bus/2, 2=OSCERCLK, 3=async
- ADC_CFG1_ADICLK(0);
- ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(3);
-#endif // defined(__IMXRT1062__)
+#if defined(__IMXRT1062__) // Teensy 4.x
#define SOURCE_SADDR ADC1_R0
#define SOURCE_EVENT DMAMUX_SOURCE_ADC1
#else
@@ -93,54 +79,26 @@ void overclock() {
#define SOURCE_EVENT DMAMUX_SOURCE_ADC0
-// Should replace ADC stuff with calls to Teensy ADC library.
-// https://github.com/pedvide/ADC
static void init(uint8_t pin) {
- uint32_t adch;
- uint32_t i, sum = 0;
- // Actually, do many normal reads, to start with a nice DC level
- for (i=0; i < 1024; i++) {
- sum += analogRead(pin);
- // save channel
- adch = ADC1_HC0 & 0x1F;
- // Continuous conversion , DMA enable
- ADC1_GC = ADC_GC_ADCO | ADC_GC_DMAEN;
- // start conversion
- ADC1_HC0 = adch;
-#else // defined(__IMXRT1062__) // Teensy 4.0
- adch = ADC0_SC1A & 0x1F;
- // DMA enable
- ADC0_SC2 |= ADC_SC2_DMAEN;
- // Continuous conversion enable
- ADC0_SC3 = ADC_SC3_ADCO;
- // Start ADC
- ADC0_SC1A = adch;
- #endif // defined(__IMXRT1062__) // Teensy 4.0
- // set up a DMA channel to store the ADC data
- dma.attachInterrupt(isr);
- dma.begin();
- dma.source((volatile const signed short &)SOURCE_SADDR);
+ dma.begin();
+ dma.attachInterrupt(isr);
+ dma.source((volatile const signed short&)SOURCE_SADDR);
dma.destinationBuffer((volatile uint16_t*)dmaBuf, sizeof(dmaBuf));
dma.interruptAtHalf();
dma.interruptAtCompletion();
- dma.triggerAtHardwareEvent(SOURCE_EVENT);
- dma.enable();
+ dma.triggerAtHardwareEvent(SOURCE_EVENT);
+ dma.enable();
+ adc.adc0->enableDMA();
+ adc.adc0->startContinuous(pin);
void stopDma() {
- ADC1_GC = 0;
- ADC0_SC3 = 0;
+ adc.adc0->disableDMA();
dma.disable();
void printTest(Print* pr) {
- if (file.fileSize() < 1024*2) {
+ if (file.fileSize() < 1024 * 2) {
@@ -153,7 +111,8 @@ void printTest(Print* pr) {
for (size_t i = 0; i < 1024; i++) {
pr->print(i);
pr->print(',');
- rb.memcpyOut(&data, 2);
+ // Test read with: template <typename Type>bool read(Type* data).
+ rb.read(&data);
pr->println(data);
@@ -192,36 +151,42 @@ void runTest(uint8_t pin) {
stopDma();
- samplingTime = (micros() - samplingTime);
+ samplingTime = micros() - samplingTime;
+ if (!rb.sync()) {
+ Serial.println("sync() failed");
+ file.close();
+ return;
if (!file.truncate()) {
sd.errorHalt("truncate failed");
if (overrun) {
Serial.println("Overrun ERROR!!");
+ Serial.print("dmsCount ");
+ Serial.println(dmaCount);
Serial.print("RingBufSize ");
Serial.println(RING_BUF_SIZE);
Serial.print("maxBytesUsed ");
Serial.println(maxBytesUsed);
Serial.print("fileSize ");
- Serial.println((uint32_t)file.fileSize());
- Serial.print(0.000001*samplingTime);
+ file.printFileSize(&Serial);
+ Serial.println();
+ Serial.print(0.000001 * samplingTime);
Serial.println(" seconds");
- Serial.print(1.0*file.fileSize()/samplingTime, 3);
+ Serial.print(1.0 * file.fileSize() / samplingTime, 3);
Serial.println(" MB/sec\n");
printTest(&Serial);
void waitSerial(const char* msg) {
- uint32_t m = micros();
do {
- if (Serial.read() >= 0) {
- m = micros();
- } while (micros() - m < 10000);
+ delay(10);
+ } while (Serial.read() >= 0);
@@ -239,9 +204,11 @@ void loop() {
-//analogReadAveraging(1);
-//analogReadResolution(12);
-//overclock(); // 3 Msps on Teensy 3.6 - requires high quality card.
- runTest(A0);
+ // Try for max speed.
+ adc.adc0->setAveraging(1);
+ adc.adc0->setResolution(10);
+ adc.adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
+ adc.adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
+ runTest(ADC_PIN);
waitSerial("Type any character to run test again");
@@ -1,9 +1,10 @@
// Test of time-stamp callback with Teensy 3/4.
// The upload time will be used to set the RTC.
// You must arrange for syncing the RTC.
#include <TimeLib.h>
#define SD_FAT_TYPE 3
@@ -19,7 +20,7 @@
@@ -30,7 +31,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -55,7 +56,6 @@ FsFile file;
// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
// Return date using FS_DATE macro to format fields.
*date = FS_DATE(year(), month(), day());
@@ -66,10 +66,7 @@ void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
*ms10 = second() & 1 ? 100 : 0;
-time_t getTeensy3Time()
-{
- return Teensy3Clock.get();
+time_t getTeensy3Time() { return Teensy3Clock.get(); }
void printField(Print* pr, char sep, uint8_t v) {
if (sep) {
@@ -102,7 +99,7 @@ void setup() {
- if (timeStatus()!= timeSet) {
+ if (timeStatus() != timeSet) {
Serial.println("Unable to sync with the RTC");
@@ -135,5 +132,4 @@ void setup() {
@@ -7,7 +7,7 @@
@@ -20,7 +20,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
const size_t BUF_DIM = 32768;
// 8 MiB file.
-const uint32_t FILE_SIZE = 256UL*BUF_DIM;
+const uint32_t FILE_SIZE = 256UL * BUF_DIM;
SdFat sd;
@@ -72,13 +72,12 @@ void errorHalt(const char* msg) {
Serial.print(", ErrorData: 0X");
Serial.println(sd.sdErrorData(), HEX);
bool ready = false;
-bool sdBusy() {
- return ready ? sd.card()->isBusy() : false;
+bool sdBusy() { return ready ? sd.card()->isBusy() : false; }
// Replace "weak" system yield() function.
void yield() {
@@ -110,7 +109,7 @@ void runTest() {
Serial.println("\nsize,write,read");
Serial.println("bytes,KB/sec,KB/sec");
for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {
- uint32_t nRdWr = FILE_SIZE/nb;
+ uint32_t nRdWr = FILE_SIZE / nb;
if (!file.truncate(0)) {
errorHalt("truncate failed");
@@ -121,14 +120,14 @@ void runTest() {
for (uint32_t n = 0; n < nRdWr; n++) {
// Set start and end of buffer.
buf32[0] = n;
- buf32[nb/4 - 1] = n;
+ buf32[nb / 4 - 1] = n;
if (nb != file.write(buf, nb)) {
errorHalt("write failed");
t = micros() - t;
totalMicros += t;
- Serial.print(1000.0*FILE_SIZE/t);
+ Serial.print(1000.0 * FILE_SIZE / t);
t = micros();
@@ -138,13 +137,13 @@ void runTest() {
errorHalt("read failed");
// crude check of data.
- if (buf32[0] != n || buf32[nb/4 - 1] != n) {
+ if (buf32[0] != n || buf32[nb / 4 - 1] != n) {
errorHalt("data check");
- Serial.println(1000.0*FILE_SIZE/t);
+ Serial.println(1000.0 * FILE_SIZE / t);
Serial.print("\ntotalMicros ");
@@ -155,8 +154,8 @@ void runTest() {
Serial.println(yieldCalls);
Serial.print("yieldMaxUsec ");
Serial.println(yieldMaxUsec);
-// Serial.print("kHzSdClk ");
-// Serial.println(kHzSdClk());
+ // Serial.print("kHzSdClk ");
+ // Serial.println(kHzSdClk());
@@ -171,22 +170,22 @@ void loop() {
if (warn) {
warn = false;
Serial.println(
- "SD cards must be power cycled to leave\n"
- "SPI mode so do SDIO tests first.\n"
- "\nCycle power on the card if an error occurs.");
+ "SD cards must be power cycled to leave\n"
+ "SPI mode so do SDIO tests first.\n"
+ "\nCycle power on the card if an error occurs.");
- "\nType '1' for FIFO SDIO"
- "\n '2' for DMA SDIO"
- "\n '3' for Dedicated SPI"
- "\n '4' for Shared SPI");
+ "\nType '1' for FIFO SDIO"
+ "\n '2' for DMA SDIO"
+ "\n '3' for Dedicated SPI"
+ "\n '4' for Shared SPI");
char c = Serial.read();
- if (c =='1') {
+ if (c == '1') {
if (!sd.begin(SdioConfig(FIFO_SDIO))) {
errorHalt("begin failed");
@@ -202,7 +201,7 @@ void loop() {
Serial.println("\nDedicated SPI mode.");
-#else // ENABLE_DEDICATED_SPI
+#else // ENABLE_DEDICATED_SPI
Serial.println("ENABLE_DEDICATED_SPI must be non-zero.");
@@ -6,20 +6,20 @@
// Teensy 4.1. About 5 usec is required to write a sector when the
// controller is in write mode.
// Use Teensy SDIO
-#define SD_CONFIG SdioConfig(FIFO_SDIO)
+#define SD_CONFIG SdioConfig(FIFO_SDIO)
// Interval between points for 25 ksps.
#define LOG_INTERVAL_USEC 40
// Size to log 10 byte lines at 25 kHz for more than ten minutes.
-#define LOG_FILE_SIZE 10*25000*600 // 150,000,000 bytes.
+#define LOG_FILE_SIZE 10 * 25000 * 600 // 150,000,000 bytes.
// Space to hold more than 800 ms of data for 10 byte lines at 25 ksps.
-#define RING_BUF_CAPACITY 400*512
+#define RING_BUF_CAPACITY 400 * 512
#define LOG_FILENAME "SdioLogger.csv"
@@ -41,9 +41,9 @@ void logData() {
// File must be pre-allocated to avoid huge
// delays searching for free clusters.
if (!file.preAllocate(LOG_FILE_SIZE)) {
- Serial.println("preAllocate failed\n");
- file.close();
- return;
+ Serial.println("preAllocate failed\n");
// initialize the RingBuf.
rb.begin(&file);
@@ -88,7 +88,8 @@ void logData() {
// Wait until time to log data.
- while (micros() < logTime) {}
+ while (micros() < logTime) {
// Read ADC0 - about 17 usec on Teensy 4, Teensy 3.6 is faster.
uint16_t adc = analogRead(0);
@@ -134,7 +135,8 @@ void clearSerialInput() {
// Go faster or log more channels. ADC quality will suffer.
// analogReadAveraging(1);
@@ -142,7 +144,8 @@ void setup() {
Serial.println("Type any character to start");
- while (!Serial.available()) {};
logData();
@@ -18,7 +18,7 @@ const char* names[] = {u8"россиянин", u8"très élégant", u8"狗.txt",
@@ -91,8 +91,7 @@ void setup() {
#endif // REMOVE_UTF8_FILES
Serial.println("Done!");
#else // USE_UTF8_LONG_NAMES
#error USE_UTF8_LONG_NAMES must be non-zero in SdFat/src/SdFatCongfig.h
#endif // USE_UTF8_LONG_NAMES
@@ -1,7 +1,7 @@
// An example of an external SPI driver.
#include "SPI.h" // Only required if you use features in the SPI library.
#if SPI_DRIVER_SELECT == 3 // Must be set in SdFat/SdFatConfig.h
@@ -16,22 +16,16 @@
class MySpiClass : public SdSpiBaseClass {
public:
// Activate SPI hardware with correct speed and mode.
- void activate() {
- SPI.beginTransaction(m_spiSettings);
+ void activate() { SPI.beginTransaction(m_spiSettings); }
// Initialize the SPI bus.
void begin(SdSpiConfig config) {
(void)config;
SPI.begin();
// Deactivate SPI hardware.
- void deactivate() {
- SPI.endTransaction();
+ void deactivate() { SPI.endTransaction(); }
// Receive a byte.
- uint8_t receive() {
- return SPI.transfer(0XFF);
+ uint8_t receive() { return SPI.transfer(0XFF); }
// Receive multiple bytes.
// Replace this function if your board has multiple byte receive.
uint8_t receive(uint8_t* buf, size_t count) {
@@ -41,9 +35,7 @@ class MySpiClass : public SdSpiBaseClass {
return 0;
// Send a byte.
- void send(uint8_t data) {
- SPI.transfer(data);
+ void send(uint8_t data) { SPI.transfer(data); }
// Send multiple bytes.
// Replace this function if your board has multiple byte send.
void send(const uint8_t* buf, size_t count) {
@@ -73,9 +65,11 @@ void setup() {
sd.ls(&Serial, LS_SIZE);
+ Serial.println("Done");
#error SPI_DRIVER_SELECT must be three in SdFat/SdFatConfig.h
#endif // SPI_DRIVER_SELECT
@@ -1,9 +1,9 @@
/*
* This program is a simple binary write/read benchmark.
@@ -58,10 +58,10 @@ const uint8_t READ_COUNT = 2;
// End of configuration constants.
// File size in bytes.
-const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;
+const uint32_t FILE_SIZE = 1000000UL * FILE_SIZE_MB;
// Insure 4-byte alignment.
-uint32_t buf32[(BUF_SIZE + 3)/4];
+uint32_t buf32[(BUF_SIZE + 3) / 4];
uint8_t* buf = (uint8_t*)buf32;
@@ -125,8 +125,8 @@ void setup() {
cout << F("\nUse a freshly formatted SD for best performance.\n");
if (!ENABLE_DEDICATED_SPI) {
- "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
- "SdFatConfig.h for best SPI performance.\n");
+ "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
+ "SdFatConfig.h for best SPI performance.\n");
// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
@@ -161,7 +161,7 @@ void loop() {
cout << F("Type is FAT") << int(sd.fatType()) << endl;
- cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
+ cout << F("Card size: ") << sd.card()->sectorCount() * 512E-9;
cout << F(" GB (GB = 1E9 bytes)") << endl;
@@ -176,17 +176,17 @@ void loop() {
for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
buf[i] = 'A' + (i % 26);
- buf[BUF_SIZE-2] = '\r';
+ buf[BUF_SIZE - 2] = '\r';
- buf[BUF_SIZE-1] = '\n';
+ buf[BUF_SIZE - 1] = '\n';
cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl;
cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
cout << F("Starting write test, please wait.") << endl << endl;
// do write test
- uint32_t n = FILE_SIZE/BUF_SIZE;
- cout <<F("write speed and latency") << endl;
+ uint32_t n = FILE_SIZE / BUF_SIZE;
+ cout << F("write speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
@@ -223,11 +223,11 @@ void loop() {
file.sync();
s = file.fileSize();
- cout << s/t <<',' << maxLatency << ',' << minLatency;
- cout << ',' << totalLatency/n << endl;
+ cout << s / t << ',' << maxLatency << ',' << minLatency;
+ cout << ',' << totalLatency / n << endl;
cout << endl << F("Starting read test, please wait.") << endl;
- cout << endl <<F("read speed and latency") << endl;
+ cout << endl << F("read speed and latency") << endl;
@@ -240,7 +240,7 @@ void loop() {
skipLatency = SKIP_FIRST_LATENCY;
t = millis();
for (uint32_t i = 0; i < n; i++) {
- buf[BUF_SIZE-1] = 0;
+ buf[BUF_SIZE - 1] = 0;
uint32_t m = micros();
int32_t nr = file.read(buf, BUF_SIZE);
if (nr != BUF_SIZE) {
@@ -248,8 +248,7 @@ void loop() {
m = micros() - m;
totalLatency += m;
- if (buf[BUF_SIZE-1] != '\n') {
+ if (buf[BUF_SIZE - 1] != '\n') {
error("data check error");
if (skipLatency) {
@@ -265,8 +264,8 @@ void loop() {
cout << endl << F("Done") << endl;
@@ -0,0 +1,119 @@
+#ifdef __AVR__
+const uint32_t FILE_SIZE_MiB = 10UL;
+#else // __AVR__
+const uint32_t FILE_SIZE_MiB = 100UL;
+#endif
+bool waitBusy = true;
+#define SD_CONFIG SdSpiConfig(SS, DEDICATED_SPI)
+//#define SD_CONFIG SdSpiConfig(SS, SHARED_SPI)
+// Config for Teensy 3.5/3.6 buit-in SD.
+//#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, DEDICATED_SPI)
+//#define SD_CONFIG SdioConfig(FIFO_SDIO)
+//------------------------------------------------------------------------------
+const uint64_t FILE_SIZE = (uint64_t)FILE_SIZE_MiB << 20;
+SdFs sd;
+FsFile file;
+uint8_t buf[512];
+#define error(s) sd.errorHalt(&Serial, F(s))
+void clearSerialInput() {
+ uint32_t m = micros();
+ do {
+ if (Serial.read() >= 0) {
+ m = micros();
+ } while (micros() - m < 10000);
+}
+void setup() {
+ Serial.begin(9600);
+ // Wait for USB Serial
+ yield();
+ delay(1000);
+void loop() {
+ clearSerialInput();
+ Serial.println(F("\nType any character to start\n"));
+ // Initialize the SD card.
+ if (!sd.begin(SD_CONFIG)) {
+ sd.initErrorHalt();
+ if (!file.open("SdBusyTest.bin", O_RDWR | O_CREAT |O_TRUNC)) {
+ error("file open failed");
+ if (!file.preAllocate(FILE_SIZE)) {
+ error("preallocate failed");
+ Serial.print(F("Starting write of "));
+ Serial.print(FILE_SIZE_MiB);
+ Serial.println(F(" MiB."));
+ uint32_t maxWrite = 0;
+ uint32_t minWrite = 99999999;
+ uint32_t ms = millis();
+ uint32_t maxBusy = 0;
+ uint32_t minBusy = UINT32_MAX;
+ // Write a dummy sector to start a multi-sector write.
+ if(file.write(buf, sizeof(buf)) != sizeof(buf)) {
+ error("write failed for first sector");
+ while (file.position() < FILE_SIZE) {
+ if (waitBusy) {
+ while (sd.card()->isBusy()) {}
+ m = micros() - m;
+ if (m < minBusy) {
+ minBusy = m;
+ if (m > maxBusy) {
+ maxBusy = m;
+ if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
+ error("write failed");
+ if (m < minWrite) {
+ minWrite = m;
+ if (m > maxWrite) {
+ maxWrite = m;
+ ms = millis() - ms;
+ Serial.println(F("\nTimes in micros"));
+ Serial.print(F("minBusy: "));
+ Serial.println(minBusy);
+ Serial.print(F("maxBusy: "));
+ Serial.println(maxBusy);
+ Serial.print(F("minWrite: "));
+ Serial.println(minWrite);
+ Serial.print(F("maxWrite: "));
+ Serial.println(maxWrite);
+ Serial.print(1e-3*ms);
+ Serial.println(F(" Seconds"));
+ Serial.print(1.0*FILE_SIZE/ms);
+ Serial.println(F(" KB/sec"));
@@ -0,0 +1,51 @@
+#define DUMP_RAW 0
+#define DUMP_UPCASE 0
+const uint8_t CS_PIN = SS;
+#define SD_CONFIG SdSpiConfig(CS_PIN)
+SdExFat sd;
+ Serial.println(F("Type any character to begin"));
+ if (!sd.begin(SD_CONFIG)){
+ error("begin failed");
+#if DUMP_RAW
+ sd.dmpSector(&Serial, 0);
+ for (uint8_t i = 0; i < 24; i++) {
+ sd.dmpSector(&Serial, 0X8000 + i);
+ #endif // DUMP_RAW
+ ExFatFile root;
+ if (!root.openRoot(&sd)) {
+ error("openRoot failed");
+ sd.printDir(&Serial, &root);
+ // startSector = 0, sectorCount = 1.
+ sd.dmpFat(&Serial, 0, 1);
+ sd.dmpBitmap(&Serial);
+ sd.printVolInfo(&Serial);
+ sd.checkUpcase(&Serial);
+#if DUMP_UPCASE
+ sd.printUpcase(&Serial);
+#endif // DUMP_UPCASE
+ // sd.dmpCluster(&Serial, 8, 0, 4);
+ // put your main code here, to run repeatedly:
@@ -0,0 +1,43 @@
+const char* name[] = {
+ "SFN.TXT",
+ "LongFilename.txt",
+#if USE_UTF8_LONG_NAMES
+ u8"très élégant.txt",
+#endif // USE_UTF8_LONG_NAMES
+ nullptr};
+char buf[32];
+ while (!Serial) {}
+ Serial.println("Type any character to begin");
+ while (!Serial.available()) {}
+ if (!sd.begin(SS)) {
+ for (uint8_t i = 0; name[i]; i++) {
+ if (!file.open(name[i], O_CREAT |O_RDWR)) {
+ sd.errorHalt("open");
+ size_t len = strlen(name[i]);
+ size_t rtn = file.getName(buf, len);
+ if (rtn != 0) {
+ Serial.println("fail len");
+ rtn = file.getName(buf, len + 1);
+ if (rtn != len) {
+ Serial.println("fail len + 1");
+ Serial.print(rtn);
+ Serial.print(' ');
+ Serial.println(buf);
+ if (!file.remove()) {
+ sd.errorHalt("remove");
@@ -0,0 +1,140 @@
+/*
+ * This sketch is a test of subdirectory and file creation.
+ * It also tests allocation of clusters to directories.
+ *
+ * It will create two subdirectories and create enough files
+ * to force the allocation of a cluster to each directory.
+ * More than 3000 files may be created on a FAT32 volume.
+ * Note: Some cards may 'stutter' others just get slow due
+ * to the number of flash erases this program causes.
+ */
+#include <SdFat.h>
+const uint8_t SD_CHIP_SELECT = SS;
+SdFat sd;
+typedef File file_t;
+// store error strings in flash to save RAM
+ * create enough files to force a cluster to be allocated to dir.
+void dirAllocTest(file_t* dir) {
+ char buf[32], name[32];
+ file_t file;
+ uint16_t n;
+ uint32_t size = dir->dirSize();
+ // create files and write name to file
+ for (n = 0; ; n++){
+ // make file name
+ sprintf(name, "%u.TXT", n);
+ // open start time
+ uint32_t t0 = millis();
+ if (!file.open(dir, name, O_WRONLY | O_CREAT | O_EXCL)) {
+ error("open for write failed");
+ // open end time and write start time
+ uint32_t t1 = millis();
+ // write file name to file
+ file.print(name);
+ if (!file.close()) error("close write");
+ // write end time
+ uint32_t t2 = millis();
+ Serial.print(F("WR "));
+ Serial.print(n);
+ Serial.write(' ');
+ // print time to create file
+ Serial.print(t1 - t0);
+ // print time to write file
+ Serial.println(t2 - t1);
+ // directory size will change when a cluster is added
+ if (dir->curPosition() > size) break;
+ // read files and check content
+ for (uint16_t i = 0; i <= n; i++) {
+ sprintf(name, "%u.TXT", i);
+ if (!file.open(dir, name, O_RDONLY)) {
+ error("open for read failed");
+ // open end time and read start time
+ int16_t nr = file.read(buf, sizeof(buf));
+ if (nr < 5) error("file.read failed");
+ // read end time
+ // check file content
+ if (strlen(name) != (size_t)nr || strncmp(name, buf, nr)) {
+ error("content compare failed");
+ if (!file.close()) error("close read failed");
+ Serial.print(F("RD "));
+ Serial.print(i);
+ // print open time
+ // print read time
+ file_t root;
+ while (!Serial) {} // wait for Leonardo
+ Serial.println(F("Type any character to start"));
+ while (Serial.read() <= 0) {}
+ delay(200); // Catch Due reset problem
+ // initialize the SD card at SPI_FULL_SPEED for best performance.
+ // try lower speed if bus errors occur.
+ if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
+ sd.initErrorHalt(&Serial);
+ root.openRoot(&sd);
+ uint32_t m = millis();
+ // write files to root if not FAT16
+ if (sd.fatType() != 16) {
+ Serial.println(F("Writing files to root"));
+ dirAllocTest(&root);
+ // create sub1 and write files
+ file_t sub1;
+ if (!sub1.mkdir(&root, "SUB1")) error("makdeDir SUB1 failed");
+ Serial.println(F("Writing files to SUB1"));
+ dirAllocTest(&sub1);
+ // create sub2 and write files
+ file_t sub2;
+ if (!sub2.mkdir(&sub1, "SUB2")) error("mkdir SUB2 failed");
+ Serial.println(F("Writing files to SUB2"));
+ dirAllocTest(&sub2);
+ m = millis() - m;
+ Serial.print(F("Done millis: "));
+ Serial.println(m);
+void loop() { }
@@ -0,0 +1,99 @@
+ * This sketch will remove the files and directories
+ * created by the SdFatMakeDir.pde sketch.
+ * Performance is erratic due to the large number
+ * of flash erase operations caused by many random
+ * writes to file structures.
+ * remove all files in dir.
+void deleteFiles(FatFile* dir) {
+ char name[32];
+ // open and delete files
+ for (uint16_t n = 0; ; n++){
+ // assume done if open fails
+ if (!file.open(dir, name, O_WRONLY)) return;
+ // open end time and remove start time
+ if (!file.remove()) error("file.remove failed");
+ // remove end time
+ Serial.print(F("RM "));
+ // open time
+ // remove time
+ // delete files in root if not FAT16.
+ Serial.println(F("Remove files in root"));
+ deleteFiles(&root);
+ // open SUB1 and delete files
+ if (!sub1.open("SUB1", O_RDONLY)) error("open SUB1 failed");
+ Serial.println(F("Remove files in SUB1"));
+ deleteFiles(&sub1);
+ // open SUB2 and delete files
+ if (!sub2.open(&sub1, "SUB2", O_RDONLY)) error("open SUB2 failed");
+ Serial.println(F("Remove files in SUB2"));
+ deleteFiles(&sub2);
+ // remove SUB2
+ if (!sub2.rmdir()) error("sub2.rmdir failed");
+ Serial.println(F("SUB2 removed"));
+ // remove SUB1
+ if (!sub1.rmdir()) error("sub1.rmdir failed");
+ Serial.println(F("SUB1 removed"));
+ Serial.println(F("Done"));
@@ -0,0 +1,162 @@
+ * This program tests the dateTimeCallback() function
+ * and the timestamp() function.
+#include <SPI.h>
+#include "sdios.h"
+// Default SD chip select is SS pin
+const uint8_t chipSelect = SS;
+// create Serial stream
+ArduinoOutStream cout(Serial);
+#define error(s) sd.errorHalt(F(s))
+ * date/time values for debug
+ * normally supplied by a real-time clock or GPS
+// date 1-Oct-21
+uint16_t year = 2021;
+uint8_t month = 10;
+uint8_t day = 1;
+// time 20:30:40
+uint8_t hour = 20;
+uint8_t minute = 30;
+uint8_t second = 40;
+ * User provided date time callback function.
+ * See SdFile::dateTimeCallback() for usage.
+void dateTime(uint16_t* date, uint16_t* time) {
+ // User gets date and time from GPS or real-time
+ // clock in real callback function
+ // return date using FAT_DATE macro to format fields
+ *date = FAT_DATE(year, month, day);
+ // return time using FAT_TIME macro to format fields
+ *time = FAT_TIME(hour, minute, second);
+ * Function to print all timestamps.
+void printTimestamps(FsFile& f) {
+ cout << F("Creation: ");
+ f.printCreateDateTime(&Serial);
+ cout << endl << F("Modify: ");
+ f.printModifyDateTime(&Serial);
+ cout << endl << F("Access: ");
+ f.printAccessDateTime(&Serial);
+ cout << endl;
+void setup(void) {
+ cout << F("Type any character to start\n");
+ // Initialize at the highest speed supported by the board that is
+ // not over 50 MHz. Try a lower speed if SPI errors occur.
+ if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
+ // remove files if they exist
+ sd.remove("callback.txt");
+ sd.remove("default.txt");
+ sd.remove("stamp.txt");
+ // create a new file with default timestamps
+ if (!file.open("default.txt", O_WRONLY | O_CREAT)) {
+ error("open default.txt failed");
+ cout << F("\nOpen with default times\n");
+ printTimestamps(file);
+ // close file
+ /*
+ * Test the date time callback function.
+ * dateTimeCallback() sets the function
+ * that is called when a file is created
+ * or when a file's directory entry is
+ * modified by sync().
+ * The callback can be disabled by the call
+ * SdFile::dateTimeCallbackCancel()
+ // set date time callback function
+ SdFile::dateTimeCallback(dateTime);
+ // create a new file with callback timestamps
+ if (!file.open("callback.txt", O_WRONLY | O_CREAT)) {
+ error("open callback.txt failed");
+ cout << ("\nOpen with callback times\n");
+ // change call back date
+ day += 1;
+ // must add two to see change since FAT second field is 5-bits
+ second += 2;
+ // modify file by writing a byte
+ file.write('t');
+ // force dir update
+ file.sync();
+ cout << F("\nTimes after write\n");
+ * Test timestamp() function
+ * Cancel callback so sync will not
+ * change access/modify timestamp
+ SdFile::dateTimeCallbackCancel();
+ if (!file.open("stamp.txt", O_WRONLY | O_CREAT)) {
+ error("open stamp.txt failed");
+ // set creation date time
+ if (!file.timestamp(T_CREATE, 2021, 11, 10, 1, 2, 3)) {
+ error("set create time failed");
+ // set write/modification date time
+ if (!file.timestamp(T_WRITE, 2021, 11, 11, 4, 5, 6)) {
+ error("set write time failed");
+ // set access date
+ if (!file.timestamp(T_ACCESS, 2021, 11, 12, 7, 8, 9)) {
+ error("set access time failed");
+ cout << F("\nTimes after timestamp() calls\n");
+ cout << F("\nDone\n");
@@ -22,6 +22,7 @@
#include "AnalogBinLogger.h"
@@ -648,7 +649,7 @@ void logData() {
bgnErase = endErase + 1;
// Start a multiple block write.
- if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
+ if (!sd.card()->writeStart(bgnBlock)) {
error("writeBegin failed");
// Write metadata.
@@ -20,7 +20,7 @@
@@ -31,7 +31,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
@@ -80,8 +80,7 @@ void setup() {
// Remove file/dirs from previous run.
if (sd.exists("dir2/DIR3/NAME3.txt")) {
cout << F("Removing /dir2/DIR3/NAME3.txt") << endl;
- if (!sd.remove("dir2/DIR3/NAME3.txt") ||
- !sd.rmdir("dir2/DIR3/") ||
+ if (!sd.remove("dir2/DIR3/NAME3.txt") || !sd.rmdir("dir2/DIR3/") ||
!sd.rmdir("dir2/")) {
error("remove/rmdir failed");
@@ -0,0 +1,567 @@
+ Print.cpp - Base class that provides print() and println()
+ Copyright (c) 2008 David A. Mellis. All right reserved.
+ many modifications, by Paul Stoffregen <paul@pjrc.com>
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Modified 23 November 2006 by David A. Mellis
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+#include <avr/pgmspace.h>
+#include "Arduino.h" // (was wiring.h)
+#include "Print.h"
+#if ARDUINO >= 100
+#else
+void Print::write(const char *str)
+{
+ write((const uint8_t *)str, strlen(str));
+size_t Print::write(const uint8_t *buffer, size_t size)
+ size_t count = 0;
+ while (size--) count += write(*buffer++);
+ return count;
+void Print::write(const uint8_t *buffer, size_t size)
+ while (size--) write(*buffer++);
+size_t Print::print(const String &s)
+ uint8_t buffer[33];
+ unsigned int index = 0;
+ unsigned int len = s.length();
+ while (len > 0) {
+ s.getBytes(buffer, sizeof(buffer), index);
+ unsigned int nbytes = len;
+ if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1;
+ index += nbytes;
+ len -= nbytes;
+ count += write(buffer, nbytes);
+void Print::print(const String &s)
+ for (unsigned int i=0; i < len; i++) {
+ write(s[i]);
+size_t Print::print(const __FlashStringHelper *ifsh)
+ uint8_t buffer[32];
+ const char PROGMEM *p = (const char PROGMEM *)ifsh;
+ unsigned int len = strlen_P(p);
+ if (nbytes > sizeof(buffer)) nbytes = sizeof(buffer);
+ memcpy_P(buffer, p, nbytes);
+ p += nbytes;
+void Print::print(const __FlashStringHelper *ifsh)
+ while (1) {
+ unsigned char c = pgm_read_byte(p++);
+ if (c == 0) return;
+ write(c);
+size_t Print::print(long n)
+ uint8_t sign=0;
+ if (n < 0) {
+ sign = 1;
+ n = -n;
+ return printNumber(n, sign, 10);
+void Print::print(long n)
+ printNumber(n, sign, 10);
+size_t Print::println(void)
+ uint8_t buf[2]={'\r', '\n'};
+ return write(buf, 2);
+void Print::println(void)
+ write(buf, 2);
+//#define USE_HACKER_DELIGHT_OPTIMIZATION
+#define USE_STIMMER_OPTIMIZATION
+#define USE_BENCHMARK_CODE
+#ifdef USE_HACKER_DELIGHT_OPTIMIZATION
+// Adapted from Hacker's Delight (Henry Warren, ISBN 0321842685) www.hackersdelight.org
+// by Rob Tillaart, Tom Carpenter, "genom2" with input from others...
+// http://forum.arduino.cc/index.php?topic=167414.0
+//
+#define divmod10_asm(in32, tmp32, mod8) \
+asm volatile ( \
+ "mov %2, %A0 \n\t" /* mod = in */ \
+ "ori %A0, 1 \n\t" /* q = in | 1 */ \
+ "movw %A1, %A0 \n\t" /* x = q */ \
+ "movw %C1, %C0 \n\t" \
+ "lsr %D1 \n\t" /* x = x >> 2 */ \
+ "ror %C1 \n\t" \
+ "ror %B1 \n\t" \
+ "ror %A1 \n\t" \
+ "lsr %D1 \n\t" \
+ "sub %A0, %A1 \n\t" /* q = q - x */ \
+ "sbc %B0, %B1 \n\t" \
+ "sbc %C0, %C1 \n\t" \
+ "sbc %D0, %D1 \n\t" \
+ "lsr %D1 \n\t" /* x = x >> 4 */ \
+ "add %A1, %A0 \n\t" /* x = x + q */ \
+ "adc %B1, %B0 \n\t" \
+ "adc %C1, %C0 \n\t" \
+ "adc %D1, %D0 \n\t" \
+ "movw %A0, %A1 \n\t" /* q = x */ \
+ "movw %C0, %C1 \n\t" \
+ "add %A0, %B1 \n\t" /* q = q + (x >> 8) */ \
+ "adc %B0, %C1 \n\t" \
+ "adc %C0, %D1 \n\t" \
+ "adc %D0, r1 \n\t" \
+ "mov %A0, %B0 \n\t" /* q = q >> 8 */ \
+ "mov %B0, %C0 \n\t" \
+ "mov %C0, %D0 \n\t" \
+ "eor %D0, %D0 \n\t" \
+ "add %A0, %A1 \n\t" /* q = q + x */ \
+ "adc %B0, %B1 \n\t" \
+ "adc %C0, %C1 \n\t" \
+ "adc %D0, %D1 \n\t" \
+ "andi %A0, 0xF8 \n\t" /* q = q & ~0x7 */ \
+ "sub %2, %A0 \n\t" /* mod = mod - q */ \
+ "lsr %D0 \n\t" /* q = q >> 2 */ \
+ "ror %C0 \n\t" \
+ "ror %B0 \n\t" \
+ "ror %A0 \n\t" \
+ "lsr %D0 \n\t" \
+ "lsr %D0 \n\t" /* q = q >> 1 */ \
+ : "+d" (in32), "=r" (tmp32), "=r" (mod8) : : "r0" \
+)
+#endif // USE_HACKER_DELIGHT_OPTIMIZATION
+#ifdef USE_STIMMER_OPTIMIZATION
+// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
+#define divmod10_asm32(in32, mod8, tmp8) \
+ " ldi %2,51 \n\t" \
+ " mul %A0,%2 \n\t" \
+ " clr %A0 \n\t" \
+ " add r0,%2 \n\t" \
+ " adc %A0,r1 \n\t" \
+ " mov %1,r0 \n\t" \
+ " mul %B0,%2 \n\t" \
+ " clr %B0 \n\t" \
+ " add %A0,r0 \n\t" \
+ " adc %B0,r1 \n\t" \
+ " mul %C0,%2 \n\t" \
+ " clr %C0 \n\t" \
+ " add %B0,r0 \n\t" \
+ " adc %C0,r1 \n\t" \
+ " mul %D0,%2 \n\t" \
+ " clr %D0 \n\t" \
+ " add %C0,r0 \n\t" \
+ " adc %D0,r1 \n\t" \
+ " clr r1 \n\t" \
+ " add %1,%A0 \n\t" \
+ " adc %A0,%B0 \n\t" \
+ " adc %B0,%C0 \n\t" \
+ " adc %C0,%D0 \n\t" \
+ " add %1,%B0 \n\t" \
+ " adc %A0,%C0 \n\t" \
+ " adc %B0,%D0 \n\t" \
+ " add %1,%D0 \n\t" \
+ " lsr %D0 \n\t" \
+ " ror %C0 \n\t" \
+ " ror %B0 \n\t" \
+ " ror %A0 \n\t" \
+ " ror %1 \n\t" \
+ " ldi %2,10 \n\t" \
+ " mul %1,%2 \n\t" \
+ " mov %1,r1 \n\t" \
+ :"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
+#define divmod10_asm24(in32, mod8, tmp8) \
+ " lsr %C0 \n\t" \
+#define divmod10_asm16(in32, mod8, tmp8) \
+ " lsr %B0 \n\t" \
+#define divmod10_asm8(in32, mod8, tmp8) \
+ " lsr %A0 \n\t" \
+#endif // USE_STIMMER_OPTIMIZATION
+#ifdef USE_BENCHMARK_CODE
+uint32_t usec_print = 0;
+size_t Print::printNumberDec(unsigned long n, uint8_t sign)
+void Print::printNumberDec(unsigned long n, uint8_t sign)
+ uint8_t digit, buf[11], *p;
+ uint32_t tmp32;
+ uint8_t tmp8;
+ uint32_t usec = micros();
+ p = buf + (sizeof(buf)-1);
+ #if defined(USE_STIMMER_OPTIMIZATION)
+ while(n & 0xff000000){divmod10_asm32(n, digit, tmp8);*--p = digit + '0';}
+ while(n & 0xff0000){divmod10_asm24(n, digit, tmp8);*--p = digit + '0';}
+ while(n & 0xff00){divmod10_asm16(n, digit, tmp8);*--p = digit + '0';}
+ while((n & 0xff)>9){divmod10_asm8(n, digit, tmp8);*--p = digit + '0';}
+ *--p = n + '0';
+ #else
+ #if defined(USE_HACKER_DELIGHT_OPTIMIZATION)
+ divmod10_asm(n, tmp32, digit);
+ tmp32 = n;
+ n = n / 10;
+ digit = tmp32 - n * 10;
+ #endif
+ *--p = digit + '0';
+ } while (n);
+ if (sign) *--p = '-';
+ usec_print += micros() - usec;
+ return write(p, sizeof(buf)-1 - (p - buf));
+ write(p, sizeof(buf)-1 - (p - buf));
+size_t Print::printNumberHex(unsigned long n)
+void Print::printNumberHex(unsigned long n)
+ uint8_t digit, buf[8], *p;
+ digit = n & 15;
+ *--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
+ n >>= 4;
+size_t Print::printNumberBin(unsigned long n)
+void Print::printNumberBin(unsigned long n)
+ uint8_t buf[32], *p;
+ *--p = '0' + ((uint8_t)n & 1);
+ n >>= 1;
+size_t Print::printNumberAny(unsigned long n, uint8_t base)
+void Print::printNumberAny(unsigned long n, uint8_t base)
+ uint8_t digit, buf[21], *p;
+ uint32_t tmp;
+ //uint32_t usec;
+ //usec = micros();
+ tmp = n;
+ n = n / base;
+ digit = tmp - n * base;
+ //usec_print += micros() - usec;
+size_t Print::printFloat(double number, uint8_t digits)
+void Print::printFloat(double number, uint8_t digits)
+ size_t count=0;
+ // Handle negative numbers
+ if (number < 0.0) {
+ number = -number;
+ // Round correctly so that print(1.999, 2) prints as "2.00"
+ double rounding = 0.5;
+ for (uint8_t i=0; i<digits; ++i) {
+ rounding *= 0.1;
+ number += rounding;
+ // Extract the integer part of the number and print it
+ unsigned long int_part = (unsigned long)number;
+ double remainder = number - (double)int_part;
+ count += printNumber(int_part, sign, 10);
+ printNumber(int_part, sign, 10);
+ // Print the decimal point, but only if there are digits beyond
+ if (digits > 0) {
+ uint8_t n, buf[8], count=1;
+ buf[0] = '.';
+ // Extract digits from the remainder one at a time
+ if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1;
+ while (digits-- > 0) {
+ remainder *= 10.0;
+ n = (uint8_t)(remainder);
+ buf[count++] = '0' + n;
+ remainder -= n;
+ count += write(buf, count);
+ write(buf, count);
@@ -1,6 +1,4 @@
-+++ "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\USB_Host_Shield_2.0/masstorage.cpp" 2020-02-20 06:02:48.567008200 -0800
+master/masstorage.cpp" 2022-10-18 08:48:03.639503200 -0700
@@ -796,6 +796,7 @@
buf[i] = 0x00;
@@ -9,3 +7,4 @@
uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
if(!rc) {
WriteOk[lun] = ((buf[2] & 0x80) == 0);
-This zip file was downloaded on 2/20/2020 from
+This zip file was downloaded on 10/18/2022 from
https://github.com/felis/USB_Host_Shield_2.0
@@ -23,6 +23,7 @@
* DEALINGS IN THE SOFTWARE.
#include "PrintBasic.h"
+#if ENABLE_ARDUINO_FEATURES == 0
#include <math.h>
size_t PrintBasic::print(long n, uint8_t base) {
@@ -32,14 +33,14 @@ size_t PrintBasic::print(long n, uint8_t base) {
return printNum(n, base);
size_t PrintBasic::printNum(unsigned long n, uint8_t base) {
- const uint8_t DIM = 8*sizeof(long);
+ const uint8_t DIM = 8 * sizeof(long);
char buf[DIM];
char *str = &buf[DIM];
if (base < 2) return 0;
- char c = n%base;
+ char c = n % base;
n /= base;
*--str = c + (c < 10 ? '0' : 'A' - 10);
} while (n);
@@ -66,7 +67,7 @@ size_t PrintBasic::printDouble(double n, uint8_t prec) {
double round = 0.5;
- for (uint8_t i = 0; i < prec; ++i) {
+ for (uint8_t i = 0; i < prec; ++i) {
round *= 0.1;
@@ -87,3 +88,4 @@ size_t PrintBasic::printDouble(double n, uint8_t prec) {
return rtn;
+#endif // ENABLE_ARDUINO_FEATURES == 0
@@ -28,18 +28,21 @@
* \file
* \brief Stream/Print like replacement for non-Arduino systems.
-#include <stdint.h>
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
-#ifdef F
-#warning F() macro defined for non Arduino System
-#elif defined(__AVR__)
+#include "../SdFatConfig.h"
+#ifndef F
+#if defined(__AVR__)
#include <avr/pgmspace.h>
class __FlashStringHelper;
-#define F(str) (reinterpret_cast<const __FlashStringHelper *>(PSTR(str)))
-#else // F
+#define F(string_literal) \
+ (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
+#else // defined(__AVR__)
#define F(str) (str)
+#endif // defined(__AVR__)
#endif // F
#ifdef BIN
@@ -54,63 +57,44 @@ class PrintBasic {
PrintBasic() : m_error(0) {}
- void clearWriteError() {
- setWriteError(0);
- int getWriteError() {
- return m_error;
- size_t print(char c) {
- return write(c);
- size_t print(const char* str) {
- return write(str);
+ void clearWriteError() { setWriteError(0); }
+ int getWriteError() { return m_error; }
+ size_t print(char c) { return write(c); }
+ size_t print(const char *str) { return write(str); }
size_t print(const __FlashStringHelper *str) {
- PGM_P p = reinterpret_cast<PGM_P>(str);
- size_t n = 0;
- for (uint8_t c; (c = pgm_read_byte(p + n)) && write(c); n++) {}
- return n;
-#else // __AVR__
- return print(reinterpret_cast<const char *>(str));
+ PGM_P p = reinterpret_cast<PGM_P>(str);
+ size_t n = 0;
+ for (uint8_t c; (c = pgm_read_byte(p + n)) && write(c); n++) {
+ return n;
+ return print(reinterpret_cast<const char *>(str));
#endif // __AVR__
size_t println(const __FlashStringHelper *str) {
return print(str) + println();
return println(reinterpret_cast<const char *>(str));
- size_t print(double n, uint8_t prec = 2) {
- return printDouble(n, prec);
+ size_t print(double n, uint8_t prec = 2) { return printDouble(n, prec); }
size_t print(signed char n, uint8_t base = 10) {
return print((long)n, base);
size_t print(unsigned char n, uint8_t base = 10) {
return print((unsigned long)n, base);
- size_t print(int n, uint8_t base = 10) {
- return print((long)n, base);
+ size_t print(int n, uint8_t base = 10) { return print((long)n, base); }
size_t print(unsigned int n, uint8_t base = 10) {
size_t print(long n, uint8_t base = 10);
- size_t print(unsigned long n, uint8_t base = 10) {
- return printNum(n, base);
- size_t println() {
- return write("\r\n");
- size_t println(char c) {
- return write(c) + println();
- size_t println(const char* str) {
- return print(str) + println();
+ size_t print(unsigned long n, uint8_t base = 10) { return printNum(n, base); }
+ size_t println() { return write("\r\n"); }
+ size_t println(char c) { return write(c) + println(); }
+ size_t println(const char *str) { return print(str) + println(); }
size_t println(double n, uint8_t prec = 2) {
return print(n, prec) + println();
@@ -132,12 +116,10 @@ class PrintBasic {
size_t println(unsigned long n, uint8_t base = 10) {
return print(n, base) + println();
- size_t write(const char *str) {
- return write(str, strlen(str));
+ size_t write(const char *str) { return write(str, strlen(str)); }
virtual size_t write(uint8_t b) = 0;
- virtual size_t write(const uint8_t* buffer, size_t size) {
+ virtual size_t write(const uint8_t *buffer, size_t size) {
size_t i;
for (i = 0; i < size; i++) {
if (!write(buffer[i])) break;
@@ -145,13 +127,11 @@ class PrintBasic {
return i;
size_t write(const char *buffer, size_t size) {
- return write((const uint8_t*)buffer, size);
+ return write(reinterpret_cast<const uint8_t *>(buffer), size);
protected:
- void setWriteError(int err = 1) {
- m_error = err;
+ void setWriteError(int err = 1) { m_error = err; }
private:
size_t printDouble(double n, uint8_t prec);
@@ -67,7 +67,7 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
<file> [file] ...
The style guidelines this tries to follow are those in
- https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+ https://google.github.io/styleguide/cppguide.html
Every problem is given a confidence score from 1-5, with 5 meaning we are
certain of the problem, and 1 meaning it could be a legitimate construct.
@@ -1,5 +1,5 @@
name=SdFat
-version=2.2.0
+version=2.2.2
license=MIT
author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
@@ -28,12 +28,15 @@
* \brief Fast buffered print.
+#endif // __AVR__
#include "common/FmtNumber.h"
/**
* \class BufferedPrint
* \brief Fast buffered print template.
-template<typename WriteClass, uint8_t BUF_DIM>
+template <typename WriteClass, uint8_t BUF_DIM>
class BufferedPrint {
BufferedPrint() : m_wr(nullptr), m_in(0) {}
@@ -49,7 +52,7 @@ class BufferedPrint {
m_in = 0;
/** Flush the buffer - same as sync() with no status return. */
- void flush() {sync();}
+ void flush() { sync(); }
/** Print a character followed by a field terminator.
* \param[in] c character to print.
* \param[in] term The field terminator. Use '\\n' for CR LF.
@@ -72,7 +75,7 @@ class BufferedPrint {
* \return true for success or false if an error occurs.
- size_t printField(const __FlashStringHelper *fsh, char term) {
+ size_t printField(const __FlashStringHelper* fsh, char term) {
size_t rtn = 0;
PGM_P p = reinterpret_cast<PGM_P>(fsh);
@@ -93,8 +96,8 @@ class BufferedPrint {
rtn += write(str, buf + sizeof(buf) - str);
- return printField(reinterpret_cast<const char *>(fsh), term);
+ return printField(reinterpret_cast<const char*>(fsh), term);
/** Print a string followed by a field terminator.
@@ -139,7 +142,7 @@ class BufferedPrint {
* \param[in] prec Number of digits after decimal point.
- size_t printField(float f, char term, uint8_t prec = 2) {
+ size_t printField(float f, char term, uint8_t prec = 2) {
return printField(static_cast<double>(f), term, prec);
/** Print an integer value for 8, 16, and 32 bit signed and unsigned types.
@@ -147,7 +150,7 @@ class BufferedPrint {
- template<typename Type>
+ template <typename Type>
size_t printField(Type n, char term) {
const uint8_t DIM = sizeof(Type) <= 2 ? 8 : 13;
@@ -184,9 +187,7 @@ class BufferedPrint {
- size_t print(double d, uint8_t prec = 2) {
- return printField(d, 0, prec);
+ size_t print(double d, uint8_t prec = 2) { return printField(d, 0, prec); }
/** Print a double followed by CR LF.
* \param[in] d The number to be printed.
@@ -215,7 +216,7 @@ class BufferedPrint {
* \param[in] v item to print.
size_t print(Type v) {
return printField(v, 0);
@@ -223,7 +224,7 @@ class BufferedPrint {
size_t println(Type v) {
return printField(v, '\n');
@@ -238,7 +239,7 @@ class BufferedPrint {
return true;
- /** Write data to an open file.
+ /** Write data to an open file.
* \param[in] src Pointer to the location of the data to be written.
*
* \param[in] n Number of bytes to write.
@@ -22,9 +22,9 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-#include "ExFatVolume.h"
#include "../common/upcase.h"
#include "ExFatLib.h"
+#include "ExFatVolume.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static void printHex(print_t* pr, uint8_t h);
@@ -59,15 +59,15 @@ static uint16_t hashDir(DirName_t* dir, uint16_t hash) {
if (!u) {
- uint16_t c = toUpcase(u);
- hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
- hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
+ uint16_t c = toUpcase(u);
+ hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
+ hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
return hash;
-static void printDateTime(print_t* pr,
- uint32_t timeDate, uint8_t ms, int8_t tz) {
+static void printDateTime(print_t* pr, uint32_t timeDate, uint8_t ms,
+ int8_t tz) {
fsPrintDateTime(pr, timeDate, ms, tz);
pr->println();
@@ -93,11 +93,11 @@ static void printDirFile(print_t* pr, DirFile_t* dir) {
pr->print(F("attributes: 0x"));
pr->println(getLe16(dir->attributes), HEX);
pr->print(F("createTime: "));
- printDateTime(pr, getLe32(dir->createTime),
- dir->createTimeMs, dir->createTimezone);
+ printDateTime(pr, getLe32(dir->createTime), dir->createTimeMs,
+ dir->createTimezone);
pr->print(F("modifyTime: "));
- printDateTime(pr, getLe32(dir->modifyTime),
- dir->modifyTimeMs, dir->modifyTimezone);
+ printDateTime(pr, getLe32(dir->modifyTime), dir->modifyTimeMs,
+ dir->modifyTimezone);
pr->print(F("accessTime: "));
printDateTime(pr, getLe32(dir->accessTime), 0, dir->accessTimezone);
@@ -109,7 +109,7 @@ static void printDirLabel(print_t* pr, DirLabel_t* dir) {
pr->println(dir->labelLength);
pr->print(F("unicode: "));
for (size_t i = 0; i < dir->labelLength; i++) {
- pr->write(dir->unicode[2*i]);
+ pr->write(dir->unicode[2 * i]);
@@ -152,7 +152,7 @@ static void printDirStream(print_t* pr, DirStream_t* dir) {
static void printDirUpcase(print_t* pr, DirUpcase_t* dir) {
pr->print(F("dirUpcase: 0x"));
pr->println(dir->type, HEX);
- pr->print(F("checksum: 0x"));
+ pr->print(F("checksum: 0x"));
pr->println(getLe32(dir->checksum), HEX);
pr->print(F("firstCluster: "));
pr->println(getLe32(dir->firstCluster));
@@ -192,7 +192,7 @@ static void printExFatBoot(print_t* pr, pbs_t* pbs) {
pr->print(F("FileSystemRevision: 0x"));
pr->println(getLe32(ebs->fileSystemRevision), HEX);
pr->print(F("VolumeFlags: 0x"));
- pr->println(getLe16(ebs->volumeFlags) , HEX);
+ pr->println(getLe16(ebs->volumeFlags), HEX);
pr->print(F("BytesPerSectorShift: "));
pr->println(ebs->bytesPerSectorShift);
pr->print(F("SectorsPerClusterShift: "));
@@ -215,7 +215,7 @@ static void printHex(print_t* pr, uint8_t h) {
static void printHex(print_t* pr, uint16_t val) {
bool space = true;
for (uint8_t i = 0; i < 4; i++) {
- uint8_t h = (val >> (12 - 4*i)) & 15;
+ uint8_t h = (val >> (12 - 4 * i)) & 15;
if (h || i == 3) {
space = false;
@@ -230,7 +230,7 @@ static void printHex(print_t* pr, uint16_t val) {
static void printHex(print_t* pr, uint32_t val) {
for (uint8_t i = 0; i < 8; i++) {
- uint8_t h = (val >> (28 - 4*i)) & 15;
+ uint8_t h = (val >> (28 - 4 * i)) & 15;
if (h || i == 7) {
@@ -244,7 +244,7 @@ static void printHex(print_t* pr, uint32_t val) {
static void printHex64(print_t* pr, uint64_t n) {
char buf[17];
- char *str = &buf[sizeof(buf) - 1];
+ char* str = &buf[sizeof(buf) - 1];
*str = '\0';
uint8_t h = n & 15;
@@ -256,12 +256,12 @@ static void printHex64(print_t* pr, uint64_t n) {
static void println64(print_t* pr, uint64_t n) {
char buf[21];
uint64_t m = n;
n /= 10;
- *--str = m - 10*n + '0';
+ *--str = m - 10 * n + '0';
pr->println(str);
@@ -313,15 +313,15 @@ void ExFatPartition::checkUpcase(print_t* pr) {
pr->println(F("upcase not found"));
- for (size_t i = 0; i < size/2; i++) {
- if ((i%256) == 0) {
+ for (size_t i = 0; i < size / 2; i++) {
+ if ((i % 256) == 0) {
upcase = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
if (!upcase) {
pr->println(F("read upcase failed"));
- uint16_t v = getLe16(&upcase[2*(i & 0XFF)]);
+ uint16_t v = getLe16(&upcase[2 * (i & 0XFF)]);
if (skip) {
pr->print("skip ");
pr->print(u);
@@ -334,7 +334,7 @@ void ExFatPartition::checkUpcase(print_t* pr) {
for (uint16_t k = 0; k < v; k++) {
uint16_t x = toUpcase(u + k);
if (x != (u + k)) {
- printHex(pr, (uint16_t)(u+k));
+ printHex(pr, (uint16_t)(u + k));
pr->write(',');
printHex(pr, x);
pr->println("<<<<<<<<<<<<<<<<<<<<");
@@ -363,8 +363,8 @@ void ExFatPartition::dmpBitmap(print_t* pr) {
dmpSector(pr, m_clusterHeapStartSector);
-void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
- uint32_t offset, uint32_t count) {
+void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster, uint32_t offset,
+ uint32_t count) {
uint32_t sector = clusterStartSector(cluster) + offset;
for (uint32_t i = 0; i < count; i++) {
pr->print(F("\nSector: "));
@@ -375,7 +375,7 @@ void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
uint32_t sector = m_fatStartSector + start;
- uint32_t cluster = 128*start;
+ uint32_t cluster = 128 * start;
pr->println(F("FAT:"));
uint8_t* cache = dataCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
@@ -385,7 +385,7 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
for (size_t k = 0; k < 128; k++) {
- if (0 == cluster%8) {
+ if (0 == cluster % 8) {
if (k) {
@@ -406,7 +406,7 @@ void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) {
for (uint16_t i = 0; i < m_bytesPerSector; i++) {
- if (i%32 == 0) {
+ if (i % 32 == 0) {
if (i) {
@@ -427,9 +427,9 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
uint16_t nameHash = 0;
uint16_t setChecksum = 0;
uint16_t calcChecksum = 0;
- uint8_t nameLength = 0;
- uint8_t setCount = 0;
- uint8_t nUnicode;
+ uint8_t nameLength = 0;
+ uint8_t setCount = 0;
+ uint8_t nUnicode;
#define RAW_ROOT
#ifndef RAW_ROOT
@@ -439,12 +439,12 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
dir = reinterpret_cast<DirGeneric_t*>(buf);
-#else // RAW_ROOT
+#else // RAW_ROOT
(void)file;
uint32_t nDir = 1UL << (m_sectorsPerClusterShift + 4);
uint32_t sector = clusterStartSector(m_rootDirectoryCluster);
for (uint32_t iDir = 0; iDir < nDir; iDir++) {
- size_t i = iDir%16;
+ size_t i = iDir % 16;
if (i == 0) {
uint8_t* cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
if (!cache) {
@@ -491,7 +491,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
calcHash = 0;
- case EXFAT_TYPE_NAME:
+ case EXFAT_TYPE_NAME:
dirName = reinterpret_cast<DirName_t*>(dir);
printDirName(pr, dirName);
calcChecksum = exFatDirChecksum(dir, calcChecksum);
@@ -499,7 +499,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
calcHash = hashDir(dirName, calcHash);
nameLength -= nUnicode;
setCount--;
- if (nameLength == 0 || setCount == 0) {
+ if (nameLength == 0 || setCount == 0) {
pr->print(F("setChecksum: 0x"));
pr->print(setChecksum, HEX);
if (setChecksum != calcChecksum) {
@@ -536,10 +536,9 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
void ExFatPartition::printFat(print_t* pr) {
uint32_t next;
- int8_t status;
for (uint32_t cluster = 0; cluster < 16; cluster++) {
- status = fatGet(cluster, &next);
+ int8_t status = fatGet(cluster, &next);
pr->print(cluster, HEX);
pr->write(' ');
if (status == 0) {
@@ -573,20 +572,20 @@ void ExFatPartition::printUpcase(print_t* pr) {
- for (uint16_t i = 0; i < size/2; i++) {
+ for (uint16_t i = 0; i < size / 2; i++) {
- if (i%16 == 0) {
+ if (i % 16 == 0) {
printHex(pr, i);
- uint16_t uc = getLe16(&upcase[2*(i & 0XFF)]);
+ uint16_t uc = getLe16(&upcase[2 * (i & 0XFF)]);
printHex(pr, uc);
checksum = upcaseChecksum(uc, checksum);
@@ -36,7 +36,7 @@
inline bool lfnLegalChar(uint8_t c) {
#if USE_UTF8_LONG_NAMES
return !lfnReservedChar(c);
-#else // USE_UTF8_LONG_NAMES
+#else // USE_UTF8_LONG_NAMES
return !(lfnReservedChar(c) || c & 0X80);
@@ -60,13 +60,13 @@ bool ExFatFile::attrib(uint8_t bits) {
- fail:
+fail:
uint8_t* ExFatFile::dirCache(uint8_t set, uint8_t options) {
DirPos_t pos = m_dirPos;
- if (m_vol->dirSeek(&pos, FS_DIR_SIZE*set) != 1) {
+ if (m_vol->dirSeek(&pos, FS_DIR_SIZE * set) != 1) {
return nullptr;
return m_vol->dirCache(&pos, options);
@@ -87,8 +87,8 @@ bool ExFatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
*bgnSector = firstSector();
if (endSector) {
- *endSector = firstSector() +
- ((m_validLength - 1) >> m_vol->bytesPerSectorShift());
+ *endSector =
+ firstSector() + ((m_validLength - 1) >> m_vol->bytesPerSectorShift());
@@ -136,8 +136,8 @@ void ExFatFile::fsetpos(const fspos_t* pos) {
bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
- DirFile_t* df = reinterpret_cast<DirFile_t*>
- (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
+ DirFile_t* df = reinterpret_cast<DirFile_t*>(
+ m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
if (!df) {
DBG_FAIL_MACRO;
goto fail;
@@ -146,13 +146,13 @@ bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
*ptime = getLe16(df->accessTime);
bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
@@ -161,13 +161,13 @@ bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
*ptime = getLe16(df->createTime);
bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
@@ -176,13 +176,11 @@ bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
*ptime = getLe16(df->modifyTime);
-bool ExFatFile::isBusy() {
- return m_vol->isBusy();
+bool ExFatFile::isBusy() { return m_vol->isBusy(); }
bool ExFatFile::open(const char* path, oflag_t oflag) {
return open(ExFatVolume::cwv(), path, oflag);
@@ -231,7 +229,7 @@ bool ExFatFile::open(ExFatFile* dirFile, const char* path, oflag_t oflag) {
return openPrivate(dirFile, &fname, oflag);
@@ -241,7 +239,7 @@ bool ExFatFile::open(uint32_t index, oflag_t oflag) {
bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) {
- if (dirFile->seekSet(FS_DIR_SIZE*index) && openNext(dirFile, oflag)) {
+ if (dirFile->seekSet(FS_DIR_SIZE * index) && openNext(dirFile, oflag)) {
if (dirIndex() == index) {
@@ -260,7 +258,7 @@ bool ExFatFile::openCwd() {
rewind();
@@ -271,20 +269,18 @@ bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
return openPrivate(dir, nullptr, oflag);
bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
uint8_t modeFlags;
- uint32_t curCluster __attribute__((unused));
uint8_t* cache __attribute__((unused));
DirPos_t freePos __attribute__((unused));
- DirFile_t* dirFile;
+ DirFile_t* dirFile;
DirStream_t* dirStream;
- DirName_t* dirName;
+ DirName_t* dirName;
uint8_t buf[FS_DIR_SIZE];
uint8_t freeCount = 0;
uint8_t freeNeed = 3;
@@ -313,7 +309,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
modeFlags |= oflag & O_APPEND ? FILE_FLAG_APPEND : 0;
if (fname) {
- freeNeed = 2 + (fname->nameLength + 14)/15;
+ freeNeed = 2 + (fname->nameLength + 14) / 15;
dir->rewind();
@@ -394,7 +390,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
- found:
+found:
// Don't open if create only.
if (oflag & O_EXCL) {
@@ -428,11 +424,11 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
#endif // !EXFAT_READ_ONLY
- create:
+create:
#if EXFAT_READ_ONLY
-#else // EXFAT_READ_ONLY
+#else // EXFAT_READ_ONLY
// don't create unless O_CREAT and write
if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !fname) {
DBG_WARN_MACRO;
@@ -441,12 +437,12 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
while (freeCount < freeNeed) {
n = dir->read(buf, FS_DIR_SIZE);
if (n == 0) {
- curCluster = dir->m_curCluster;
+ uint32_t saveCurCluster = dir->m_curCluster;
if (!dir->addDirCluster()) {
- dir->m_curCluster = curCluster;
+ dir->m_curCluster = saveCurCluster;
continue;
if (n != FS_DIR_SIZE) {
@@ -471,7 +467,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
- memset(cache, 0 , FS_DIR_SIZE);
+ memset(cache, 0, FS_DIR_SIZE);
dirFile = reinterpret_cast<DirFile_t*>(cache);
dirFile->type = EXFAT_TYPE_FILE;
@@ -489,11 +485,11 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
setLe16(dirFile->createDate, FS_DEFAULT_DATE);
setLe16(dirFile->modifyDate, FS_DEFAULT_DATE);
setLe16(dirFile->accessDate, FS_DEFAULT_DATE);
- if (FS_DEFAULT_TIME) {
- setLe16(dirFile->createTime, FS_DEFAULT_TIME);
- setLe16(dirFile->modifyTime, FS_DEFAULT_TIME);
- setLe16(dirFile->accessTime, FS_DEFAULT_TIME);
+ if (FS_DEFAULT_TIME) {
+ setLe16(dirFile->createTime, FS_DEFAULT_TIME);
+ setLe16(dirFile->modifyTime, FS_DEFAULT_TIME);
+ setLe16(dirFile->accessTime, FS_DEFAULT_TIME);
} else if (i == 1) {
dirStream = reinterpret_cast<DirStream_t*>(cache);
@@ -510,14 +506,14 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
uint16_t u = fname->get16();
- setLe16(dirName->unicode + 2*k, u);
+ setLe16(dirName->unicode + 2 * k, u);
return sync();
#endif // EXFAT_READ_ONLY
// close file
m_attributes = FILE_ATTR_CLOSED;
m_flags = 0;
@@ -535,12 +531,12 @@ bool ExFatFile::openRoot(ExFatVolume* vol) {
m_flags = FILE_FLAG_READ;
-bool ExFatFile::parsePathName(const char* path,
- ExName_t* fname, const char** ptr) {
+bool ExFatFile::parsePathName(const char* path, ExName_t* fname,
+ const char** ptr) {
// Skip leading spaces.
while (*path == ' ') {
path++;
@@ -559,20 +555,21 @@ bool ExFatFile::parsePathName(const char* path,
// Advance to next path component.
- for (; *path == ' ' || isDirSeparator(*path); path++) {}
+ for (; *path == ' ' || isDirSeparator(*path); path++) {
*ptr = path;
return hashName(fname);
int ExFatFile::peek() {
- uint64_t curPosition = m_curPosition;
- uint32_t curCluster = m_curCluster;
+ uint64_t saveCurPosition = m_curPosition;
+ uint32_t saveCurCluster = m_curCluster;
int c = read();
- m_curPosition = curPosition;
- m_curCluster = curCluster;
+ m_curPosition = saveCurPosition;
+ m_curCluster = saveCurCluster;
return c;
@@ -600,8 +597,8 @@ int ExFatFile::read(void* buf, size_t count) {
sectorOffset = clusterOffset & m_vol->sectorMask();
if (clusterOffset == 0) {
if (m_curPosition == 0) {
- m_curCluster = isRoot()
- ? m_vol->rootDirectoryCluster() : m_firstCluster;
+ m_curCluster =
+ isRoot() ? m_vol->rootDirectoryCluster() : m_firstCluster;
} else if (isContiguous()) {
m_curCluster++;
@@ -622,8 +619,8 @@ int ExFatFile::read(void* buf, size_t count) {
sector = m_vol->clusterStartSector(m_curCluster) +
(clusterOffset >> m_vol->bytesPerSectorShift());
- if (sectorOffset != 0 || toRead < m_vol->bytesPerSector()
- || sector == m_vol->dataCacheSector()) {
+ if (sectorOffset != 0 || toRead < m_vol->bytesPerSector() ||
+ sector == m_vol->dataCacheSector()) {
n = m_vol->bytesPerSector() - sectorOffset;
if (n > toRead) {
n = toRead;
@@ -637,16 +634,16 @@ int ExFatFile::read(void* buf, size_t count) {
uint8_t* src = cache + sectorOffset;
memcpy(dst, src, n);
#if USE_MULTI_SECTOR_IO
- } else if (toRead >= 2*m_vol->bytesPerSector()) {
+ } else if (toRead >= 2 * m_vol->bytesPerSector()) {
uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
// Limit reads to current cluster.
- uint32_t maxNs = m_vol->sectorsPerCluster()
- - (clusterOffset >> m_vol->bytesPerSectorShift());
+ uint32_t maxNs = m_vol->sectorsPerCluster() -
+ (clusterOffset >> m_vol->bytesPerSectorShift());
if (ns > maxNs) {
ns = maxNs;
n = ns << m_vol->bytesPerSectorShift();
- if (!m_vol->cacheSafeRead(sector, dst, ns)) {
+ if (!m_vol->cacheSafeRead(sector, dst, ns)) {
@@ -665,7 +662,7 @@ int ExFatFile::read(void* buf, size_t count) {
return count - toRead;
m_error |= READ_ERROR;
return -1;
@@ -678,7 +675,7 @@ bool ExFatFile::remove(const char* path) {
return file.remove();
@@ -728,11 +725,11 @@ bool ExFatFile::seekSet(uint64_t pos) {
- done:
+done:
m_curPosition = pos;
m_curCluster = tmp;
@@ -30,9 +30,10 @@
#include <limits.h>
-#include "../common/FsDateTime.h"
-#include "../common/FsApiConstants.h"
#include "../common/FmtNumber.h"
+#include "../common/FsApiConstants.h"
+#include "../common/FsDateTime.h"
#include "../common/FsName.h"
#include "ExFatPartition.h"
@@ -68,9 +69,7 @@ class ExFatFile {
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
- ExFatFile(const char* path, oflag_t oflag) {
- open(path, oflag);
+ ExFatFile(const char* path, oflag_t oflag) { open(path, oflag); }
#if DESTRUCTOR_CLOSES_FILE
~ExFatFile() {
@@ -81,18 +80,14 @@ class ExFatFile {
#endif // DESTRUCTOR_CLOSES_FILE
/** The parenthesis operator.
- *
- * \return true if a file is open.
- */
- operator bool() {
- return isOpen();
+ * \return true if a file is open.
+ operator bool() { return isOpen(); }
* \return user settable file attributes for success else -1.
- int attrib() {
- return isFileOrSubDir() ? m_attributes & FS_ATTRIB_COPY : -1;
+ int attrib() { return isFileOrSubDir() ? m_attributes & FS_ATTRIB_COPY : -1; }
/** Set file attributes
* \param[in] bits bit-wise or of selected attributes: FS_ATTRIB_READ_ONLY,
@@ -117,17 +112,11 @@ class ExFatFile {
/** \return The number of bytes available from the current position
* to EOF for normal files. Zero is returned for directory files.
- uint64_t available64() {
- return isFile() ? fileSize() - curPosition() : 0;
+ uint64_t available64() { return isFile() ? fileSize() - curPosition() : 0; }
/** Clear all error bits. */
- void clearError() {
- m_error = 0;
+ void clearError() { m_error = 0; }
/** Clear writeError. */
- m_error &= ~WRITE_ERROR;
+ void clearWriteError() { m_error &= ~WRITE_ERROR; }
/** Close a file and force cached data and directory information
* to be written to the storage device.
@@ -145,13 +134,13 @@ class ExFatFile {
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
/** \return The current cluster number for a file or directory. */
- uint32_t curCluster() const {return m_curCluster;}
+ uint32_t curCluster() const { return m_curCluster; }
/** \return The current position for a file or directory. */
- uint64_t curPosition() const {return m_curPosition;}
+ uint64_t curPosition() const { return m_curPosition; }
/** \return Total data length for file. */
- uint64_t dataLength() const {return m_dataLength;}
+ uint64_t dataLength() const { return m_dataLength; }
/** \return Directory entry index. */
- uint32_t dirIndex() const {return m_dirPos.position/FS_DIR_SIZE;}
+ uint32_t dirIndex() const { return m_dirPos.position / FS_DIR_SIZE; }
/** Test for the existence of a file in a directory
* \param[in] path Path of the file to be tested for.
@@ -163,15 +152,15 @@ class ExFatFile {
* \return true if the file exists else false.
- bool exists(const char* path) {
- ExFatFile file;
- return file.open(this, path, O_RDONLY);
+ bool exists(const char* path) {
+ ExFatFile file;
+ return file.open(this, path, O_RDONLY);
/** get position for streams
* \param[out] pos struct to receive position
void fgetpos(fspos_t* pos) const;
- /**
+ /**
* Get a string from a file.
* fgets() reads bytes from a file into the array pointed to by \a str, until
@@ -194,7 +183,7 @@ class ExFatFile {
int fgets(char* str, int num, char* delim = nullptr);
/** \return The total number of bytes in a file. */
- uint64_t fileSize() const {return m_validLength;}
+ uint64_t fileSize() const { return m_validLength; }
/** \return Address of first sector or zero for empty file. */
uint32_t firstSector() const;
/** Set position for streams
@@ -202,7 +191,7 @@ class ExFatFile {
void fsetpos(const fspos_t* pos);
/** Arduino name for sync() */
/** Get a file's access date and time.
* \param[out] pdate Packed date for directory entry.
@@ -220,9 +209,7 @@ class ExFatFile {
bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime);
/** \return All error bits. */
- uint8_t getError() const {
- return isOpen() ? m_error : 0XFF;
+ uint8_t getError() const { return isOpen() ? m_error : 0XFF; }
/** Get a file's modify date and time.
@@ -241,7 +228,7 @@ class ExFatFile {
size_t getName(char* name, size_t size) {
return getName8(name, size);
return getName7(name, size);
@@ -262,9 +249,7 @@ class ExFatFile {
size_t getName8(char* name, size_t size);
/** \return value of writeError */
- bool getWriteError() const {
- return isOpen() ? m_error & WRITE_ERROR : true;
+ bool getWriteError() const { return isOpen() ? m_error & WRITE_ERROR : true; }
* Check for FsBlockDevice busy.
@@ -272,29 +257,29 @@ class ExFatFile {
bool isBusy();
/** \return True if the file is contiguous. */
- bool isContiguous() const {return m_flags & FILE_FLAG_CONTIGUOUS;}
+ bool isContiguous() const { return m_flags & FILE_FLAG_CONTIGUOUS; }
/** \return True if this is a directory. */
- bool isDir() const {return m_attributes & FILE_ATTR_DIR;}
+ bool isDir() const { return m_attributes & FILE_ATTR_DIR; }
/** \return True if this is a normal file. */
- bool isFile() const {return m_attributes & FILE_ATTR_FILE;}
+ bool isFile() const { return m_attributes & FILE_ATTR_FILE; }
/** \return True if this is a normal file or sub-directory. */
- bool isFileOrSubDir() const {return isFile() || isSubDir();}
+ bool isFileOrSubDir() const { return isFile() || isSubDir(); }
/** \return True if this is a hidden. */
- bool isHidden() const {return m_attributes & FS_ATTRIB_HIDDEN;}
+ bool isHidden() const { return m_attributes & FS_ATTRIB_HIDDEN; }
/** \return true if the file is open. */
- bool isOpen() const {return m_attributes;}
+ bool isOpen() const { return m_attributes; }
/** \return True if file is read-only */
- bool isReadOnly() const {return m_attributes & FS_ATTRIB_READ_ONLY;}
+ bool isReadOnly() const { return m_attributes & FS_ATTRIB_READ_ONLY; }
/** \return True if this is the root directory. */
- bool isRoot() const {return m_attributes & FILE_ATTR_ROOT;}
+ bool isRoot() const { return m_attributes & FILE_ATTR_ROOT; }
/** \return True file is readable. */
- bool isReadable() const {return m_flags & FILE_FLAG_READ;}
+ bool isReadable() const { return m_flags & FILE_FLAG_READ; }
/** \return True if this is a sub-directory. */
- bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
+ bool isSubDir() const { return m_attributes & FILE_ATTR_SUBDIR; }
/** \return True if this is a system file. */
- bool isSystem() const {return m_attributes & FS_ATTRIB_SYSTEM;}
+ bool isSystem() const { return m_attributes & FS_ATTRIB_SYSTEM; }
/** \return True file is writable. */
- bool isWritable() const {return m_flags & FILE_FLAG_WRITE;}
+ bool isWritable() const { return m_flags & FILE_FLAG_WRITE; }
/** List directory contents.
* \param[in] pr Print stream for list.
@@ -424,7 +409,7 @@ class ExFatFile {
* \return true for success or false for failure.
bool open(const char* path, oflag_t oflag = O_RDONLY);
- /** Open the current working directory.
+ /** Open the current working directory.
@@ -463,14 +448,14 @@ class ExFatFile {
bool preAllocate(uint64_t length);
- /** Print a file's access date and time
+ /** Print a file's access date and time
* \param[in] pr Print stream for output.
size_t printAccessDateTime(print_t* pr);
- /** Print a file's creation date and time
+ /** Print a file's creation date and time
@@ -512,7 +497,7 @@ class ExFatFile {
template <typename Type>
size_t printField(Type value, char term) {
char sign = 0;
- char buf[3*sizeof(Type) + 3];
+ char buf[3 * sizeof(Type) + 3];
char* str = buf + sizeof(buf);
if (term) {
@@ -556,7 +541,7 @@ class ExFatFile {
size_t printName(print_t* pr) {
return printName8(pr);
return printName7(pr);
@@ -621,14 +606,14 @@ class ExFatFile {
bool remove(const char* path);
- /** Rename a file or subdirectory.
+ /** Rename a file or subdirectory.
* \param[in] newPath New path name for the file/directory.
bool rename(const char* newPath);
* \param[in] dirFile Directory for the new path.
@@ -637,9 +622,7 @@ class ExFatFile {
bool rename(ExFatFile* dirFile, const char* newPath);
/** Set the file's current position to zero. */
- void rewind() {
- seekSet(0);
+ void rewind() { seekSet(0); }
/** Remove a directory file.
* The directory file will be removed only if it is empty and is not the
@@ -657,9 +640,7 @@ class ExFatFile {
* \param[in] offset The new position in bytes from the current position.
- bool seekCur(int64_t offset) {
- return seekSet(m_curPosition + offset);
+ bool seekCur(int64_t offset) { return seekSet(m_curPosition + offset); }
/** Set the files position to end-of-file + \a offset. See seekSet().
* Can't be used for directory files since file size is not defined.
* \param[in] offset The new position in bytes from end-of-file.
@@ -676,7 +657,7 @@ class ExFatFile {
bool seekSet(uint64_t pos);
/** \return directory set count */
- uint8_t setCount() const {return m_setCount;}
+ uint8_t setCount() const { return m_setCount; }
/** The sync() call causes all modified data and directory fields
@@ -728,32 +709,28 @@ class ExFatFile {
bool truncate();
- /** Truncate a file to a specified length. The current file position
+ /** Truncate a file to a specified length. The current file position
* will be set to end of file.
* \param[in] length The desired length for the file.
- bool truncate(uint64_t length) {
- return seekSet(length) && truncate();
+ bool truncate(uint64_t length) { return seekSet(length) && truncate(); }
/** \return The valid number of bytes in a file. */
- uint64_t validLength() const {return m_validLength;}
+ uint64_t validLength() const { return m_validLength; }
/** Write a string to a file. Used by the Arduino Print class.
* \param[in] str Pointer to the string.
* Use getWriteError to check for errors.
* \return count of characters written for success or -1 for failure.
- size_t write(const char* str) {
+ size_t write(const char* str) { return write(str, strlen(str)); }
/** Write a single byte.
* \param[in] b The byte to be written.
* \return +1 for success or zero for failure.
- size_t write(uint8_t b) {return write(&b, 1);}
+ size_t write(uint8_t b) { return write(&b, 1); }
/** Write data to an open file.
* \note Data is moved to the cache but may not be written to the
@@ -781,16 +758,12 @@ class ExFatFile {
- bool ls(uint8_t flags = 0) {
- return ls(&Serial, flags);
+ bool ls(uint8_t flags = 0) { return ls(&Serial, flags); }
/** Print a file's name.
* \return length for success or zero for failure.
- size_t printName() {
- return ExFatFile::printName(&Serial);
+ size_t printName() { return ExFatFile::printName(&Serial); }
#endif // ENABLE_ARDUINO_SERIAL
@@ -804,13 +777,12 @@ class ExFatFile {
bool mkdir(ExFatFile* parent, ExName_t* fname);
bool openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag);
- bool parsePathName(const char* path,
- ExName_t* fname, const char** ptr);
- ExFatVolume* volume() const {return m_vol;}
+ bool parsePathName(const char* path, ExName_t* fname, const char** ptr);
+ ExFatVolume* volume() const { return m_vol; }
bool syncDir();
//----------------------------------------------------------------------------
static const uint8_t WRITE_ERROR = 0X1;
- static const uint8_t READ_ERROR = 0X2;
+ static const uint8_t READ_ERROR = 0X2;
/** This file has not been opened. */
static const uint8_t FILE_ATTR_CLOSED = 0;
@@ -826,21 +798,20 @@ class ExFatFile {
static const uint8_t FILE_FLAG_READ = 0X01;
static const uint8_t FILE_FLAG_WRITE = 0X02;
static const uint8_t FILE_FLAG_APPEND = 0X08;
- static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
+ static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
static const uint8_t FILE_FLAG_DIR_DIRTY = 0X80;
- uint64_t m_curPosition;
- uint64_t m_dataLength;
- uint64_t m_validLength;
- uint32_t m_curCluster;
- uint32_t m_firstCluster;
- ExFatVolume* m_vol;
- DirPos_t m_dirPos;
- uint8_t m_setCount;
- uint8_t m_attributes = FILE_ATTR_CLOSED;
- uint8_t m_error = 0;
- uint8_t m_flags = 0;
+ uint64_t m_curPosition;
+ uint64_t m_dataLength;
+ uint64_t m_validLength;
+ uint32_t m_curCluster;
+ uint32_t m_firstCluster;
+ ExFatVolume* m_vol;
+ DirPos_t m_dirPos;
+ uint8_t m_setCount;
+ uint8_t m_attributes = FILE_ATTR_CLOSED;
+ uint8_t m_error = 0;
+ uint8_t m_flags = 0;
#include "../common/ArduinoFiles.h"
@@ -850,7 +821,7 @@ class ExFatFile {
class ExFile : public StreamFile<ExFatFile, uint64_t> {
- /** Opens the next file or folder in a directory.
+ /** Opens the next file or folder in a directory.
* \param[in] oflag open flags.
* \return a FatStream object.
@@ -24,8 +24,8 @@
#define DBG_FILE "ExFatFilePrint.cpp"
#include "../common/DebugMacros.h"
-#include "ExFatLib.h"
#include "../common/FsUtf.h"
+#include "ExFatLib.h"
bool ExFatFile::ls(print_t* pr) {
ExFatFile file;
@@ -51,7 +51,7 @@ bool ExFatFile::ls(print_t* pr) {
@@ -94,7 +94,7 @@ bool ExFatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
@@ -119,13 +119,13 @@ size_t ExFatFile::printCreateDateTime(print_t* pr) {
size_t ExFatFile::printFileSize(print_t* pr) {
uint64_t n = m_validLength;
- char *bgn = str - 12;
+ char* bgn = str - 12;
while (str > bgn) {
*--str = ' ';
@@ -148,18 +148,17 @@ size_t ExFatFile::printName7(print_t* pr) {
uint8_t in;
uint8_t buf[15];
if (!isOpen()) {
- DBG_FAIL_MACRO;
- goto fail;
+ DBG_FAIL_MACRO;
+ goto fail;
for (uint8_t is = 2; is <= m_setCount; is++) {
- dn = reinterpret_cast<DirName_t*>
- (dirCache(is, FsCache::CACHE_FOR_READ));
+ dn = reinterpret_cast<DirName_t*>(dirCache(is, FsCache::CACHE_FOR_READ));
if (!dn || dn->type != EXFAT_TYPE_NAME) {
for (in = 0; in < 15; in++) {
- uint16_t c = getLe16(dn->unicode + 2*in);
+ uint16_t c = getLe16(dn->unicode + 2 * in);
if (!c) {
@@ -170,11 +169,11 @@ size_t ExFatFile::printName7(print_t* pr) {
return n;
-size_t ExFatFile::printName8(print_t *pr) {
+size_t ExFatFile::printName8(print_t* pr) {
DirName_t* dn;
uint16_t hs = 0;
uint32_t cp;
@@ -182,18 +181,17 @@ size_t ExFatFile::printName8(print_t *pr) {
char buf[5];
if (hs) {
if (!FsUtf::isLowSurrogate(c)) {
@@ -218,11 +216,11 @@ size_t ExFatFile::printName8(print_t *pr) {
- n += pr->write(buf, str - buf);
+ n += pr->write(reinterpret_cast<uint8_t*>(buf), str - buf);
@@ -28,7 +28,7 @@
bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
- (void) parent;
+ (void)parent;
(void)path;
(void)pFlag;
@@ -46,12 +46,8 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
(void)newPath;
-bool ExFatFile::sync() {
- return false;
-bool ExFatFile::truncate() {
+bool ExFatFile::sync() { return false; }
+bool ExFatFile::truncate() { return false; }
size_t ExFatFile::write(const void* buf, size_t nbyte) {
(void)buf;
(void)nbyte;
@@ -69,7 +65,7 @@ static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
bool ExFatFile::addCluster() {
- uint32_t find = m_vol->bitmapFind(m_curCluster ? m_curCluster + 1 : 0, 1);
+ uint32_t find = m_vol->bitmapFind(m_curCluster ? m_curCluster + 1 : 0, 1);
if (find < 2) {
@@ -109,11 +105,11 @@ bool ExFatFile::addCluster() {
m_curCluster = find;
@@ -131,9 +127,9 @@ bool ExFatFile::addDirCluster() {
sector = m_vol->clusterStartSector(m_curCluster);
- for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) {
- cache = m_vol->dataCachePrepare(sector + i,
- FsCache::CACHE_RESERVE_FOR_WRITE);
+ for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) {
+ cache =
+ m_vol->dataCachePrepare(sector + i, FsCache::CACHE_RESERVE_FOR_WRITE);
@@ -142,12 +138,12 @@ bool ExFatFile::addDirCluster() {
if (!isRoot()) {
m_flags |= FILE_FLAG_DIR_DIRTY;
- m_dataLength += m_vol->bytesPerCluster();
+ m_dataLength += m_vol->bytesPerCluster();
m_validLength += m_vol->bytesPerCluster();
@@ -189,7 +185,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
return mkdir(parent, &fname);
@@ -218,7 +214,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, ExName_t* fname) {
m_flags = FILE_FLAG_READ | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
@@ -248,7 +244,7 @@ bool ExFatFile::preAllocate(uint64_t length) {
@@ -290,7 +286,7 @@ bool ExFatFile::remove() {
// Write entry to device.
return m_vol->cacheSync();
@@ -330,7 +326,7 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
oldFile.m_attributes = FILE_ATTR_FILE;
return oldFile.remove();
@@ -363,7 +359,7 @@ bool ExFatFile::rmdir() {
m_flags |= FILE_FLAG_WRITE;
return remove();
@@ -382,7 +378,7 @@ bool ExFatFile::sync() {
m_error |= WRITE_ERROR;
@@ -393,7 +389,7 @@ bool ExFatFile::syncDir() {
uint8_t* cache;
uint16_t checksum = 0;
- for (uint8_t is = 0; is <= m_setCount ; is++) {
+ for (uint8_t is = 0; is <= m_setCount; is++) {
cache = dirCache(is, FsCache::CACHE_FOR_READ);
@@ -439,8 +435,8 @@ bool ExFatFile::syncDir() {
checksum = exFatDirChecksum(cache, checksum);
- df = reinterpret_cast<DirFile_t*>
- (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
+ df = reinterpret_cast<DirFile_t*>(
+ m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
@@ -452,13 +448,14 @@ bool ExFatFile::syncDir() {
bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
- uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
+ uint8_t day, uint8_t hour, uint8_t minute,
+ uint8_t second) {
DirFile_t* df;
@@ -466,16 +463,8 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint16_t time;
uint8_t ms10;
- if (!isFile()
- || year < 1980
- || year > 2107
- || month < 1
- || month > 12
- || day < 1
- || day > 31
- || hour > 23
- || minute > 59
- || second > 59) {
+ if (!isFile() || year < 1980 || year > 2107 || month < 1 || month > 12 ||
+ day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
@@ -529,8 +518,8 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
@@ -542,7 +531,7 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
@@ -554,7 +543,7 @@ bool ExFatFile::truncate() {
if (m_firstCluster == 0) {
- return true;
+ return true;
if (isContiguous()) {
uint32_t nc = 1 + ((m_dataLength - 1) >> m_vol->bytesPerClusterShift());
@@ -601,7 +590,7 @@ bool ExFatFile::truncate() {
@@ -708,18 +697,18 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
- } else if (toWrite >= 2*m_vol->bytesPerSector()) {
+ } else if (toWrite >= 2 * m_vol->bytesPerSector()) {
// use multiple sector write command
uint32_t ns = toWrite >> m_vol->bytesPerSectorShift();
// Limit writes to current cluster.
if (!m_vol->cacheSafeWrite(sector, src, ns)) {
#endif // USE_MULTI_SECTOR_IO
@@ -748,7 +737,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
return nbyte;
// return for write error
@@ -31,7 +31,7 @@
const uint32_t BOOT_BACKUP_OFFSET = 12;
const uint16_t BYTES_PER_SECTOR = 512;
const uint16_t SECTOR_MASK = BYTES_PER_SECTOR - 1;
-const uint8_t BYTES_PER_SECTOR_SHIFT = 9;
+const uint8_t BYTES_PER_SECTOR_SHIFT = 9;
const uint16_t MINIMUM_UPCASE_SKIP = 512;
const uint32_t BITMAP_CLUSTER = 2;
const uint32_t UPCASE_CLUSTER = 3;
@@ -41,14 +41,16 @@ const uint32_t ROOT_CLUSTER = 4;
#if !PRINT_FORMAT_PROGRESS
#define writeMsg(pr, str)
#elif defined(__AVR__)
-#define writeMsg(pr, str) if (pr) pr->print(F(str))
+#define writeMsg(pr, str) \
+ if (pr) pr->print(F(str))
#else // PRINT_FORMAT_PROGRESS
-#define writeMsg(pr, str) if (pr) pr->write(str)
+ if (pr) pr->write(str)
#endif // PRINT_FORMAT_PROGRESS
bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
-(void)pr;
+ (void)pr;
#endif // !PRINT_FORMAT_PROGRESS
MbrSector_t* mbr;
ExFatPbs_t* pbs;
@@ -81,14 +83,15 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
// Determine partition layout.
- for (m = 1, vs = 0; m && sectorCount > m; m <<= 1, vs++) {}
- sectorsPerClusterShift = vs < 29 ? 8 : (vs - 11)/2;
+ for (m = 1, vs = 0; m && sectorCount > m; m <<= 1, vs++) {
+ sectorsPerClusterShift = vs < 29 ? 8 : (vs - 11) / 2;
sectorsPerCluster = 1UL << sectorsPerClusterShift;
- fatLength = 1UL << (vs < 27 ? 13 : (vs + 1)/2);
+ fatLength = 1UL << (vs < 27 ? 13 : (vs + 1) / 2);
fatOffset = fatLength;
- partitionOffset = 2*fatLength;
- clusterHeapOffset = 2*fatLength;
- clusterCount = (sectorCount - 4*fatLength) >> sectorsPerClusterShift;
+ partitionOffset = 2 * fatLength;
+ clusterHeapOffset = 2 * fatLength;
+ clusterCount = (sectorCount - 4 * fatLength) >> sectorsPerClusterShift;
volumeLength = clusterHeapOffset + (clusterCount << sectorsPerClusterShift);
// make Master Boot Record. Use fake CHS.
@@ -152,8 +155,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
checksum = exFatChecksum(checksum, secBuf[i]);
sector = partitionOffset;
- if (!dev->writeSector(sector, secBuf) ||
- !dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
+ if (!dev->writeSector(sector, secBuf) ||
+ !dev->writeSector(sector + BOOT_BACKUP_OFFSET, secBuf)) {
@@ -165,8 +168,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
@@ -178,8 +181,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
@@ -189,15 +192,15 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
for (size_t i = 0; i < BYTES_PER_SECTOR; i += 4) {
setLe32(secBuf + i, checksum);
// Initialize FAT.
writeMsg(pr, "Writing FAT ");
sector = partitionOffset + fatOffset;
- ns = ((clusterCount + 2)*4 + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
+ ns = ((clusterCount + 2) * 4 + BYTES_PER_SECTOR - 1) / BYTES_PER_SECTOR;
memset(secBuf, 0, BYTES_PER_SECTOR);
// Allocate two reserved clusters, bitmap, upcase, and root clusters.
@@ -206,7 +209,7 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
secBuf[i] = 0XFF;
for (uint32_t i = 0; i < ns; i++) {
- if (i%(ns/32) == 0) {
+ if (i % (ns / 32) == 0) {
writeMsg(pr, ".");
if (!dev->writeSector(sector + i, secBuf)) {
@@ -220,8 +223,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
writeMsg(pr, "\r\n");
// Write cluster two, bitmap.
sector = partitionOffset + clusterHeapOffset;
- bitmapSize = (clusterCount + 7)/8;
- ns = (bitmapSize + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
+ bitmapSize = (clusterCount + 7) / 8;
+ ns = (bitmapSize + BYTES_PER_SECTOR - 1) / BYTES_PER_SECTOR;
if (ns > sectorsPerCluster) {
@@ -244,14 +247,14 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
- if (m_upcaseSize > BYTES_PER_SECTOR*sectorsPerCluster) {
+ if (m_upcaseSize > BYTES_PER_SECTOR * sectorsPerCluster) {
// Initialize first sector of root.
writeMsg(pr, "Writing root\r\n");
ns = sectorsPerCluster;
- sector = partitionOffset + clusterHeapOffset + 2*sectorsPerCluster;
+ sector = partitionOffset + clusterHeapOffset + 2 * sectorsPerCluster;
// Unused Label entry.
@@ -284,7 +287,7 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
writeMsg(pr, "Format done\r\n");
writeMsg(pr, "Format failed\r\n");
@@ -334,7 +337,8 @@ bool ExFatFormatter::writeUpcase(uint32_t sector) {
ch++;
- for (n = ch + 1; n < 0X10000 && n == toUpcase(n); n++) {}
+ for (n = ch + 1; n < 0X10000 && n == toUpcase(n); n++) {
ns = n - ch;
if (ns >= MINIMUM_UPCASE_SKIP) {
if (!writeUpcaseUnicode(0XFFFF) || !writeUpcaseUnicode(ns)) {
@@ -358,6 +362,6 @@ bool ExFatFormatter::writeUpcase(uint32_t sector) {
@@ -31,6 +31,8 @@
class ExFatFormatter {
+ /** Constructor. */
+ ExFatFormatter() = default;
* Format an exFAT volume.
@@ -41,6 +43,7 @@ class ExFatFormatter {
bool format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr);
bool syncUpcase();
bool writeUpcase(uint32_t sector);
@@ -24,6 +24,6 @@
#ifndef ExFatLib_h
#define ExFatLib_h
#include "ExFatFormatter.h"
#endif // ExFatLib_h
@@ -24,13 +24,11 @@
#define DBG_FILE "ExFatName.cpp"
-#include "../common/upcase.h"
+#include "../common/upcase.h"
-static char toUpper(char c) {
- return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c;
+static char toUpper(char c) { return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c; }
inline uint16_t exFatHash(char c, uint16_t hash) {
uint8_t u = toUpper(c);
@@ -48,16 +46,16 @@ inline uint16_t exFatHash(uint16_t u, uint16_t hash) {
bool ExFatFile::cmpName(const DirName_t* dirName, ExName_t* fname) {
for (uint8_t i = 0; i < 15; i++) {
- uint16_t u = getLe16(dirName->unicode + 2*i);
+ uint16_t u = getLe16(dirName->unicode + 2 * i);
if (fname->atEnd()) {
return u == 0;
uint16_t cp = fname->get16();
if (toUpcase(cp) != toUpcase(u)) {
+ return false;
char c = fname->getch();
if (u >= 0x7F || toUpper(c) != toUpper(u)) {
@@ -71,18 +69,17 @@ size_t ExFatFile::getName7(char* name, size_t count) {
for (uint8_t in = 0; in < 15; in++) {
if (c == 0) {
goto done;
@@ -93,11 +90,11 @@ size_t ExFatFile::getName7(char* name, size_t count) {
name[n++] = c < 0X7F ? c : '?';
name[n] = 0;
*name = 0;
@@ -110,18 +107,17 @@ size_t ExFatFile::getName8(char* name, size_t count) {
@@ -150,11 +146,11 @@ size_t ExFatFile::getName8(char* name, size_t count) {
str = ptr;
return str - name;
@@ -167,13 +163,13 @@ bool ExFatFile::hashName(ExName_t* fname) {
while (!fname->atEnd()) {
if (u == 0XFFFF) {
hash = exFatHash(u, hash);
fname->nameLength++;
// Convert to byte for smaller exFatHash.
@@ -188,7 +184,6 @@ bool ExFatFile::hashName(ExName_t* fname) {
@@ -39,8 +39,8 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
uint8_t mask = 1 << (start & 7);
- uint32_t sector = m_clusterHeapStartSector +
- (endAlloc >> (m_bytesPerSectorShift + 3));
+ uint32_t sector =
+ m_clusterHeapStartSector + (endAlloc >> (m_bytesPerSectorShift + 3));
cache = bitmapCachePrepare(sector, FsCache::CACHE_FOR_READ);
@@ -75,8 +75,8 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
-bool ExFatPartition::bitmapModify(uint32_t cluster,
- uint32_t count, bool value) {
+bool ExFatPartition::bitmapModify(uint32_t cluster, uint32_t count,
+ bool value) {
uint32_t sector;
uint32_t start = cluster - 2;
@@ -88,7 +88,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
if (value) {
- if (start <= m_bitmapStart && m_bitmapStart < (start + count)) {
+ if (start <= m_bitmapStart && m_bitmapStart < (start + count)) {
m_bitmapStart = (start + count) < m_clusterCount ? start + count : 0;
@@ -97,8 +97,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
mask = 1 << (start & 7);
- sector = m_clusterHeapStartSector +
- (start >> (m_bytesPerSectorShift + 3));
+ sector = m_clusterHeapStartSector + (start >> (m_bytesPerSectorShift + 3));
i = (start >> 3) & m_sectorMask;
cache = bitmapCachePrepare(sector++, FsCache::CACHE_FOR_WRITE);
@@ -122,7 +121,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
i = 0;
@@ -130,7 +129,7 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) {
uint32_t n = 0;
int8_t status;
- status = fatGet(cluster, & cluster);
+ status = fatGet(cluster, &cluster);
if (status < 0) return 0;
n++;
} while (status);
@@ -203,7 +202,7 @@ bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
setLe32(cache + ((cluster << 2) & m_sectorMask), value);
@@ -233,7 +232,7 @@ bool ExFatPartition::freeChain(uint32_t cluster) {
@@ -250,9 +249,9 @@ int32_t ExFatPartition::freeClusterCount() {
for (size_t i = 0; i < m_bytesPerSector; i++) {
if (cache[i] == 0XFF) {
- usedCount+= 8;
+ usedCount += 8;
} else if (cache[i]) {
- for (uint8_t mask = 1; mask ; mask <<=1) {
+ for (uint8_t mask = 1; mask; mask <<= 1) {
if ((mask & cache[i])) {
usedCount++;
@@ -280,8 +279,8 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
- mbr = reinterpret_cast<MbrSector_t*>
- (dataCachePrepare(0, FsCache::CACHE_FOR_READ));
+ mbr = reinterpret_cast<MbrSector_t*>(
+ dataCachePrepare(0, FsCache::CACHE_FOR_READ));
if (!mbr) {
@@ -293,8 +292,8 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
volStart = getLe32(mp->relativeSectors);
- pbs = reinterpret_cast<pbs_t*>
- (dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
+ pbs = reinterpret_cast<pbs_t*>(
+ dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
if (!pbs) {
@@ -322,7 +321,7 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
m_fatType = FAT_TYPE_EXFAT;
@@ -28,10 +28,10 @@
* \brief ExFatPartition include file.
-#include "../common/SysCall.h"
#include "../common/FsBlockDevice.h"
#include "../common/FsCache.h"
#include "../common/FsStructs.h"
+#include "../common/SysCall.h"
/** Set EXFAT_READ_ONLY non-zero for read only */
#ifndef EXFAT_READ_ONLY
#define EXFAT_READ_ONLY 0
@@ -51,7 +51,7 @@ struct DirPos_t {
/** offset */
uint32_t position;
/** directory is contiguous */
- bool isContiguous;
+ bool isContiguous;
@@ -60,28 +60,26 @@ struct DirPos_t {
class ExFatPartition {
- ExFatPartition() {}
+ ExFatPartition() = default;
/** \return the number of bytes in a cluster. */
- uint32_t bytesPerCluster() const {return m_bytesPerCluster;}
+ uint32_t bytesPerCluster() const { return m_bytesPerCluster; }
/** \return the power of two for bytesPerCluster. */
uint8_t bytesPerClusterShift() const {
return m_bytesPerSectorShift + m_sectorsPerClusterShift;
/** \return the number of bytes in a sector. */
- uint16_t bytesPerSector() const {return m_bytesPerSector;}
+ uint16_t bytesPerSector() const { return m_bytesPerSector; }
/** \return the power of two for bytesPerSector. */
- uint8_t bytesPerSectorShift() const {return m_bytesPerSectorShift;}
+ uint8_t bytesPerSectorShift() const { return m_bytesPerSectorShift; }
/** Clear the cache and returns a pointer to the cache. Not for normal apps.
* \return A pointer to the cache buffer or zero if an error occurs.
- uint8_t* cacheClear() {
- return m_dataCache.clear();
+ uint8_t* cacheClear() { return m_dataCache.clear(); }
/** \return the cluster count for the partition. */
- uint32_t clusterCount() const {return m_clusterCount;}
+ uint32_t clusterCount() const { return m_clusterCount; }
/** \return the cluster heap start sector. */
- uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
+ uint32_t clusterHeapStartSector() const { return m_clusterHeapStartSector; }
/** End access to volume
* \return pointer to sector size buffer for format.
@@ -90,11 +88,11 @@ class ExFatPartition {
return cacheClear();
/** \return the FAT length in sectors */
- uint32_t fatLength() const {return m_fatLength;}
+ uint32_t fatLength() const { return m_fatLength; }
/** \return the FAT start sector number. */
- uint32_t fatStartSector() const {return m_fatStartSector;}
+ uint32_t fatStartSector() const { return m_fatStartSector; }
/** \return Type FAT_TYPE_EXFAT for exFAT partition or zero for error. */
- uint8_t fatType() const {return m_fatType;}
+ uint8_t fatType() const { return m_fatType; }
/** \return free cluster count or -1 if an error occurs. */
int32_t freeClusterCount();
/** Initialize a exFAT partition.
@@ -113,25 +111,25 @@ class ExFatPartition {
* \return true if busy else false.
- bool isBusy() {return m_blockDev->isBusy();}
+ bool isBusy() { return m_blockDev->isBusy(); }
/** \return the root directory start cluster number. */
- uint32_t rootDirectoryCluster() const {return m_rootDirectoryCluster;}
+ uint32_t rootDirectoryCluster() const { return m_rootDirectoryCluster; }
/** \return the root directory length. */
uint32_t rootLength();
/** \return the number of sectors in a cluster. */
- uint32_t sectorsPerCluster() const {return 1UL << m_sectorsPerClusterShift;}
+ uint32_t sectorsPerCluster() const { return 1UL << m_sectorsPerClusterShift; }
uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** \return the power of two for sectors per cluster. */
- uint8_t sectorsPerClusterShift() const {return m_sectorsPerClusterShift;}
+ uint8_t sectorsPerClusterShift() const { return m_sectorsPerClusterShift; }
void checkUpcase(print_t* pr);
bool printDir(print_t* pr, ExFatFile* file);
void dmpBitmap(print_t* pr);
- void dmpCluster(print_t* pr, uint32_t cluster,
- uint32_t offset, uint32_t count);
+ void dmpCluster(print_t* pr, uint32_t cluster, uint32_t offset,
+ uint32_t count);
void dmpFat(print_t* pr, uint32_t start, uint32_t count);
void dmpSector(print_t* pr, uint32_t sector);
bool printVolInfo(print_t* pr);
@@ -149,7 +147,7 @@ class ExFatPartition {
uint8_t* bitmapCachePrepare(uint32_t sector, uint8_t option) {
#if USE_EXFAT_BITMAP_CACHE
return m_bitmapCache.prepare(sector, option);
-#else // USE_EXFAT_BITMAP_CACHE
+#else // USE_EXFAT_BITMAP_CACHE
return m_dataCache.prepare(sector, option);
#endif // USE_EXFAT_BITMAP_CACHE
@@ -162,19 +160,19 @@ class ExFatPartition {
bool cacheSync() {
return m_bitmapCache.sync() && m_dataCache.sync() && syncDevice();
return m_dataCache.sync() && syncDevice();
- void dataCacheDirty() {m_dataCache.dirty();}
- void dataCacheInvalidate() {m_dataCache.invalidate();}
+ void dataCacheDirty() { m_dataCache.dirty(); }
+ void dataCacheInvalidate() { m_dataCache.invalidate(); }
uint8_t* dataCachePrepare(uint32_t sector, uint8_t option) {
- uint32_t dataCacheSector() {return m_dataCache.sector();}
- bool dataCacheSync() {return m_dataCache.sync();}
+ uint32_t dataCacheSector() { return m_dataCache.sector(); }
+ bool dataCacheSync() { return m_dataCache.sync(); }
- uint32_t clusterMask() const {return m_clusterMask;}
+ uint32_t clusterMask() const { return m_clusterMask; }
uint32_t clusterStartSector(uint32_t cluster) {
return m_clusterHeapStartSector +
((cluster - 2) << m_sectorsPerClusterShift);
@@ -185,10 +183,8 @@ class ExFatPartition {
bool fatPut(uint32_t cluster, uint32_t value);
uint32_t chainSize(uint32_t cluster);
bool freeChain(uint32_t cluster);
- uint16_t sectorMask() const {return m_sectorMask;}
- bool syncDevice() {
- return m_blockDev->syncDevice();
+ uint16_t sectorMask() const { return m_sectorMask; }
+ bool syncDevice() { return m_blockDev->syncDevice(); }
bool cacheSafeRead(uint32_t sector, uint8_t* dst) {
return m_dataCache.cacheSafeRead(sector, dst);
@@ -199,7 +195,7 @@ class ExFatPartition {
return m_dataCache.cacheSafeRead(sector, dst, count);
bool cacheSafeWrite(uint32_t sector, const uint8_t* src, size_t count) {
- return m_dataCache.cacheSafeWrite(sector, src, count);
+ return m_dataCache.cacheSafeWrite(sector, src, count);
bool readSector(uint32_t sector, uint8_t* dst) {
return m_blockDev->readSector(sector, dst);
@@ -208,14 +204,14 @@ class ExFatPartition {
return m_blockDev->writeSector(sector, src);
- static const uint8_t m_bytesPerSectorShift = 9;
+ static const uint8_t m_bytesPerSectorShift = 9;
static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift;
static const uint16_t m_sectorMask = m_bytesPerSector - 1;
- FsCache m_bitmapCache;
+ FsCache m_bitmapCache;
- FsCache m_dataCache;
+ FsCache m_dataCache;
uint32_t m_bitmapStart;
uint32_t m_fatStartSector;
uint32_t m_fatLength;
@@ -225,7 +221,7 @@ class ExFatPartition {
uint32_t m_clusterMask;
uint32_t m_bytesPerCluster;
FsBlockDevice* m_blockDev;
- uint8_t m_fatType = 0;
- uint8_t m_sectorsPerClusterShift;
+ uint8_t m_fatType = 0;
+ uint8_t m_sectorsPerClusterShift;
#endif // ExFatPartition_h
@@ -40,6 +40,6 @@ bool ExFatVolume::chdir(const char* path) {
m_vwd = dir;
@@ -60,8 +60,8 @@ class ExFatVolume : public ExFatPartition {
* \param[in] volStart Start sector of volume if part is zero.
- bool begin(FsBlockDevice* dev, bool setCwv = true,
- uint8_t part = 1, uint32_t volStart = 0) {
+ bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1,
+ uint32_t volStart = 0) {
if (!init(dev, part, volStart)) {
@@ -89,7 +89,7 @@ class ExFatVolume : public ExFatPartition {
bool chdir(const char* path);
/** Change global working volume to this volume. */
- void chvol() {m_cwv = this;}
+ void chvol() { m_cwv = this; }
* Test for the existence of a file.
@@ -117,9 +117,7 @@ class ExFatVolume : public ExFatPartition {
- bool ls(print_t* pr, uint8_t flags = 0) {
- return m_vwd.ls(pr, flags);
+ bool ls(print_t* pr, uint8_t flags = 0) { return m_vwd.ls(pr, flags); }
/** List the contents of a directory.
@@ -223,10 +221,8 @@ class ExFatVolume : public ExFatPartition {
- bool ls() {
- return ls(&Serial);
- /** List the directory contents of the volume root to Serial.
+ bool ls() { return ls(&Serial); }
+ /** List the directory contents of the volume root to Serial.
* \param[in] flags The inclusive OR of
@@ -238,9 +234,7 @@ class ExFatVolume : public ExFatPartition {
- bool ls(uint8_t flags) {
+ bool ls(uint8_t flags) { return ls(&Serial, flags); }
/** List the directory contents of a directory to Serial.
* \param[in] path directory to list.
@@ -265,18 +259,14 @@ class ExFatVolume : public ExFatPartition {
* \param[in] path Path for volume working directory.
- bool chdir(const String& path) {
- return chdir(path.c_str());
+ bool chdir(const String& path) { return chdir(path.c_str()); }
- bool exists(const String &path) {
- return exists(path.c_str());
+ bool exists(const String& path) { return exists(path.c_str()); }
/** Make a subdirectory in the volume root directory.
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
@@ -285,7 +275,7 @@ class ExFatVolume : public ExFatPartition {
- bool mkdir(const String &path, bool pFlag = true) {
+ bool mkdir(const String& path, bool pFlag = true) {
return mkdir(path.c_str(), pFlag);
/** open a file
@@ -294,7 +284,7 @@ class ExFatVolume : public ExFatPartition {
* \param[in] oflag open oflag flags.
* \return a ExFile object.
- ExFile open(const String &path, oflag_t oflag = O_RDONLY) {
+ ExFile open(const String& path, oflag_t oflag = O_RDONLY) {
return open(path.c_str(), oflag);
/** Remove a file from the volume root directory.
@@ -303,9 +293,7 @@ class ExFatVolume : public ExFatPartition {
- bool remove(const String& path) {
- return remove(path.c_str());
+ bool remove(const String& path) { return remove(path.c_str()); }
/** Rename a file or subdirectory.
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
@@ -331,9 +319,7 @@ class ExFatVolume : public ExFatPartition {
- bool rmdir(const String& path) {
- return rmdir(path.c_str());
+ bool rmdir(const String& path) { return rmdir(path.c_str()); }
/** Truncate a file to a specified length. The current file position
* will be at the new EOF.
@@ -349,8 +335,8 @@ class ExFatVolume : public ExFatPartition {
friend ExFatFile;
- static ExFatVolume* cwv() {return m_cwv;}
- ExFatFile* vwd() {return &m_vwd;}
+ static ExFatVolume* cwv() { return m_cwv; }
+ ExFatFile* vwd() { return &m_vwd; }
static ExFatVolume* m_cwv;
ExFatFile m_vwd;
@@ -27,11 +27,11 @@
static uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i) {
if (i < 5) {
- return getLe16(ldir->unicode1 + 2*i);
+ return getLe16(ldir->unicode1 + 2 * i);
} else if (i < 11) {
- return getLe16(ldir->unicode2 + 2*i - 10);
+ return getLe16(ldir->unicode2 + 2 * (i - 5));
} else if (i < 13) {
- return getLe16(ldir->unicode3 + 2*i - 22);
+ return getLe16(ldir->unicode3 + 2 * (i - 11));
@@ -58,7 +58,7 @@ static void printHex(print_t* pr, uint8_t w, uint16_t h) {
@@ -73,7 +73,7 @@ static void printHex(print_t* pr, uint16_t val) {
@@ -85,7 +85,7 @@ static void printHex(print_t* pr, uint32_t val) {
-template<typename Uint>
+template <typename Uint>
static void printHexLn(print_t* pr, Uint val) {
printHex(pr, val);
@@ -111,8 +111,8 @@ static bool printFatDir(print_t* pr, DirFat_t* dir) {
printHexLn(pr, dir->attributes);
pr->print(F("caseFlags: 0X"));
printHexLn(pr, dir->caseFlags);
- uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16)
- | getLe16(dir->firstClusterLow);
+ uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) |
+ getLe16(dir->firstClusterLow);
pr->println(fc, HEX);
pr->print(F("fileSize: "));
@@ -175,7 +175,7 @@ void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) {
printHex(pr, 2, h);
- text[i&15] = ' ' <= h && h < 0X7F ? h : '.';
+ text[i & 15] = ' ' <= h && h < 0X7F ? h : '.';
pr->write('\r');
pr->write('\n');
@@ -215,7 +215,7 @@ void FatPartition::dmpSector(print_t* pr, uint32_t sector, uint8_t bits) {
for (uint16_t i = 0; i < m_bytesPerSector;) {
@@ -243,7 +243,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
- uint32_t cluster = nf*start;
+ uint32_t cluster = nf * start;
uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
if (!pc) {
@@ -251,7 +251,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
for (size_t k = 0; k < nf; k++) {
@@ -259,7 +259,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
cluster++;
- uint32_t v = fatType() == 32 ? getLe32(pc + 4*k) : getLe16(pc + 2*k);
+ uint32_t v = fatType() == 32 ? getLe32(pc + 4 * k) : getLe16(pc + 2 * k);
printHex(pr, v);
@@ -42,9 +42,9 @@ bool FatFile::addCluster() {
-#else // USE_FAT_FILE_FLAG_CONTIGUOUS
+#else // USE_FAT_FILE_FLAG_CONTIGUOUS
return m_vol->allocateCluster(m_curCluster, &m_curCluster);
#endif // USE_FAT_FILE_FLAG_CONTIGUOUS
@@ -61,7 +61,7 @@ bool FatFile::addDirCluster() {
// max folder size
- if (m_curPosition >= 512UL*4095) {
+ if (m_curPosition >= 512UL * 4095) {
@@ -82,7 +82,7 @@ bool FatFile::addDirCluster() {
m_curPosition += m_vol->bytesPerCluster();
@@ -105,7 +105,7 @@ bool FatFile::attrib(uint8_t bits) {
@@ -120,7 +120,7 @@ DirFat_t* FatFile::cacheDirEntry(uint8_t action) {
return dir + (m_dirIndex & 0XF);
@@ -137,7 +137,7 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
- for (uint32_t c = m_firstCluster; ; c++) {
+ for (uint32_t c = m_firstCluster;; c++) {
int8_t fg = m_vol->fatGet(c, &next);
if (fg < 0) {
@@ -158,14 +158,14 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
*bgnSector = m_vol->clusterStartSector(m_firstCluster);
- *endSector = m_vol->clusterStartSector(c)
- + m_vol->sectorsPerCluster() - 1;
+ m_vol->clusterStartSector(c) + m_vol->sectorsPerCluster() - 1;
@@ -178,12 +178,12 @@ bool FatFile::createContiguous(const char* path, uint32_t size) {
close();
-bool FatFile::createContiguous(FatFile* dirFile,
- const char* path, uint32_t size) {
+bool FatFile::createContiguous(FatFile* dirFile, const char* path,
+ uint32_t size) {
if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) {
@@ -192,7 +192,7 @@ bool FatFile::createContiguous(FatFile* dirFile,
@@ -213,7 +213,7 @@ bool FatFile::dirEntry(DirFat_t* dst) {
memcpy(dst, dir, sizeof(DirFat_t));
@@ -223,7 +223,7 @@ uint32_t FatFile::dirSize() {
if (isRootFixed()) {
- return FS_DIR_SIZE*m_vol->rootDirEntryCount();
+ return FS_DIR_SIZE * m_vol->rootDirEntryCount();
uint16_t n = 0;
uint32_t c = isRoot32() ? m_vol->rootDirStart() : m_firstCluster;
@@ -234,7 +234,7 @@ uint32_t FatFile::dirSize() {
n += m_vol->sectorsPerCluster();
} while (fg);
- return 512UL*n;
+ return 512UL * n;
int FatFile::fgets(char* str, int num, char* delim) {
@@ -288,7 +288,7 @@ bool FatFile::getAccessDate(uint16_t* pdate) {
*pdate = getLe16(dir.accessDate);
@@ -302,7 +302,7 @@ bool FatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
*ptime = getLe16(dir.createTime);
@@ -316,13 +316,11 @@ bool FatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
*ptime = getLe16(dir.modifyTime);
-bool FatFile::isBusy() {
+bool FatFile::isBusy() { return m_vol->isBusy(); }
bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
FatName_t fname;
@@ -362,7 +360,7 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
@@ -433,7 +431,7 @@ bool FatFile::mkdir(FatFile* parent, FatName_t* fname) {
// write first sector
@@ -485,7 +483,7 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) {
return open(dirFile, &fname, oflag);
@@ -509,7 +507,7 @@ bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) {
if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) {
- if (!dirFile->seekSet(32UL*(index - i))) {
+ if (!dirFile->seekSet(32UL * (index - i))) {
@@ -530,7 +528,7 @@ bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) {
@@ -591,8 +589,8 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
m_dirSector = m_vol->cacheSectorNumber();
// copy first cluster number for directory fields
- firstCluster = ((uint32_t)getLe16(dir->firstClusterHigh) << 16)
+ firstCluster = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) |
if (oflag & O_TRUNC) {
if (firstCluster && !m_vol->freeChain(firstCluster)) {
@@ -611,7 +609,7 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
@@ -638,7 +636,7 @@ bool FatFile::openCwd() {
@@ -655,7 +653,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
while (1) {
// read entry into cache
- index = dirFile->curPosition()/FS_DIR_SIZE;
+ index = dirFile->curPosition() / FS_DIR_SIZE;
DirFat_t* dir = dirFile->readDirCache();
if (!dir) {
if (dirFile->getError()) {
@@ -691,7 +689,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
@@ -706,34 +704,34 @@ bool FatFile::openRoot(FatVolume* vol) {
m_vol = vol;
switch (vol->fatType()) {
#if FAT12_SUPPORT
- case 12:
+ case 12:
#endif // FAT12_SUPPORT
- case 16:
- m_attributes = FILE_ATTR_ROOT_FIXED;
+ case 16:
+ m_attributes = FILE_ATTR_ROOT_FIXED;
- case 32:
- m_attributes = FILE_ATTR_ROOT32;
+ case 32:
+ m_attributes = FILE_ATTR_ROOT32;
- default:
+ default:
// read only
int FatFile::peek() {
- uint32_t curPosition = m_curPosition;
+ uint32_t saveCurPosition = m_curPosition;
@@ -754,13 +752,13 @@ bool FatFile::preAllocate(uint32_t length) {
#if USE_FAT_FILE_FLAG_CONTIGUOUS
// Mark contiguous and insure sync() will update dir entry
m_flags |= FILE_FLAG_PREALLOCATE | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
// insure sync() will update dir entry
@@ -785,7 +783,7 @@ int FatFile::read(void* buf, size_t nbyte) {
} else if (isRootFixed()) {
uint16_t tmp16 =
- FS_DIR_SIZE*m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition;
+ FS_DIR_SIZE * m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition;
if (nbyte > tmp16) {
nbyte = tmp16;
@@ -795,8 +793,8 @@ int FatFile::read(void* buf, size_t nbyte) {
size_t n;
offset = m_curPosition & m_vol->sectorMask(); // offset in sector
- sector = m_vol->rootDirStart()
- + (m_curPosition >> m_vol->bytesPerSectorShift());
+ sector = m_vol->rootDirStart() +
+ (m_curPosition >> m_vol->bytesPerSectorShift());
sectorOfCluster = m_vol->sectorOfCluster(m_curPosition);
if (offset == 0 && sectorOfCluster == 0) {
@@ -826,8 +824,8 @@ int FatFile::read(void* buf, size_t nbyte) {
sector = m_vol->clusterStartSector(m_curCluster) + sectorOfCluster;
- if (offset != 0 || toRead < m_vol->bytesPerSector()
- || sector == m_vol->cacheSectorNumber()) {
+ if (offset != 0 || toRead < m_vol->bytesPerSector() ||
+ sector == m_vol->cacheSectorNumber()) {
// amount to be read from current sector
n = m_vol->bytesPerSector() - offset;
@@ -842,7 +840,7 @@ int FatFile::read(void* buf, size_t nbyte) {
uint8_t* src = pc + offset;
if (!isRootFixed()) {
uint32_t mb = m_vol->sectorsPerCluster() - sectorOfCluster;
@@ -870,20 +868,19 @@ int FatFile::read(void* buf, size_t nbyte) {
return nbyte - toRead;
int8_t FatFile::readDir(DirFat_t* dir) {
- int16_t n;
// if not a directory file or miss-positioned return an error
if (!isDir() || (0X1F & m_curPosition)) {
- n = read(dir, sizeof(DirFat_t));
+ int16_t n = read(dir, sizeof(DirFat_t));
if (n != sizeof(DirFat_t)) {
return n == 0 ? 0 : -1;
@@ -910,7 +907,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
if (i == 0 || !skipReadOk) {
int8_t n = read(&n, 1);
- if (n != 1) {
+ if (n != 1) {
if (n != 0) {
@@ -923,7 +920,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
// return pointer to entry
return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
@@ -935,7 +932,7 @@ bool FatFile::remove(const char* path) {
@@ -1031,7 +1028,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
// store new dot dot
sector = m_vol->clusterStartSector(m_firstCluster);
- uint8_t* pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
+ pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
dir = reinterpret_cast<DirFat_t*>(pc);
@@ -1049,7 +1046,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
@@ -1091,7 +1088,7 @@ bool FatFile::rmdir() {
@@ -1105,7 +1102,7 @@ bool FatFile::rmRfStar() {
// remember position
- index = m_curPosition/FS_DIR_SIZE;
+ index = m_curPosition / FS_DIR_SIZE;
DirFat_t* dir = readDirCache();
@@ -1150,8 +1147,8 @@ bool FatFile::rmRfStar() {
// position to next entry if required
- if (m_curPosition != (32UL*(index + 1))) {
- if (!seekSet(32UL*(index + 1))) {
+ if (m_curPosition != (32UL * (index + 1))) {
+ if (!seekSet(32UL * (index + 1))) {
@@ -1166,7 +1163,7 @@ bool FatFile::rmRfStar() {
@@ -1194,7 +1191,7 @@ bool FatFile::seekSet(uint32_t pos) {
- if (pos <= FS_DIR_SIZE*m_vol->rootDirEntryCount()) {
+ if (pos <= FS_DIR_SIZE * m_vol->rootDirEntryCount()) {
@@ -1225,12 +1222,12 @@ bool FatFile::seekSet(uint32_t pos) {
m_flags &= ~FILE_FLAG_PREALLOCATE;
@@ -1272,27 +1269,20 @@ bool FatFile::sync() {
bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint16_t dirDate;
uint16_t dirTime;
DirFat_t* dir;
@@ -1323,7 +1313,7 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
@@ -1335,7 +1325,7 @@ bool FatFile::truncate() {
if (m_curCluster) {
toFree = 0;
@@ -1367,7 +1357,7 @@ bool FatFile::truncate() {
@@ -1414,7 +1404,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
int8_t fg = m_vol->fatGet(m_curCluster, &m_curCluster);
@@ -1442,8 +1432,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
// sector for data write
- uint32_t sector = m_vol->clusterStartSector(m_curCluster)
- + sectorOfCluster;
+ uint32_t sector = m_vol->clusterStartSector(m_curCluster) + sectorOfCluster;
if (sectorOffset != 0 || nToWrite < m_vol->bytesPerSector()) {
// partial sector - must use cache
@@ -1455,7 +1444,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
if (sectorOffset == 0 &&
- (m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) {
+ (m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) {
// start of new sector don't need to read into cache
cacheOption = FsCache::CACHE_RESERVE_FOR_WRITE;
@@ -1477,7 +1466,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
- } else if (nToWrite >= 2*m_vol->bytesPerSector()) {
+ } else if (nToWrite >= 2 * m_vol->bytesPerSector()) {
uint32_t maxSectors = m_vol->sectorsPerCluster() - sectorOfCluster;
uint32_t nSector = nToWrite >> m_vol->bytesPerSectorShift();
@@ -1512,7 +1501,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
@@ -28,9 +28,10 @@
* \brief FatFile class
-#include <string.h>
-#include <stddef.h>
+#include <stddef.h>
#include "../common/FsApiConstants.h"
#include "../common/FsDateTime.h"
@@ -38,28 +39,6 @@
#include "FatPartition.h"
class FatVolume;
-// Stuff to store strings in AVR flash.
-#ifdef __AVR__
-#include <avr/pgmspace.h>
-#ifndef PSTR
-/** store literal string in flash for ARM */
-#define PSTR(x) (x)
-#endif // PSTR
-#ifndef pgm_read_byte
-/** read 8-bits from flash for ARM */
-#define pgm_read_byte(addr) (*(const unsigned char*)(addr))
-#endif // pgm_read_byte
-#ifndef pgm_read_word
-/** read 16-bits from flash for ARM */
-#define pgm_read_word(addr) (*(const uint16_t*)(addr))
-#endif // pgm_read_word
-#ifndef PROGMEM
-/** store in flash for ARM */
-#define PROGMEM
-#endif // PROGMEM
-#endif // __AVR__
* \struct FatPos_t
* \brief Internal type for file position - do not use in user apps.
@@ -105,7 +84,7 @@ class FatSfn_t {
#if USE_LONG_FILE_NAMES
/** Internal class for file names */
typedef FatLfn_t FatName_t;
-#else // USE_LONG_FILE_NAMES
+#else // USE_LONG_FILE_NAMES
typedef FatSfn_t FatName_t;
#endif // USE_LONG_FILE_NAMES
@@ -116,14 +95,11 @@ const uint8_t FNAME_FLAG_LOST_CHARS = 0X01;
const uint8_t FNAME_FLAG_MIXED_CASE = 0X02;
/** LFN entries are required for file name. */
const uint8_t FNAME_FLAG_NEED_LFN =
- FNAME_FLAG_LOST_CHARS | FNAME_FLAG_MIXED_CASE;
+ FNAME_FLAG_LOST_CHARS | FNAME_FLAG_MIXED_CASE;
/** Filename base-name is all lower case */
const uint8_t FNAME_FLAG_LC_BASE = FAT_CASE_LC_BASE;
/** Filename extension is all lower case. */
const uint8_t FNAME_FLAG_LC_EXT = FAT_CASE_LC_EXT;
-#if FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
-#error FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
-#endif // FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
* \class FatFile
@@ -140,9 +116,7 @@ class FatFile {
- FatFile(const char* path, oflag_t oflag) {
+ FatFile(const char* path, oflag_t oflag) { open(path, oflag); }
/** Destructor */
~FatFile() {
@@ -155,7 +129,7 @@ class FatFile {
* \return true if a file is open.
- operator bool() const {return isOpen();}
+ operator bool() const { return isOpen(); }
@@ -190,13 +164,9 @@ class FatFile {
return isFile() ? fileSize() - curPosition() : 0;
/** Set writeError to zero */
@@ -221,8 +191,7 @@ class FatFile {
- bool createContiguous(FatFile* dirFile,
- const char* path, uint32_t size);
+ bool createContiguous(FatFile* dirFile, const char* path, uint32_t size);
/** Create and open a new contiguous file of a specified size.
* \param[in] path A path with a valid file name.
@@ -232,10 +201,10 @@ class FatFile {
bool createContiguous(const char* path, uint32_t size);
- uint32_t curPosition() const {return m_curPosition;}
+ uint32_t curPosition() const { return m_curPosition; }
/** Return a file's directory entry.
* \param[out] dir Location for return of the file's directory entry.
@@ -244,7 +213,7 @@ class FatFile {
bool dirEntry(DirFat_t* dir);
- uint16_t dirIndex() const {return m_dirIndex;}
+ uint16_t dirIndex() const { return m_dirIndex; }
/** \return The number of bytes allocated to a directory or zero
* if an error occurs.
@@ -297,13 +266,13 @@ class FatFile {
- uint32_t fileSize() const {return m_fileSize;}
+ uint32_t fileSize() const { return m_fileSize; }
/** \return first sector of file or zero for empty file. */
- uint32_t firstBlock() const {return firstSector();}
+ uint32_t firstBlock() const { return firstSector(); }
/** set position for streams
* \param[in] pos struct with value for new position
@@ -340,7 +309,7 @@ class FatFile {
- uint8_t getError() const {return m_error;}
+ uint8_t getError() const { return m_error; }
@@ -388,9 +357,7 @@ class FatFile {
size_t getSFN(char* name, size_t size);
* Check for device busy.
@@ -398,37 +365,37 @@ class FatFile {
- /** \return True if the file is contiguous. */
+ /** \return True if the file is contiguous. */
/** \return True if this is a hidden file. */
/** \return true if this file has a Long File Name. */
- bool isLFN() const {return m_lfnOrd;}
+ bool isLFN() const { return m_lfnOrd; }
/** \return True if this is an open file/directory. */
/** \return True if this is the FAT32 root directory. */
- bool isRoot32() const {return m_attributes & FILE_ATTR_ROOT32;}
+ bool isRoot32() const { return m_attributes & FILE_ATTR_ROOT32; }
/** \return True if this is the FAT12 of FAT16 root directory. */
- bool isRootFixed() const {return m_attributes & FILE_ATTR_ROOT_FIXED;}
+ bool isRootFixed() const { return m_attributes & FILE_ATTR_ROOT_FIXED; }
@@ -553,7 +520,7 @@ class FatFile {
@@ -615,9 +582,7 @@ class FatFile {
* \return The number of characters printed.
- size_t printAccessDateTime(print_t* pr) {
- return printAccessDate(pr);
+ size_t printAccessDateTime(print_t* pr) { return printAccessDate(pr); }
/** Print a file's creation date and time
@@ -676,7 +641,7 @@ class FatFile {
@@ -819,9 +784,7 @@ class FatFile {
bool rename(FatFile* dirFile, const char* newPath);
@@ -854,9 +817,7 @@ class FatFile {
- bool seekCur(int32_t offset) {
+ bool seekCur(int32_t offset) { return seekSet(m_curPosition + offset); }
@@ -927,24 +888,18 @@ class FatFile {
- bool truncate(uint32_t length) {
+ bool truncate(uint32_t length) { return seekSet(length) && truncate(); }
* \return +1 for success or -1 for failure.
- size_t write(uint8_t b) {
- return write(&b, 1);
@@ -973,16 +928,12 @@ class FatFile {
- return FatFile::printName(&Serial);
+ size_t printName() { return FatFile::printName(&Serial); }
@@ -1000,8 +951,7 @@ class FatFile {
/** A FAT32 root directory */
static const uint8_t FILE_ATTR_ROOT32 = 0X80;
/** Entry is for root. */
- static const uint8_t FILE_ATTR_ROOT =
- FILE_ATTR_ROOT_FIXED | FILE_ATTR_ROOT32;
+ static const uint8_t FILE_ATTR_ROOT = FILE_ATTR_ROOT_FIXED | FILE_ATTR_ROOT32;
/** Directory type bits */
static const uint8_t FILE_ATTR_DIR = FILE_ATTR_SUBDIR | FILE_ATTR_ROOT;
@@ -1010,16 +960,16 @@ class FatFile {
bool addCluster();
bool addDirCluster();
DirFat_t* cacheDir(uint16_t index) {
- return seekSet(32UL*index) ? readDirCache() : nullptr;
+ return seekSet(32UL * index) ? readDirCache() : nullptr;
DirFat_t* cacheDirEntry(uint8_t action);
bool cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd);
bool createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd);
uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i);
- uint8_t lfnChecksum(uint8_t* name) {
+ uint8_t lfnChecksum(const uint8_t* name) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
- sum = (((sum & 1) << 7) | (sum >> 1)) + name[i];
+ sum = (((sum & 1) << 7) | (sum >> 1)) + name[i];
return sum;
@@ -1043,26 +993,26 @@ class FatFile {
// treat curPosition as valid length.
static const uint8_t FILE_FLAG_PREALLOCATE = 0X20;
// file is contiguous
// sync of directory entry required
// private data
- uint8_t m_error = 0; // Error bits.
- uint8_t m_flags = 0; // See above for definition of m_flags bits
- uint8_t m_lfnOrd;
- uint16_t m_dirIndex; // index of directory entry in dir file
- FatVolume* m_vol; // volume where file is located
- uint32_t m_dirCluster;
- uint32_t m_curCluster; // cluster for current file position
- uint32_t m_curPosition; // current file position
- uint32_t m_dirSector; // sector for this files directory entry
- uint32_t m_fileSize; // file size in bytes
- uint32_t m_firstCluster; // first cluster of file
+ uint8_t m_error = 0; // Error bits.
+ uint8_t m_flags = 0; // See above for definition of m_flags bits
+ uint8_t m_lfnOrd;
+ uint16_t m_dirIndex; // index of directory entry in dir file
+ FatVolume* m_vol; // volume where file is located
+ uint32_t m_dirCluster;
+ uint32_t m_curCluster; // cluster for current file position
+ uint32_t m_curPosition; // current file position
+ uint32_t m_dirSector; // sector for this files directory entry
+ uint32_t m_fileSize; // file size in bytes
+ uint32_t m_firstCluster; // first cluster of file
@@ -1072,7 +1022,7 @@ class FatFile {
class File32 : public StreamFile<FatFile, uint32_t> {
@@ -24,23 +24,17 @@
#define DBG_FILE "FatFileLFN.cpp"
#include "FatLib.h"
-static bool isLower(char c) {
- return 'a' <= c && c <= 'z';
+static bool isLower(char c) { return 'a' <= c && c <= 'z'; }
-static bool isUpper(char c) {
- return 'A' <= c && c <= 'Z';
+static bool isUpper(char c) { return 'A' <= c && c <= 'Z'; }
// A bit smaller than toupper in AVR 328.
-inline char toUpper(char c) {
- return isLower(c) ? c - 'a' + 'A' : c;
+inline char toUpper(char c) { return isLower(c) ? c - 'a' + 'A' : c; }
* Store a 16-bit long file name character.
@@ -51,24 +45,13 @@ inline char toUpper(char c) {
static void putLfnChar(DirLfn_t* ldir, uint8_t i, uint16_t c) {
- setLe16(ldir->unicode1 + 2*i, c);
+ setLe16(ldir->unicode1 + 2 * i, c);
- setLe16(ldir->unicode2 + 2*i -10, c);
+ setLe16(ldir->unicode2 + 2 * (i - 5), c);
- setLe16(ldir->unicode3 + 2*i - 22, c);
+ setLe16(ldir->unicode3 + 2 * (i - 11), c);
-// Daniel Bernstein University of Illinois at Chicago.
-// Original had + instead of ^
-__attribute__((unused))
-static uint16_t Bernstein(const char* bgn, const char* end, uint16_t hash) {
- while (bgn < end) {
- // hash = hash * 33 ^ str[i];
- hash = ((hash << 5) + hash) ^ (*bgn++);
- return hash;
bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
FatFile dir = *this;
@@ -95,7 +78,7 @@ bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
if (toUpcase(u) != toUpcase(cp)) {
if (u > 0X7F || toUpper(u) != toUpper(fname->getch())) {
@@ -104,7 +87,7 @@ bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
@@ -141,13 +124,13 @@ bool FatFile::createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
bool FatFile::makeSFN(FatLfn_t* fname) {
bool is83;
-// char c;
+ // char c;
uint8_t c;
uint8_t bit = FAT_CASE_LC_BASE;
uint8_t lc = 0;
@@ -170,15 +153,17 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
// Not 8.3 if starts with dot.
is83 = *ptr == '.' ? false : true;
// Skip leading dots.
- for (; *ptr == '.'; ptr++) {}
+ for (; *ptr == '.'; ptr++) {
// Find last dot.
- for (dot = end - 1; dot > ptr && *dot != '.'; dot--) {}
+ for (dot = end - 1; dot > ptr && *dot != '.'; dot--) {
for (; ptr < end; ptr++) {
c = *ptr;
if (c == '.' && ptr == dot) {
- in = 10; // Max index for full 8.3 name.
- i = 8; // Place for extension.
+ in = 10; // Max index for full 8.3 name.
+ i = 8; // Place for extension.
bit = FAT_CASE_LC_EXT; // bit for extension.
if (sfnReservedChar(c)) {
@@ -192,7 +177,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
if (i > in) {
is83 = false;
if (in == 10 || ptr > dot) {
- // Done - extension longer than three characters or no extension.
+ // Done - extension longer than three characters or no extension.
// Skip to dot.
@@ -216,7 +201,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
if (is83) {
- fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
+ fname->flags = (lc & uc) ? FNAME_FLAG_MIXED_CASE : lc;
fname->flags = FNAME_FLAG_LOST_CHARS;
fname->sfn[fname->seqPos] = '~';
@@ -224,7 +209,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
@@ -238,17 +223,13 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
for (uint8_t seq = FIRST_HASH_SEQ; seq < 100; seq++) {
- DBG_WARN_IF(seq > FIRST_HASH_SEQ);
-#ifdef USE_LFN_HASH
- hex = Bernstein(fname->begin, fname->end, seq);
-#else
+ DBG_WARN_IF(seq > FIRST_HASH_SEQ);
hex += millis();
-#endif
if (pos > 3) {
// Make space in name for ~HHHH.
pos = 3;
- for (uint8_t i = pos + 4 ; i > pos; i--) {
+ for (uint8_t i = pos + 4; i > pos; i--) {
uint8_t h = hex & 0XF;
fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
hex >>= 4;
@@ -277,25 +258,26 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
// fall inti fail - too many tries.
bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
bool fnameFound = false;
uint8_t lfnOrd = 0;
- uint8_t freeNeed;
uint8_t freeFound = 0;
+ uint8_t freeNeed;
uint8_t order = 0;
uint8_t checksum = 0;
uint8_t nameOrd;
- uint16_t freeIndex = 0;
uint16_t curIndex;
uint16_t date;
+ uint16_t freeIndex = 0;
+ uint16_t freeTotal;
DirLfn_t* ldir;
@@ -306,11 +288,11 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
// Number of directory entries needed.
- nameOrd = (fname->len + 12)/13;
- freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + nameOrd : 1;
+ nameOrd = (fname->len + 12) / 13;
+ freeNeed = (fname->flags & FNAME_FLAG_NEED_LFN) ? 1 + nameOrd : 1;
dirFile->rewind();
- curIndex = dirFile->m_curPosition/FS_DIR_SIZE;
+ curIndex = dirFile->m_curPosition / FS_DIR_SIZE;
dir = dirFile->readDirCache();
@@ -343,7 +325,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
if (!lfnOrd) {
order = ldir->order & 0X1F;
if (order != nameOrd ||
- (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) {
+ (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) {
lfnOrd = nameOrd;
@@ -376,7 +358,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
@@ -384,7 +366,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
goto open;
// don't create unless O_CREAT and write mode
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
@@ -407,13 +389,16 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
freeFound++;
- while (freeFound < freeNeed) {
+ // Loop handles the case of huge filename and cluster size one.
+ freeTotal = freeFound;
+ while (freeTotal < freeNeed) {
// Will fail if FAT16 root.
if (!dirFile->addDirCluster()) {
- freeFound += vol->dirEntriesPerCluster();
+ // 16-bit freeTotal needed for large cluster size.
+ freeTotal += vol->dirEntriesPerCluster();
if (fnameFound) {
if (!dirFile->makeUniqueSfn(fname)) {
@@ -456,7 +441,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
// Force write of entry to device.
vol->cacheDirty();
- open:
+open:
// open entry in cache.
if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
@@ -464,12 +449,12 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
-bool FatFile::parsePathName(const char* path,
- FatLfn_t* fname, const char** ptr) {
+bool FatFile::parsePathName(const char* path, FatLfn_t* fname,
size_t len = 0;
@@ -491,7 +476,7 @@ bool FatFile::parsePathName(const char* path,
uint8_t cp = *path++;
if (cp >= 0X80 || lfnReservedChar(cp)) {
@@ -510,11 +495,12 @@ bool FatFile::parsePathName(const char* path,
return makeSFN(fname);
@@ -570,8 +556,7 @@ bool FatFile::remove() {
if (ldir->attributes != FAT_ATTRIB_LONG_NAME ||
- order != (ldir->order & 0X1F) ||
- checksum != ldir->checksum) {
+ order != (ldir->order & 0X1F) || checksum != ldir->checksum) {
@@ -589,7 +574,7 @@ bool FatFile::remove() {
// Fall into fail.
#endif // #if USE_LONG_FILE_NAMES
@@ -67,7 +67,7 @@ bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
@@ -99,7 +99,7 @@ size_t FatFile::printModifyDateTime(print_t* pr) {
size_t FatFile::printFileSize(print_t* pr) {
char buf[11];
- char *ptr = buf + sizeof(buf);
+ char* ptr = buf + sizeof(buf);
*--ptr = 0;
ptr = fmtBase10(ptr, fileSize());
while (ptr > buf) {
@@ -46,7 +46,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
dir = dirFile->readDirCache(true);
- if (dirFile->getError()) {
+ if (dirFile->getError()) {
@@ -143,7 +143,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
return openCachedEntry(dirFile, index, oflag, 0);
@@ -169,7 +169,7 @@ bool FatFile::openExistingSFN(const char* path) {
} while (*path);
@@ -192,9 +192,9 @@ bool FatFile::openSFN(FatSfn_t* fname) {
if (isFatFileOrSubdir(&dir) && memcmp(fname->sfn, dir.name, 11) == 0) {
- uint16_t dirIndex = (m_curPosition - 32) >> 5;
- uint32_t dirCluster = m_firstCluster;
- memset(this, 0 , sizeof(FatFile));
+ uint16_t saveDirIndex = (m_curPosition - 32) >> 5;
+ uint32_t saveDirCluster = m_firstCluster;
+ memset(this, 0, sizeof(FatFile));
m_attributes = dir.attributes & FS_ATTRIB_COPY;
if (isFatFile(&dir)) {
@@ -209,9 +209,9 @@ bool FatFile::openSFN(FatSfn_t* fname) {
m_firstCluster |= getLe16(dir.firstClusterLow);
m_fileSize = getLe32(dir.fileSize);
- m_dirCluster = dirCluster;
+ m_dirCluster = saveDirCluster;
- m_dirIndex = dirIndex;
+ m_dirIndex = saveDirIndex;
} else if (isFatLongName(&dir)) {
ldir = reinterpret_cast<DirLfn_t*>(&dir);
@@ -223,7 +223,7 @@ bool FatFile::openSFN(FatSfn_t* fname) {
@@ -269,14 +269,14 @@ bool FatFile::parsePathName(const char* path, FatSfn_t* fname,
// Set base-name and extension bits.
- fname->flags = lc & uc ? 0 : lc;
+ fname->flags = (lc & uc) ? 0 : lc;
while (isDirSeparator(*path)) {
#if !USE_LONG_FILE_NAMES
@@ -309,7 +309,7 @@ bool FatFile::remove() {
#endif // !USE_LONG_FILE_NAMES
@@ -31,18 +31,20 @@ uint16_t const BU16 = 128;
uint16_t const BU32 = 8192;
// Assume 512 byte sectors.
-const uint16_t SECTORS_PER_MB = 0X100000/BYTES_PER_SECTOR;
+const uint16_t SECTORS_PER_MB = 0X100000 / BYTES_PER_SECTOR;
const uint16_t FAT16_ROOT_ENTRY_COUNT = 512;
const uint16_t FAT16_ROOT_SECTOR_COUNT =
- 32*FAT16_ROOT_ENTRY_COUNT/BYTES_PER_SECTOR;
+ 32 * FAT16_ROOT_ENTRY_COUNT / BYTES_PER_SECTOR;
#define PRINT_FORMAT_PROGRESS 1
#define writeMsg(str)
-#define writeMsg(str) if (m_pr) m_pr->print(F(str))
+#define writeMsg(str) \
+ if (m_pr) m_pr->print(F(str))
-#define writeMsg(str) if (m_pr) m_pr->write(str)
+ if (m_pr) m_pr->write(str)
bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
@@ -51,7 +53,7 @@ bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
m_secBuf = secBuf;
m_pr = pr;
m_sectorCount = m_dev->sectorCount();
- m_capacityMB = (m_sectorCount + SECTORS_PER_MB - 1)/SECTORS_PER_MB;
+ m_capacityMB = (m_sectorCount + SECTORS_PER_MB - 1) / SECTORS_PER_MB;
if (m_capacityMB <= 6) {
writeMsg("Card is too small.\r\n");
@@ -87,9 +89,9 @@ bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
writeMsg("Writing FAT ");
for (uint32_t i = 1; i < sectorCount; i++) {
if (!m_dev->writeSector(m_fatStart + i, m_secBuf)) {
- if ((i%(sectorCount/32)) == 0) {
+ if ((i % (sectorCount / 32)) == 0) {
writeMsg(".");
@@ -131,13 +133,12 @@ void FatFormatter::initPbs() {
bool FatFormatter::makeFat16() {
uint32_t nc;
- uint32_t r;
PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
- for (m_dataStart = 2*BU16; ; m_dataStart += BU16) {
- nc = (m_sectorCount - m_dataStart)/m_sectorsPerCluster;
- m_fatSize = (nc + 2 + (BYTES_PER_SECTOR/2) - 1)/(BYTES_PER_SECTOR/2);
- r = BU16 + 1 + 2*m_fatSize + FAT16_ROOT_SECTOR_COUNT;
+ for (m_dataStart = 2 * BU16;; m_dataStart += BU16) {
+ nc = (m_sectorCount - m_dataStart) / m_sectorsPerCluster;
+ m_fatSize = (nc + 2 + (BYTES_PER_SECTOR / 2) - 1) / (BYTES_PER_SECTOR / 2);
+ uint32_t r = BU16 + 1 + 2 * m_fatSize + FAT16_ROOT_SECTOR_COUNT;
if (m_dataStart >= r) {
m_relativeSectors = m_dataStart - r + BU16;
@@ -150,8 +151,8 @@ bool FatFormatter::makeFat16() {
m_reservedSectorCount = 1;
m_fatStart = m_relativeSectors + m_reservedSectorCount;
- m_totalSectors = nc*m_sectorsPerCluster
- + 2*m_fatSize + m_reservedSectorCount + 32;
+ m_totalSectors =
+ nc * m_sectorsPerCluster + 2 * m_fatSize + m_reservedSectorCount + 32;
if (m_totalSectors < 65536) {
m_partType = 0X04;
@@ -183,15 +184,14 @@ bool FatFormatter::makeFat16() {
bool FatFormatter::makeFat32() {
FsInfo_t* fsi = reinterpret_cast<FsInfo_t*>(m_secBuf);
m_relativeSectors = BU32;
- for (m_dataStart = 2*BU32; ; m_dataStart += BU32) {
- m_fatSize = (nc + 2 + (BYTES_PER_SECTOR/4) - 1)/(BYTES_PER_SECTOR/4);
- r = m_relativeSectors + 9 + 2*m_fatSize;
+ for (m_dataStart = 2 * BU32;; m_dataStart += BU32) {
+ m_fatSize = (nc + 2 + (BYTES_PER_SECTOR / 4) - 1) / (BYTES_PER_SECTOR / 4);
+ uint32_t r = m_relativeSectors + 9 + 2 * m_fatSize;
@@ -201,9 +201,9 @@ bool FatFormatter::makeFat32() {
writeMsg("Bad cluster count\r\n");
- m_reservedSectorCount = m_dataStart - m_relativeSectors - 2*m_fatSize;
+ m_reservedSectorCount = m_dataStart - m_relativeSectors - 2 * m_fatSize;
- m_totalSectors = nc*m_sectorsPerCluster + m_dataStart - m_relativeSectors;
+ m_totalSectors = nc * m_sectorsPerCluster + m_dataStart - m_relativeSectors;
// type depends on address of end sector
// max CHS has lba = 16450560 = 1024*255*63
if ((m_relativeSectors + m_totalSectors) <= 16450560) {
@@ -232,14 +232,14 @@ bool FatFormatter::makeFat32() {
pbs->bpb.bpb32.volumeType[2] = 'T';
pbs->bpb.bpb32.volumeType[3] = '3';
pbs->bpb.bpb32.volumeType[4] = '2';
- if (!m_dev->writeSector(m_relativeSectors, m_secBuf) ||
+ if (!m_dev->writeSector(m_relativeSectors, m_secBuf) ||
!m_dev->writeSector(m_relativeSectors + 6, m_secBuf)) {
// write extra boot area and backup
- memset(m_secBuf, 0 , BYTES_PER_SECTOR);
+ memset(m_secBuf, 0, BYTES_PER_SECTOR);
setLe32(fsi->trailSignature, FSINFO_TRAIL_SIGNATURE);
- if (!m_dev->writeSector(m_relativeSectors + 2, m_secBuf) ||
+ if (!m_dev->writeSector(m_relativeSectors + 2, m_secBuf) ||
!m_dev->writeSector(m_relativeSectors + 8, m_secBuf)) {
@@ -248,11 +248,11 @@ bool FatFormatter::makeFat32() {
setLe32(fsi->structSignature, FSINFO_STRUCT_SIGNATURE);
setLe32(fsi->freeCount, 0XFFFFFFFF);
setLe32(fsi->nextFree, 0XFFFFFFFF);
- if (!m_dev->writeSector(m_relativeSectors + 1, m_secBuf) ||
+ if (!m_dev->writeSector(m_relativeSectors + 1, m_secBuf) ||
!m_dev->writeSector(m_relativeSectors + 7, m_secBuf)) {
- return initFatDir(32, 2*m_fatSize + m_sectorsPerCluster);
+ return initFatDir(32, 2 * m_fatSize + m_sectorsPerCluster);
bool FatFormatter::writeMbr() {
@@ -262,8 +262,8 @@ bool FatFormatter::writeMbr() {
#if USE_LBA_TO_CHS
lbaToMbrChs(mbr->part->beginCHS, m_capacityMB, m_relativeSectors);
lbaToMbrChs(mbr->part->endCHS, m_capacityMB,
- m_relativeSectors + m_totalSectors -1);
-#else // USE_LBA_TO_CHS
+ m_relativeSectors + m_totalSectors - 1);
+#else // USE_LBA_TO_CHS
mbr->part->beginCHS[0] = 1;
mbr->part->beginCHS[1] = 1;
mbr->part->beginCHS[2] = 0;
@@ -24,14 +24,16 @@
#ifndef FatFormatter_h
#define FatFormatter_h
* \class FatFormatter
* \brief Format a FAT volume.
class FatFormatter {
+ FatFormatter() = default;
* Format a FAT volume.
#ifndef FatLib_h
#define FatLib_h
-#include "FatVolume.h"
#include "FatFormatter.h"
+#include "FatVolume.h"
#endif // FatLib_h
@@ -29,11 +29,11 @@
uint16_t FatFile::getLfnChar(DirLfn_t* ldir, uint8_t i) {
DBG_HALT_IF(i >= 13);
@@ -87,11 +87,11 @@ size_t FatFile::getName7(char* name, size_t size) {
name[n++] = c >= 0X7F ? '?' : c;
name[0] = '\0';
@@ -105,8 +105,8 @@ size_t FatFile::getName8(char* name, size_t size) {
if (!isLFN()) {
return getSFN(name, size);
@@ -156,11 +156,11 @@ size_t FatFile::getName8(char* name, size_t size) {
@@ -217,7 +217,7 @@ size_t FatFile::getSFN(char* name, size_t size) {
name[j] = '\0';
return j;
@@ -227,10 +227,10 @@ size_t FatFile::printName(print_t* pr) {
return printSFN(pr);
#elif USE_UTF8_LONG_NAMES
-# else // USE_LONG_FILE_NAMES
size_t FatFile::printName7(print_t* pr) {
FatFile dir;
@@ -240,8 +240,8 @@ size_t FatFile::printName7(print_t* pr) {
uint8_t i;
@@ -274,11 +274,11 @@ size_t FatFile::printName7(print_t* pr) {
-size_t FatFile::printName8(print_t *pr) {
+size_t FatFile::printName8(print_t* pr) {
@@ -287,8 +287,8 @@ size_t FatFile::printName8(print_t *pr) {
char* end = buf + sizeof(buf);
@@ -309,7 +309,7 @@ size_t FatFile::printName8(print_t *pr) {
for (uint8_t i = 0; i < 13; i++) {
- uint16_t c = getLfnChar(ldir, i);;
+ uint16_t c = getLfnChar(ldir, i);
@@ -334,12 +334,12 @@ size_t FatFile::printName8(print_t *pr) {
@@ -351,6 +351,6 @@ size_t FatFile::printSFN(print_t* pr) {
return pr->write(name);
@@ -84,7 +84,7 @@ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) {
*next = find;
@@ -149,7 +149,7 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) {
*firstCluster = bgnCluster;
@@ -176,7 +176,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
next = getLe32(pc + offset);
} else if (fatType() == 16) {
cluster &= 0XFFFF;
- sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) );
+ sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1));
pc = fatCachePrepare(sector, FsCache::CACHE_FOR_READ);
@@ -216,7 +216,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
*value = next;
return 1;
@@ -245,7 +245,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
if (fatType() == 16) {
pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
@@ -293,7 +293,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
@@ -322,7 +322,7 @@ bool FatPartition::freeChain(uint32_t cluster) {
@@ -357,7 +357,7 @@ int32_t FatPartition::freeClusterCount() {
- n = fatType() == 16 ? m_bytesPerSector/2 : m_bytesPerSector/4;
+ n = fatType() == 16 ? m_bytesPerSector / 2 : m_bytesPerSector / 4;
if (todo < n) {
n = todo;
@@ -386,12 +386,12 @@ int32_t FatPartition::freeClusterCount() {
setFreeClusterCount(free);
return free;
bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
- uint32_t clusterCount;
+ uint32_t countOfClusters;
uint32_t totalSectors;
m_blockDev = dev;
pbs_t* pbs;
@@ -411,8 +411,8 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
@@ -424,8 +424,8 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
@@ -458,8 +458,10 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
// directory start for FAT16 dataStart for FAT32
m_rootDirStart = m_fatStartSector + 2 * m_sectorsPerFat;
// data start for FAT16 and FAT32
- m_dataStartSector = m_rootDirStart +
- ((FS_DIR_SIZE*m_rootDirEntryCount + m_bytesPerSector - 1)/m_bytesPerSector);
+ m_dataStartSector =
+ m_rootDirStart +
+ ((FS_DIR_SIZE * m_rootDirEntryCount + m_bytesPerSector - 1) /
+ m_bytesPerSector);
// total sectors for FAT16 or FAT32
totalSectors = getLe16(bpb->totalSectors16);
@@ -467,22 +469,22 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
totalSectors = getLe32(bpb->totalSectors32);
// total data sectors
- clusterCount = totalSectors - (m_dataStartSector - volStart);
+ countOfClusters = totalSectors - (m_dataStartSector - volStart);
// divide by cluster size to get cluster count
- clusterCount >>= m_sectorsPerClusterShift;
- m_lastCluster = clusterCount + 1;
+ countOfClusters >>= m_sectorsPerClusterShift;
+ m_lastCluster = countOfClusters + 1;
// Indicate unknown number of free clusters.
setFreeClusterCount(-1);
// FAT type is determined by cluster count
- if (clusterCount < 4085) {
+ if (countOfClusters < 4085) {
m_fatType = 12;
if (!FAT12_SUPPORT) {
- } else if (clusterCount < 65525) {
+ } else if (countOfClusters < 65525) {
m_fatType = 16;
m_rootDirStart = getLe32(bpb->fat32RootCluster);
@@ -494,6 +496,6 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
#endif // USE_SEPARATE_FAT_CACHE
@@ -29,10 +29,11 @@
* \brief FatPartition class
/** Type for FAT12 partition */
const uint8_t FAT_TYPE_FAT12 = 12;
@@ -52,7 +53,7 @@ class FatPartition {
/** Create an instance of FatPartition
- FatPartition() {}
+ FatPartition() = default;
/** \return The shift count required to multiply by bytesPerCluster. */
@@ -63,50 +64,32 @@ class FatPartition {
return m_bytesPerSector << m_sectorsPerClusterShift;
/** \return Number of bytes per sector. */
- uint16_t bytesPerSector() const {
- return m_bytesPerSector;
- uint8_t bytesPerSectorShift() const {
- return m_bytesPerSectorShift;
- /** \return Number of directory entries per sector. */
+ /** \return Number of directory entries per cluster. */
uint16_t dirEntriesPerCluster() const {
- return m_sectorsPerCluster*(m_bytesPerSector/FS_DIR_SIZE);
+ return m_sectorsPerCluster * (m_bytesPerSector / FS_DIR_SIZE);
/** \return Mask for sector offset. */
- uint16_t sectorMask() const {
- return m_sectorMask;
/** \return The volume's cluster size in sectors. */
- uint8_t sectorsPerCluster() const {
- return m_sectorsPerCluster;
+ uint8_t sectorsPerCluster() const { return m_sectorsPerCluster; }
uint8_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
/** \return The number of sectors in one FAT. */
- uint32_t sectorsPerFat() const {
- return m_sectorsPerFat;
+ uint32_t sectorsPerFat() const { return m_sectorsPerFat; }
- return m_cache.clear();
+ uint8_t* cacheClear() { return m_cache.clear(); }
/** \return The total number of clusters in the volume. */
- uint32_t clusterCount() const {
- return m_lastCluster - 1;
+ uint32_t clusterCount() const { return m_lastCluster - 1; }
/** \return The shift count required to multiply by sectorsPerCluster. */
- uint8_t sectorsPerClusterShift() const {
- return m_sectorsPerClusterShift;
/** \return The logical sector number for the start of file data. */
- uint32_t dataStartSector() const {
- return m_dataStartSector;
+ uint32_t dataStartSector() const { return m_dataStartSector; }
@@ -115,17 +98,11 @@ class FatPartition {
/** \return The number of File Allocation Tables. */
- uint8_t fatCount() const {
- return 2;
+ uint8_t fatCount() const { return 2; }
/** \return The logical sector number for the start of the first FAT. */
- uint32_t fatStartSector() const {
- return m_fatStartSector;
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
- uint8_t fatType() const {
- return m_fatType;
/** Initialize a FAT partition.
@@ -141,17 +118,13 @@ class FatPartition {
bool init(FsBlockDevice* dev, uint8_t part = 1, uint32_t volStart = 0);
/** \return The number of entries in the root directory for FAT16 volumes. */
- uint16_t rootDirEntryCount() const {
- return m_rootDirEntryCount;
+ uint16_t rootDirEntryCount() const { return m_rootDirEntryCount; }
/** \return The logical sector number for the start of the root directory
on FAT16 volumes or the first cluster number on FAT32 volumes. */
- uint32_t rootDirStart() const {
- return m_rootDirStart;
+ uint32_t rootDirStart() const { return m_rootDirStart; }
/** \return The number of sectors in the volume */
uint32_t volumeSectorCount() const {
- return sectorsPerCluster()*clusterCount();
+ return sectorsPerCluster() * clusterCount();
/** Debug access to FAT table
@@ -159,15 +132,13 @@ class FatPartition {
* \param[out] v value of entry
* \return -1 error, 0 EOC, else 1.
- int8_t dbgFat(uint32_t n, uint32_t* v) {
- return fatGet(n, v);
+ int8_t dbgFat(uint32_t n, uint32_t* v) { return fatGet(n, v); }
bool dmpDirSector(print_t* pr, uint32_t sector);
@@ -180,22 +151,22 @@ class FatPartition {
/** FatFile allowed access to private members. */
friend class FatFile;
- FsBlockDevice* m_blockDev; // sector device
- uint8_t m_sectorsPerCluster; // Cluster size in sectors.
- uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
- uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
- uint8_t m_fatType = 0; // Volume type (12, 16, OR 32).
- uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
- uint32_t m_allocSearchStart; // Start cluster for alloc search.
- uint32_t m_sectorsPerFat; // FAT size in sectors
- uint32_t m_dataStartSector; // First data sector number.
- uint32_t m_fatStartSector; // Start sector for first FAT.
- uint32_t m_lastCluster; // Last cluster number in FAT.
- uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32.
+ FsBlockDevice* m_blockDev; // sector device
+ uint8_t m_sectorsPerCluster; // Cluster size in sectors.
+ uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
+ uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
+ uint8_t m_fatType = 0; // Volume type (12, 16, OR 32).
+ uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
+ uint32_t m_allocSearchStart; // Start cluster for alloc search.
+ uint32_t m_sectorsPerFat; // FAT size in sectors
+ uint32_t m_dataStartSector; // First data sector number.
+ uint32_t m_fatStartSector; // Start sector for first FAT.
+ uint32_t m_lastCluster; // Last cluster number in FAT.
+ uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32.
// sector I/O functions.
@@ -210,33 +181,22 @@ class FatPartition {
bool cacheSafeWrite(uint32_t sector, const uint8_t* dst, size_t count) {
return m_cache.cacheSafeWrite(sector, dst, count);
#if MAINTAIN_FREE_CLUSTER_COUNT
- int32_t m_freeClusterCount; // Count of free clusters in volume.
- void setFreeClusterCount(int32_t value) {
- m_freeClusterCount = value;
+ int32_t m_freeClusterCount; // Count of free clusters in volume.
+ void setFreeClusterCount(int32_t value) { m_freeClusterCount = value; }
void updateFreeClusterCount(int32_t change) {
if (m_freeClusterCount >= 0) {
m_freeClusterCount += change;
-#else // MAINTAIN_FREE_CLUSTER_COUNT
- (void)value;
- void updateFreeClusterCount(int32_t change) {
- (void)change;
+#else // MAINTAIN_FREE_CLUSTER_COUNT
+ void setFreeClusterCount(int32_t value) { (void)value; }
+ void updateFreeClusterCount(int32_t change) { (void)change; }
#endif // MAINTAIN_FREE_CLUSTER_COUNT
-// sector caches
+ // sector caches
FsCache m_cache;
- bool cachePrepare(uint32_t sector, uint8_t option) {
- return m_cache.prepare(sector, option);
- FsCache* dataCache() {return &m_cache;}
+ FsCache* dataCache() { return &m_cache; }
#if USE_SEPARATE_FAT_CACHE
FsCache m_fatCache;
uint8_t* fatCachePrepare(uint32_t sector, uint8_t options) {
@@ -246,33 +206,20 @@ class FatPartition {
return m_cache.sync() && m_fatCache.sync() && syncDevice();
-#else // USE_SEPARATE_FAT_CACHE
+#else // USE_SEPARATE_FAT_CACHE
options |= FsCache::CACHE_STATUS_MIRROR_FAT;
return dataCachePrepare(sector, options);
- bool cacheSync() {
- return m_cache.sync() && syncDevice();
+ bool cacheSync() { return m_cache.sync() && syncDevice(); }
uint8_t* dataCachePrepare(uint32_t sector, uint8_t options) {
return m_cache.prepare(sector, options);
- void cacheInvalidate() {
- m_cache.invalidate();
- bool cacheSyncData() {
- return m_cache.sync();
- uint8_t* cacheAddress() {
- return m_cache.cacheBuffer();
- uint32_t cacheSectorNumber() {
- return m_cache.sector();
- void cacheDirty() {
- m_cache.dirty();
+ bool cacheSyncData() { return m_cache.sync(); }
+ uint8_t* cacheAddress() { return m_cache.cacheBuffer(); }
+ uint32_t cacheSectorNumber() { return m_cache.sector(); }
+ void cacheDirty() { m_cache.dirty(); }
bool allocateCluster(uint32_t current, uint32_t* next);
bool allocContiguous(uint32_t count, uint32_t* firstCluster);
@@ -284,12 +231,8 @@ class FatPartition {
int8_t fatGet(uint32_t cluster, uint32_t* value);
- bool fatPutEOC(uint32_t cluster) {
- return fatPut(cluster, 0x0FFFFFFF);
+ bool fatPutEOC(uint32_t cluster) { return fatPut(cluster, 0x0FFFFFFF); }
- bool isEOC(uint32_t cluster) const {
- return cluster > m_lastCluster;
+ bool isEOC(uint32_t cluster) const { return cluster > m_lastCluster; }
#endif // FatPartition
@@ -27,7 +27,7 @@
FatVolume* FatVolume::m_cwv = nullptr;
-bool FatVolume::chdir(const char *path) {
+bool FatVolume::chdir(const char* path) {
if (!dir.open(vwd(), path, O_RDONLY)) {
@@ -40,6 +40,6 @@ bool FatVolume::chdir(const char *path) {
@@ -34,7 +34,7 @@
* \class FatVolume
* \brief Integration class for the FatLib library.
-class FatVolume : public FatPartition {
+class FatVolume : public FatPartition {
/** Get file's user settable attributes.
* \param[in] path path to file.
@@ -63,8 +63,8 @@ class FatVolume : public FatPartition {
@@ -77,7 +77,7 @@ class FatVolume : public FatPartition {
/** Change global current working volume to this volume. */
* Set volume working directory to root.
@@ -92,7 +92,7 @@ class FatVolume : public FatPartition {
- bool chdir(const char *path);
+ bool chdir(const char* path);
@@ -120,9 +120,7 @@ class FatVolume : public FatPartition {
@@ -164,7 +162,7 @@ class FatVolume : public FatPartition {
* \return a File32 object.
- File32 open(const char *path, oflag_t oflag = O_RDONLY) {
+ File32 open(const char* path, oflag_t oflag = O_RDONLY) {
File32 tmpFile;
tmpFile.open(this, path, oflag);
return tmpFile;
@@ -195,7 +193,7 @@ class FatVolume : public FatPartition {
- bool rename(const char *oldPath, const char *newPath) {
+ bool rename(const char* oldPath, const char* newPath) {
FatFile file;
return file.open(vwd(), oldPath, O_RDONLY) && file.rename(vwd(), newPath);
@@ -226,7 +224,7 @@ class FatVolume : public FatPartition {
return file.open(this, path, O_WRONLY) && file.truncate(length);
#if ENABLE_ARDUINO_SERIAL
- /** List the directory contents of the root directory to Serial.
+ /** List the directory contents of the root directory to Serial.
@@ -238,9 +236,7 @@ class FatVolume : public FatPartition {
@@ -266,19 +262,15 @@ class FatVolume : public FatPartition {
- bool exists(const String& path) {
* \param[in] path A path with a valid name for the subdirectory.
@@ -297,7 +289,7 @@ class FatVolume : public FatPartition {
File32 open(const String& path, oflag_t oflag = O_RDONLY) {
- return open(path.c_str(), oflag );
+ return open(path.c_str(), oflag);
@@ -305,9 +297,7 @@ class FatVolume : public FatPartition {
@@ -333,9 +323,7 @@ class FatVolume : public FatPartition {
@@ -351,8 +339,8 @@ class FatVolume : public FatPartition {
friend FatFile;
- static FatVolume* cwv() {return m_cwv;}
- FatFile* vwd() {return &m_vwd;}
+ static FatVolume* cwv() { return m_cwv; }
+ FatFile* vwd() { return &m_vwd; }
static FatVolume* m_cwv;
FatFile m_vwd;
/** Indicate FillStack() and UnusedStack() are available. */
#define HAS_UNUSED_STACK 1
/** boundary between stack and heap. */
-extern char *__brkval;
+extern char* __brkval;
/** End of bss section.*/
extern char __bss_end;
/** Amount of free stack space.
@@ -48,9 +48,7 @@ inline int FreeStack() {
#define HAS_UNUSED_STACK 0
#elif defined(PLATFORM_ID) // Particle board
#include "Arduino.h"
-inline int FreeStack() {
- return System.freeMemory();
+inline int FreeStack() { return System.freeMemory(); }
#elif defined(__IMXRT1062__)
extern uint8_t _ebss;
@@ -69,9 +67,7 @@ inline int FreeStack() {
#ifndef FREE_STACK_CPP
#warning FreeStack is not defined for this system.
#endif // FREE_STACK_CPP
- return 0;
+inline int FreeStack() { return 0; }
#endif // defined(__AVR__) || defined(DOXYGEN)
#if defined(HAS_UNUSED_STACK) || defined(DOXYGEN)
/** Fill stack with 0x55 pattern */
@@ -89,6 +85,6 @@ int UnusedStack();
#else // HAS_UNUSED_STACK
inline void FillStack() {}
-inline int UnusedStack() {return 0;}
+inline int UnusedStack() { return 0; }
#endif // defined(HAS_UNUSED_STACK)
#endif // FreeStack_h
@@ -37,7 +37,9 @@ FsBaseFile::FsBaseFile(const FsBaseFile& from) {
FsBaseFile& FsBaseFile::operator=(const FsBaseFile& from) {
- if (this == &from) {return *this;}
+ if (this == &from) {
+ return *this;
if (from.m_fFile) {
m_fFile = new (m_fileMem) FatFile;
* \brief FsBaseFile include file.
-#include "FsNew.h"
-#include "FatLib/FatLib.h"
#include "ExFatLib/ExFatLib.h"
+#include "FatLib/FatLib.h"
+#include "FsNew.h"
+#include "FsVolume.h"
* \class FsBaseFile
* \brief FsBaseFile class.
@@ -38,7 +39,7 @@
class FsBaseFile {
/** Create an instance. */
- FsBaseFile() {}
+ FsBaseFile() = default;
/** Create a file object and open it in the current working directory.
* \param[in] path A path for a file to be opened.
@@ -46,11 +47,9 @@ class FsBaseFile {
- FsBaseFile(const char* path, oflag_t oflag) {
+ FsBaseFile(const char* path, oflag_t oflag) { open(path, oflag); }
- ~FsBaseFile() {close();}
+ ~FsBaseFile() { close(); }
/** Copy constructor.
* \param[in] from Object used to initialize this instance.
@@ -62,16 +61,15 @@ class FsBaseFile {
FsBaseFile& operator=(const FsBaseFile& from);
int attrib() {
- return m_fFile ? m_fFile->attrib() :
- m_xFile ? m_xFile->attrib() : -1;
+ return m_fFile ? m_fFile->attrib() : m_xFile ? m_xFile->attrib() : -1;
@@ -82,22 +80,23 @@ class FsBaseFile {
bool attrib(uint8_t bits) {
- return m_fFile ? m_fFile->attrib(bits) :
- m_xFile ? m_xFile->attrib(bits) : false;
+ return m_fFile ? m_fFile->attrib(bits)
+ : m_xFile ? m_xFile->attrib(bits)
+ : false;
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
int available() const {
- return m_fFile ? m_fFile->available() :
- m_xFile ? m_xFile->available() : 0;
+ return m_fFile ? m_fFile->available() : m_xFile ? m_xFile->available() : 0;
uint64_t available64() const {
- return m_fFile ? m_fFile->available32() :
- m_xFile ? m_xFile->available64() : 0;
+ return m_fFile ? m_fFile->available32()
+ : m_xFile ? m_xFile->available64()
+ : 0;
void clearWriteError() {
@@ -121,23 +120,29 @@ class FsBaseFile {
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
- return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector) :
- m_xFile ? m_xFile->contiguousRange(bgnSector, endSector) : false;
+ return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector)
+ : m_xFile ? m_xFile->contiguousRange(bgnSector, endSector)
uint32_t curCluster() const {
- return m_fFile ? m_fFile->curCluster() :
- m_xFile ? m_xFile->curCluster() : 0;
+ return m_fFile ? m_fFile->curCluster()
+ : m_xFile ? m_xFile->curCluster()
uint64_t curPosition() const {
- return m_fFile ? m_fFile->curPosition() :
- m_xFile ? m_xFile->curPosition() : 0;
+ return m_fFile ? m_fFile->curPosition()
+ : m_xFile ? m_xFile->curPosition()
+ /** \return Total allocated length for file. */
+ uint64_t dataLength() const {
+ return m_fFile ? m_fFile->fileSize() : m_xFile ? m_xFile->dataLength() : 0;
uint32_t dirIndex() const {
- return m_fFile ? m_fFile->dirIndex() :
- m_xFile ? m_xFile->dirIndex() : 0;
+ return m_fFile ? m_fFile->dirIndex() : m_xFile ? m_xFile->dirIndex() : 0;
@@ -151,8 +156,9 @@ class FsBaseFile {
bool exists(const char* path) {
- return m_fFile ? m_fFile->exists(path) :
- m_xFile ? m_xFile->exists(path) : false;
+ return m_fFile ? m_fFile->exists(path)
+ : m_xFile ? m_xFile->exists(path)
@@ -161,13 +167,13 @@ class FsBaseFile {
if (m_fFile) m_fFile->fgetpos(pos);
if (m_xFile) m_xFile->fgetpos(pos);
- * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
- * or end-of-file is encountered. The string is then terminated
- * with a null byte.
+ * \a num - 1 bytes are read, or a delimiter is read and transferred to \a
+ * str, or end-of-file is encountered. The string is then terminated with a
+ * null byte.
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
* terminates the string for Windows text files which use CRLF for newline.
@@ -179,24 +185,26 @@ class FsBaseFile {
* \param[in] delim Optional set of delimiters. The default is "\n".
* \return For success fgets() returns the length of the string in \a str.
- * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
+ * If no data is read, fgets() returns zero for EOF or -1 if an error
+ * occurred.
int fgets(char* str, int num, char* delim = nullptr) {
- return m_fFile ? m_fFile->fgets(str, num, delim) :
- m_xFile ? m_xFile->fgets(str, num, delim) : -1;
+ return m_fFile ? m_fFile->fgets(str, num, delim)
+ : m_xFile ? m_xFile->fgets(str, num, delim)
+ : -1;
uint64_t fileSize() const {
- return m_fFile ? m_fFile->fileSize() :
- m_xFile ? m_xFile->fileSize() : 0;
+ return m_fFile ? m_fFile->fileSize() : m_xFile ? m_xFile->fileSize() : 0;
uint32_t firstSector() const {
- return m_fFile ? m_fFile->firstSector() :
- m_xFile ? m_xFile->firstSector() : 0;
+ return m_fFile ? m_fFile->firstSector()
+ : m_xFile ? m_xFile->firstSector()
/** Ensure that any bytes written to the file are saved to the SD card. */
@@ -212,8 +220,9 @@ class FsBaseFile {
bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
- return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime) :
- m_xFile ? m_xFile->getAccessDateTime(pdate, ptime) : false;
+ return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime)
+ : m_xFile ? m_xFile->getAccessDateTime(pdate, ptime)
/** Get a file's create date and time.
@@ -223,13 +232,13 @@ class FsBaseFile {
bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
- return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime) :
- m_xFile ? m_xFile->getCreateDateTime(pdate, ptime) : false;
+ return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime)
+ : m_xFile ? m_xFile->getCreateDateTime(pdate, ptime)
uint8_t getError() const {
- return m_fFile ? m_fFile->getError() :
- m_xFile ? m_xFile->getError() : 0XFF;
+ return m_fFile ? m_fFile->getError() : m_xFile ? m_xFile->getError() : 0XFF;
/** Get a file's Modify date and time.
@@ -239,8 +248,9 @@ class FsBaseFile {
bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
- return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime) :
- m_xFile ? m_xFile->getModifyDateTime(pdate, ptime) : false;
+ return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime)
+ : m_xFile ? m_xFile->getModifyDateTime(pdate, ptime)
* Get a file's name followed by a zero byte.
@@ -253,14 +263,16 @@ class FsBaseFile {
size_t getName(char* name, size_t len) {
- return m_fFile ? m_fFile->getName(name, len) :
- m_xFile ? m_xFile->getName(name, len) : 0;
+ return m_fFile ? m_fFile->getName(name, len)
+ : m_xFile ? m_xFile->getName(name, len)
bool getWriteError() const {
- return m_fFile ? m_fFile->getWriteError() :
- m_xFile ? m_xFile->getWriteError() : true;
+ return m_fFile ? m_fFile->getWriteError()
+ : m_xFile ? m_xFile->getWriteError()
+ : true;
@@ -268,63 +280,67 @@ class FsBaseFile {
bool isBusy() {
- return m_fFile ? m_fFile->isBusy() :
- m_xFile ? m_xFile->isBusy() : true;
+ return m_fFile ? m_fFile->isBusy() : m_xFile ? m_xFile->isBusy() : true;
bool isContiguous() const {
- return m_fFile ? m_fFile->isContiguous() :
- m_xFile ? m_xFile->isContiguous() : false;
+ return m_fFile ? m_fFile->isContiguous()
+ : m_xFile ? m_xFile->isContiguous()
return m_xFile ? m_xFile->isContiguous() : false;
/** \return True if this is a directory else false. */
bool isDir() const {
- return m_fFile ? m_fFile->isDir() :
- m_xFile ? m_xFile->isDir() : false;
+ return m_fFile ? m_fFile->isDir() : m_xFile ? m_xFile->isDir() : false;
/** This function reports if the current file is a directory or not.
* \return true if the file is a directory.
- bool isDirectory() const {return isDir();}
+ bool isDirectory() const { return isDir(); }
bool isFile() const {
- return m_fFile ? m_fFile->isFile() :
- m_xFile ? m_xFile->isFile() : false;
+ return m_fFile ? m_fFile->isFile() : m_xFile ? m_xFile->isFile() : false;
bool isFileOrSubDir() const {
- return m_fFile ? m_fFile->isFileOrSubDir() :
- m_xFile ? m_xFile->isFileOrSubDir() : false;
+ return m_fFile ? m_fFile->isFileOrSubDir()
+ : m_xFile ? m_xFile->isFileOrSubDir()
/** \return True if this is a hidden file else false. */
bool isHidden() const {
- return m_fFile ? m_fFile->isHidden() :
- m_xFile ? m_xFile->isHidden() : false;
+ return m_fFile ? m_fFile->isHidden()
+ : m_xFile ? m_xFile->isHidden()
/** \return True if this is an open file/directory else false. */
- bool isOpen() const {return m_fFile || m_xFile;}
+ bool isOpen() const { return m_fFile || m_xFile; }
bool isReadable() const {
- return m_fFile ? m_fFile->isReadable() :
- m_xFile ? m_xFile->isReadable() : false;
+ return m_fFile ? m_fFile->isReadable()
+ : m_xFile ? m_xFile->isReadable()
bool isReadOnly() const {
- return m_fFile ? m_fFile->isReadOnly() :
- m_xFile ? m_xFile->isReadOnly() : false;
+ return m_fFile ? m_fFile->isReadOnly()
+ : m_xFile ? m_xFile->isReadOnly()
/** \return True if this is a sub-directory file else false. */
bool isSubDir() const {
- return m_fFile ? m_fFile->isSubDir() :
- m_xFile ? m_xFile->isSubDir() : false;
+ return m_fFile ? m_fFile->isSubDir()
+ : m_xFile ? m_xFile->isSubDir()
bool isWritable() const {
- return m_fFile ? m_fFile->isWritable() :
- m_xFile ? m_xFile->isWritable() : false;
+ return m_fFile ? m_fFile->isWritable()
+ : m_xFile ? m_xFile->isWritable()
@@ -336,14 +352,13 @@ class FsBaseFile {
* LS_SIZE - %Print file size.
* LS_R - Recursive list of subdirectories.
+ * \return true for success or false for failure.
- /** List directory contents. */
+ /** List directory contents.
@@ -352,8 +367,7 @@ class FsBaseFile {
bool ls(print_t* pr) {
- return m_fFile ? m_fFile->ls(pr) :
- m_xFile ? m_xFile->ls(pr) : false;
+ return m_fFile ? m_fFile->ls(pr) : m_xFile ? m_xFile->ls(pr) : false;
@@ -369,8 +383,9 @@ class FsBaseFile {
bool ls(print_t* pr, uint8_t flags) {
- return m_fFile ? m_fFile->ls(pr, flags) :
- m_xFile ? m_xFile->ls(pr, flags) : false;
+ return m_fFile ? m_fFile->ls(pr, flags)
+ : m_xFile ? m_xFile->ls(pr, flags)
/** Make a new directory.
@@ -412,10 +427,12 @@ class FsBaseFile {
* O_CREAT - If the file exists, this flag has no effect except as noted
* under O_EXCL below. Otherwise, the file shall be created
- * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
+ * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file
+ * exists.
* O_TRUNC - If the file exists and is a regular file, and the file is
- * successfully opened and is not read only, its length shall be truncated to 0.
+ * successfully opened and is not read only, its length shall be truncated to
+ * 0.
* WARNING: A given file must not be opened by more than one file object
* or file corruption may occur.
@@ -464,7 +481,7 @@ class FsBaseFile {
bool open(const char* path, oflag_t oflag = O_RDONLY) {
return FsVolume::m_cwv && open(FsVolume::m_cwv, path, oflag);
- /** Open a file or directory by index in the current working directory.
+ /** Open a file or directory by index in the current working directory.
* \param[in] index The \a index of the directory entry for the file to be
* opened. The value for \a index is (directory file position)/32.
@@ -497,14 +514,13 @@ class FsBaseFile {
bool openRoot(FsVolume* vol);
/** \return the current file position. */
- uint64_t position() const {return curPosition();}
+ uint64_t position() const { return curPosition(); }
/** Return the next available byte without consuming it.
* \return The byte if no error and not at eof else -1;
int peek() {
- return m_fFile ? m_fFile->peek() :
- m_xFile ? m_xFile->peek() : -1;
+ return m_fFile ? m_fFile->peek() : m_xFile ? m_xFile->peek() : -1;
/** Allocate contiguous clusters to an empty file.
@@ -518,8 +534,9 @@ class FsBaseFile {
bool preAllocate(uint64_t length) {
- return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length) :
- m_xFile ? m_xFile->preAllocate(length) : false;
+ return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length)
+ : m_xFile ? m_xFile->preAllocate(length)
/** Print a file's access date and time
@@ -528,8 +545,9 @@ class FsBaseFile {
size_t printAccessDateTime(print_t* pr) {
- return m_fFile ? m_fFile->printAccessDateTime(pr) :
- m_xFile ? m_xFile->printAccessDateTime(pr) : 0;
+ return m_fFile ? m_fFile->printAccessDateTime(pr)
+ : m_xFile ? m_xFile->printAccessDateTime(pr)
@@ -538,8 +556,9 @@ class FsBaseFile {
size_t printCreateDateTime(print_t* pr) {
- return m_fFile ? m_fFile->printCreateDateTime(pr) :
- m_xFile ? m_xFile->printCreateDateTime(pr) : 0;
+ return m_fFile ? m_fFile->printCreateDateTime(pr)
+ : m_xFile ? m_xFile->printCreateDateTime(pr)
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
@@ -548,8 +567,9 @@ class FsBaseFile {
* \return The number of bytes written or -1 if an error occurs.
size_t printField(double value, char term, uint8_t prec = 2) {
- return m_fFile ? m_fFile->printField(value, term, prec) :
- m_xFile ? m_xFile->printField(value, term, prec) : 0;
+ return m_fFile ? m_fFile->printField(value, term, prec)
+ : m_xFile ? m_xFile->printField(value, term, prec)
@@ -558,17 +578,18 @@ class FsBaseFile {
size_t printField(float value, char term, uint8_t prec = 2) {
- return printField(static_cast<double>(value), term, prec);
+ return printField(static_cast<double>(value), term, prec);
- return m_fFile ? m_fFile->printField(value, term) :
- m_xFile ? m_xFile->printField(value, term) : 0;
+ return m_fFile ? m_fFile->printField(value, term)
+ : m_xFile ? m_xFile->printField(value, term)
/** Print a file's size.
@@ -578,8 +599,9 @@ class FsBaseFile {
* for success and zero is returned for failure.
size_t printFileSize(print_t* pr) {
- return m_fFile ? m_fFile->printFileSize(pr) :
- m_xFile ? m_xFile->printFileSize(pr) : 0;
+ return m_fFile ? m_fFile->printFileSize(pr)
+ : m_xFile ? m_xFile->printFileSize(pr)
/** Print a file's modify date and time
@@ -588,8 +610,9 @@ class FsBaseFile {
size_t printModifyDateTime(print_t* pr) {
- return m_fFile ? m_fFile->printModifyDateTime(pr) :
- m_xFile ? m_xFile->printModifyDateTime(pr) : 0;
+ return m_fFile ? m_fFile->printModifyDateTime(pr)
+ : m_xFile ? m_xFile->printModifyDateTime(pr)
/** Print a file's name
@@ -598,8 +621,9 @@ class FsBaseFile {
- return m_fFile ? m_fFile->printName(pr) :
- m_xFile ? m_xFile->printName(pr) : 0;
+ return m_fFile ? m_fFile->printName(pr)
+ : m_xFile ? m_xFile->printName(pr)
/** Read the next byte from a file.
@@ -624,8 +648,9 @@ class FsBaseFile {
* or an I/O error occurred.
int read(void* buf, size_t count) {
- return m_fFile ? m_fFile->read(buf, count) :
- m_xFile ? m_xFile->read(buf, count) : -1;
+ return m_fFile ? m_fFile->read(buf, count)
+ : m_xFile ? m_xFile->read(buf, count)
/** Remove a file.
@@ -638,7 +663,7 @@ class FsBaseFile {
bool remove();
- /** Remove a file.
+ /** Remove a file.
* The directory entry and all data for the file are deleted.
@@ -653,8 +678,9 @@ class FsBaseFile {
bool remove(const char* path) {
- return m_fFile ? m_fFile->remove(path) :
- m_xFile ? m_xFile->remove(path) : false;
+ return m_fFile ? m_fFile->remove(path)
+ : m_xFile ? m_xFile->remove(path)
@@ -663,8 +689,9 @@ class FsBaseFile {
bool rename(const char* newPath) {
- return m_fFile ? m_fFile->rename(newPath) :
- m_xFile ? m_xFile->rename(newPath) : false;
+ return m_fFile ? m_fFile->rename(newPath)
+ : m_xFile ? m_xFile->rename(newPath)
@@ -674,9 +701,9 @@ class FsBaseFile {
bool rename(FsBaseFile* dir, const char* newPath) {
- return m_fFile && dir->m_fFile ? m_fFile->rename(dir->m_fFile, newPath) :
- m_xFile && dir->m_xFile ? m_xFile->rename(dir->m_xFile, newPath) :
- false;
+ return m_fFile && dir->m_fFile ? m_fFile->rename(dir->m_fFile, newPath)
+ : m_xFile && dir->m_xFile ? m_xFile->rename(dir->m_xFile, newPath)
void rewind() {
@@ -706,22 +733,18 @@ class FsBaseFile {
* \param[in] pos the new file position.
- bool seek(uint64_t pos) {return seekSet(pos);}
+ bool seek(uint64_t pos) { return seekSet(pos); }
/** Set the files position to current position + \a pos. See seekSet().
- return seekSet(curPosition() + offset);
+ bool seekCur(int64_t offset) { return seekSet(curPosition() + offset); }
- bool seekEnd(int64_t offset = 0) {
- return seekSet(fileSize() + offset);
+ bool seekEnd(int64_t offset = 0) { return seekSet(fileSize() + offset); }
/** Sets a file's position.
* \param[in] pos The new position in bytes from the beginning of the file.
@@ -729,19 +752,19 @@ class FsBaseFile {
bool seekSet(uint64_t pos) {
- return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos) :
- m_xFile ? m_xFile->seekSet(pos) : false;
+ return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos)
+ : m_xFile ? m_xFile->seekSet(pos)
/** \return the file's size. */
- uint64_t size() const {return fileSize();}
+ uint64_t size() const { return fileSize(); }
bool sync() {
- return m_fFile ? m_fFile->sync() :
- m_xFile ? m_xFile->sync() : false;
+ return m_fFile ? m_fFile->sync() : m_xFile ? m_xFile->sync() : false;
/** Set a file's timestamps in its directory entry.
@@ -777,19 +800,20 @@ class FsBaseFile {
bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second) {
- return m_fFile ?
- m_fFile->timestamp(flags, year, month, day, hour, minute, second) :
- m_xFile ?
- m_xFile->timestamp(flags, year, month, day, hour, minute, second) :
+ return m_fFile ? m_fFile->timestamp(flags, year, month, day, hour, minute,
+ second)
+ : m_xFile ? m_xFile->timestamp(flags, year, month, day, hour, minute,
/** Truncate a file to the current position.
bool truncate() {
- return m_fFile ? m_fFile->truncate() :
- m_xFile ? m_xFile->truncate() : false;
+ return m_fFile ? m_fFile->truncate()
+ : m_xFile ? m_xFile->truncate()
/** Truncate a file to a specified length.
* The current file position will be set to end of file.
@@ -799,23 +823,22 @@ class FsBaseFile {
bool truncate(uint64_t length) {
- return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length) :
- m_xFile ? m_xFile->truncate(length) : false;
+ return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length)
+ : m_xFile ? m_xFile->truncate(length)
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* \return 1 for success and 0 for failure.
@@ -829,13 +852,14 @@ class FsBaseFile {
* \a nbyte. If an error occurs, write() returns zero and writeError is set.
size_t write(const void* buf, size_t count) {
- return m_fFile ? m_fFile->write(buf, count) :
- m_xFile ? m_xFile->write(buf, count) : 0;
+ return m_fFile ? m_fFile->write(buf, count)
+ : m_xFile ? m_xFile->write(buf, count)
newalign_t m_fileMem[FS_ALIGN_DIM(ExFatFile, FatFile)];
- FatFile* m_fFile = nullptr;
+ FatFile* m_fFile = nullptr;
ExFatFile* m_xFile = nullptr;
#ifndef FsFormatter_h
#define FsFormatter_h
* \class FsFormatter
* \brief Format a exFAT/FAT volume.
class FsFormatter {
+ FsFormatter() = default;
@@ -46,10 +48,10 @@ class FsFormatter {
if (sectorCount == 0) {
- return sectorCount <= 67108864 ?
- m_fFmt.format(dev, secBuffer, pr) :
- m_xFmt.format(dev, secBuffer, pr);
+ return sectorCount <= 67108864 ? m_fFmt.format(dev, secBuffer, pr)
+ : m_xFmt.format(dev, secBuffer, pr);
FatFormatter m_fFmt;
ExFatFormatter m_xFmt;
* \brief FsLib include file.
-#include "FsVolume.h"
#include "FsFile.h"
#include "FsFormatter.h"
#endif // FsLib_h
@@ -36,7 +36,7 @@ typedef uint32_t newalign_t;
/** Dimension of aligned area. */
#define NEW_ALIGN_DIM(n) \
- (((size_t)(n) + sizeof(newalign_t) - 1U)/sizeof(newalign_t))
+ (((size_t)(n) + sizeof(newalign_t) - 1U) / sizeof(newalign_t))
/** Dimension of aligned area for etype or ftype class. */
#define FS_ALIGN_DIM(etype, ftype) NEW_ALIGN_DIM(FS_SIZE(etype, ftype))
@@ -25,23 +25,22 @@
#include "FsLib.h"
FsVolume* FsVolume::m_cwv = nullptr;
-bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv,
- uint8_t part, uint32_t volStart) {
- m_blockDev = blockDev;
+bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv, uint8_t part,
+ uint32_t volStart) {
m_fVol = nullptr;
m_xVol = new (m_volMem) ExFatVolume;
- if (m_xVol && m_xVol->begin(m_blockDev, false, part, volStart)) {
+ if (m_xVol && m_xVol->begin(blockDev, false, part, volStart)) {
m_xVol = nullptr;
m_fVol = new (m_volMem) FatVolume;
- if (m_fVol && m_fVol->begin(m_blockDev, false, part, volStart)) {
+ if (m_fVol && m_fVol->begin(blockDev, false, part, volStart)) {
if (setCwv || !m_cwv) {
m_cwv = this;
@@ -53,14 +52,14 @@ bool FsVolume::ls(print_t* pr, const char* path, uint8_t flags) {
return dir.open(this, path, O_RDONLY) && dir.ls(pr, flags);
-FsFile FsVolume::open(const char *path, oflag_t oflag) {
+FsFile FsVolume::open(const char* path, oflag_t oflag) {
FsFile tmpFile;
#if ENABLE_ARDUINO_STRING
-FsFile FsVolume::open(const String &path, oflag_t oflag) {
+FsFile FsVolume::open(const String& path, oflag_t oflag) {
#endif // ENABLE_ARDUINO_STRING
@@ -28,9 +28,9 @@
* \brief FsVolume include file.
-#include "../FatLib/FatLib.h"
#include "../ExFatLib/ExFatLib.h"
+#include "../FatLib/FatLib.h"
class FsFile;
@@ -39,16 +39,15 @@ class FsFile;
class FsVolume {
- FsVolume() {}
+ FsVolume() = default;
- ~FsVolume() {end();}
+ ~FsVolume() { end(); }
int attrib(const char* path) {
- return m_fVol ? m_fVol->attrib(path) :
- m_xVol ? m_xVol->attrib(path) : -1;
+ return m_fVol ? m_fVol->attrib(path) : m_xVol ? m_xVol->attrib(path) : -1;
/** Set file's user settable attributes.
@@ -58,8 +57,9 @@ class FsVolume {
bool attrib(const char* path, uint8_t bits) {
- return m_fVol ? m_fVol->attrib(path, bits) :
- m_xVol ? m_xVol->attrib(path, bits) : false;
+ return m_fVol ? m_fVol->attrib(path, bits)
+ : m_xVol ? m_xVol->attrib(path, bits)
* Initialize an FatVolume object.
@@ -69,44 +69,45 @@ class FsVolume {
- bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t
- part = 1, uint32_t volStart = 0);
+ bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t part = 1,
+ uint32_t volStart = 0);
uint32_t bytesPerCluster() const {
- return m_fVol ? m_fVol->bytesPerCluster() :
- m_xVol ? m_xVol->bytesPerCluster() : 0;
+ return m_fVol ? m_fVol->bytesPerCluster()
+ : m_xVol ? m_xVol->bytesPerCluster()
bool chdir() {
- return m_fVol ? m_fVol->chdir() :
- m_xVol ? m_xVol->chdir() : false;
+ return m_fVol ? m_fVol->chdir() : m_xVol ? m_xVol->chdir() : false;
* Set volume working directory.
- bool chdir(const char* path) {
- return m_fVol ? m_fVol->chdir(path) :
- m_xVol ? m_xVol->chdir(path) : false;
+ bool chdir(const char* path) {
+ return m_fVol ? m_fVol->chdir(path) : m_xVol ? m_xVol->chdir(path) : false;
uint32_t clusterCount() const {
- return m_fVol ? m_fVol->clusterCount() :
- m_xVol ? m_xVol->clusterCount() : 0;
+ return m_fVol ? m_fVol->clusterCount()
+ : m_xVol ? m_xVol->clusterCount()
uint32_t dataStartSector() const {
- return m_fVol ? m_fVol->dataStartSector() :
- m_xVol ? m_xVol->clusterHeapStartSector() : 0;
+ return m_fVol ? m_fVol->dataStartSector()
+ : m_xVol ? m_xVol->clusterHeapStartSector()
@@ -124,25 +125,27 @@ class FsVolume {
- return m_fVol ? m_fVol->exists(path) :
- m_xVol ? m_xVol->exists(path) : false;
+ return m_fVol ? m_fVol->exists(path)
+ : m_xVol ? m_xVol->exists(path)
uint32_t fatStartSector() const {
- return m_fVol ? m_fVol->fatStartSector() :
- m_xVol ? m_xVol->fatStartSector() : 0;
+ return m_fVol ? m_fVol->fatStartSector()
+ : m_xVol ? m_xVol->fatStartSector()
/** \return Partition type, FAT_TYPE_EXFAT, FAT_TYPE_FAT32,
* FAT_TYPE_FAT16, or zero for error.
uint8_t fatType() const {
- return m_fVol ? m_fVol->fatType() :
- m_xVol ? m_xVol->fatType() : 0;
+ return m_fVol ? m_fVol->fatType() : m_xVol ? m_xVol->fatType() : 0;
int32_t freeClusterCount() const {
- return m_fVol ? m_fVol->freeClusterCount() :
- m_xVol ? m_xVol->freeClusterCount() : -1;
+ return m_fVol ? m_fVol->freeClusterCount()
+ : m_xVol ? m_xVol->freeClusterCount()
@@ -150,8 +153,7 @@ class FsVolume {
- return m_fVol ? m_fVol->isBusy() :
- m_xVol ? m_xVol->isBusy() : false;
+ return m_fVol ? m_fVol->isBusy() : m_xVol ? m_xVol->isBusy() : false;
@@ -160,8 +162,7 @@ class FsVolume {
- return m_fVol ? m_fVol->ls(pr) :
- m_xVol ? m_xVol->ls(pr) : false;
+ return m_fVol ? m_fVol->ls(pr) : m_xVol ? m_xVol->ls(pr) : false;
@@ -177,8 +178,9 @@ class FsVolume {
- return m_fVol ? m_fVol->ls(pr, flags) :
- m_xVol ? m_xVol->ls(pr, flags) : false;
+ return m_fVol ? m_fVol->ls(pr, flags)
+ : m_xVol ? m_xVol->ls(pr, flags)
/** List the directory contents of a directory.
@@ -197,7 +199,7 @@ class FsVolume {
bool ls(print_t* pr, const char* path, uint8_t flags);
- /** Make a subdirectory in the volume root directory.
+ /** Make a subdirectory in the volume root directory.
@@ -205,9 +207,10 @@ class FsVolume {
- bool mkdir(const char *path, bool pFlag = true) {
- return m_fVol ? m_fVol->mkdir(path, pFlag) :
- m_xVol ? m_xVol->mkdir(path, pFlag) : false;
+ bool mkdir(const char* path, bool pFlag = true) {
+ return m_fVol ? m_fVol->mkdir(path, pFlag)
+ : m_xVol ? m_xVol->mkdir(path, pFlag)
@@ -217,14 +220,15 @@ class FsVolume {
FsFile open(const char* path, oflag_t oflag = O_RDONLY);
- * \param[in] path A path with a valid 8.3 DOS name for the file.
+ * \param[in] path A path with a valid 8.3 DOS name for the file.
- bool remove(const char *path) {
- return m_fVol ? m_fVol->remove(path) :
- m_xVol ? m_xVol->remove(path) : false;
+ bool remove(const char* path) {
+ return m_fVol ? m_fVol->remove(path)
+ : m_xVol ? m_xVol->remove(path)
@@ -240,9 +244,10 @@ class FsVolume {
- return m_fVol ? m_fVol->rename(oldPath, newPath) :
- m_xVol ? m_xVol->rename(oldPath, newPath) : false;
+ return m_fVol ? m_fVol->rename(oldPath, newPath)
+ : m_xVol ? m_xVol->rename(oldPath, newPath)
/** Remove a subdirectory from the volume's root directory.
@@ -252,22 +257,20 @@ class FsVolume {
- bool rmdir(const char *path) {
- return m_fVol ? m_fVol->rmdir(path) :
- m_xVol ? m_xVol->rmdir(path) : false;
+ bool rmdir(const char* path) {
+ return m_fVol ? m_fVol->rmdir(path) : m_xVol ? m_xVol->rmdir(path) : false;
uint32_t sectorsPerCluster() const {
- return m_fVol ? m_fVol->sectorsPerCluster() :
- m_xVol ? m_xVol->sectorsPerCluster() : 0;
+ return m_fVol ? m_fVol->sectorsPerCluster()
+ : m_xVol ? m_xVol->sectorsPerCluster()
@@ -280,9 +283,7 @@ class FsVolume {
@@ -309,18 +310,14 @@ class FsVolume {
@@ -329,7 +326,7 @@ class FsVolume {
@@ -338,16 +335,14 @@ class FsVolume {
* \return a FsBaseFile object.
- FsFile open(const String &path, oflag_t oflag = O_RDONLY);
+ FsFile open(const String& path, oflag_t oflag = O_RDONLY);
- bool remove(const String &path) {
@@ -373,9 +368,7 @@ class FsVolume {
- bool rmdir(const String &path) {
@@ -393,18 +386,17 @@ class FsVolume {
- newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
+ newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
/** FsBaseFile allowed access to private members. */
friend class FsBaseFile;
- static FsVolume* cwv() {return m_cwv;}
+ static FsVolume* cwv() { return m_cwv; }
FsVolume(const FsVolume& from);
FsVolume& operator=(const FsVolume& from);
static FsVolume* m_cwv;
- FatVolume* m_fVol = nullptr;
+ FatVolume* m_fVol = nullptr;
ExFatVolume* m_xVol = nullptr;
- FsBlockDevice* m_blockDev;
#endif // FsVolume_h
@@ -22,14 +22,11 @@
-#include "common/SysCall.h"
-#if defined(UDR0) || defined(DOXYGEN)
#include "MinimumSerial.h"
-const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
+#if defined(UDR0) || defined(DOXYGEN)
+const uint16_t MIN_2X_BAUD = F_CPU / (4 * (2 * 0XFFF + 1)) + 1;
-int MinimumSerial::available() {
- return UCSR0A & (1 << RXC0) ? 1 : 0;
+int MinimumSerial::available() { return UCSR0A & (1 << RXC0) ? 1 : 0; }
void MinimumSerial::begin(uint32_t baud) {
uint16_t baud_setting;
@@ -53,7 +50,8 @@ void MinimumSerial::begin(uint32_t baud) {
void MinimumSerial::flush() {
- while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
+ while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {
int MinimumSerial::read() {
@@ -64,7 +62,8 @@ int MinimumSerial::read() {
size_t MinimumSerial::write(uint8_t b) {
UDR0 = b;
@@ -22,7 +22,7 @@
+/**
* \brief Minimal AVR Serial driver.
@@ -37,7 +37,7 @@
class MinimumSerial : public print_t {
/** \return true for hardware serial */
- operator bool() {return true;}
+ operator bool() { return true; }
* \return one if data is available.
@@ -28,22 +28,22 @@
* \brief Ring buffer for data loggers.
+#include "common/SysCall.h"
// Teensy 3.5/3.6 has hard fault at 0x20000000 for unaligned memcpy.
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
inline bool is_aligned(const void* ptr, uintptr_t alignment) {
- auto iptr = reinterpret_cast<uintptr_t>(ptr);
- return !(iptr % alignment);
+ auto iptr = reinterpret_cast<uintptr_t>(ptr);
+ return !(iptr % alignment);
inline void memcpyBuf(void* dst, const void* src, size_t len) {
const uint8_t* b = reinterpret_cast<const uint8_t*>(0X20000000UL);
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
- const uint8_t *s = reinterpret_cast<const uint8_t*>(src);
+ const uint8_t* s = reinterpret_cast<const uint8_t*>(src);
if ((is_aligned(d, 4) && is_aligned(s, 4) && (len & 3) == 0) ||
- !((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
+ !((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
memcpy(dst, src, len);
while (len--) {
@@ -51,7 +51,7 @@ inline void memcpyBuf(void* dst, const void* src, size_t len) {
-#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
+#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
@@ -59,23 +59,22 @@ inline void memcpyBuf(void* dst, const void* src, size_t len) {
* \class RingBuf
- * \brief Ring buffer for data loggers.
+ * \brief Ring buffer for data loggers and data transmitters.
- * This ring buffer may be used in ISRs. bytesFreeIsr(), bytesUsedIsr(),
- * memcopyIn(), and memcopyOut() are ISR callable. For ISR use call
- * memcopyIn() in the ISR and use writeOut() in non-interrupt code
- * to write data to a file. readIn() and memcopyOut can be use in a
- * similar way to provide file data to an ISR.
+ * This ring buffer may be used in ISRs. Use beginISR(), endISR(), write()
+ * and print() in the ISR and use writeOut() in non-interrupt code
+ * to write data to a file.
- * Print into a RingBuf in an ISR should also work but has not been verified.
+ * Use beginISR(), endISR() and read() in an ISR with readIn() in non-interrupt
+ * code to provide file data to an ISR.
-template<class F, size_t Size>
+template <class F, size_t Size>
class RingBuf : public Print {
* RingBuf Constructor.
- RingBuf() {}
+ RingBuf() { begin(nullptr); }
* Initialize RingBuf.
* \param[in] file Underlying file.
@@ -85,97 +84,41 @@ class RingBuf : public Print {
m_count = 0;
m_head = 0;
m_tail = 0;
+ m_inISR = false;
clearWriteError();
- * \return the RingBuf free space in bytes. Not ISR callable.
+ * Disable protection of m_count by noInterrupts()/interrupts.
- size_t bytesFree() const {
- size_t count;
- noInterrupts();
- count = m_count;
- interrupts();
- return Size - count;
+ void beginISR() { m_inISR = true; }
- * \return the RingBuf free space in bytes. ISR callable.
+ * \return the RingBuf free space in bytes.
- size_t bytesFreeIsr() const {
- return Size - m_count;
+ size_t bytesFree() const { return Size - bytesUsed(); }
- * \return the RingBuf used space in bytes. Not ISR callable.
+ * \return the RingBuf used space in bytes.
size_t bytesUsed() const {
- return count;
- * \return the RingBuf used space in bytes. ISR callable.
- size_t bytesUsedIsr() const {
- return m_count;
- * Copy data to the RingBuf from buf.
- * The number of bytes copied may be less than count if
- * count is greater than bytesFree.
- * This function may be used in an ISR with writeOut()
- * in non-interrupt code.
- * \param[in] buf Location of data to be copied.
- * \param[in] count number of bytes to be copied.
- * \return Number of bytes actually copied.
- size_t memcpyIn(const void* buf, size_t count) {
- const uint8_t* src = (const uint8_t*)buf;
- size_t n = Size - m_count;
- if (count > n) {
- count = n;
- size_t nread = 0;
- while (nread != count) {
- n = minSize(Size - m_head, count - nread);
- memcpyBuf(m_buf + m_head, src + nread, n);
- m_head = advance(m_head, n);
- nread += n;
+ if (m_inISR) {
+ return m_count;
+ noInterrupts();
+ size_t rtn = m_count;
+ interrupts();
+ return rtn;
- m_count += nread;
- return nread;
- * Copy date from the RingBuf to buf.
- * bytesUsed is less than count.
- * This function may be used in an ISR with readIn() in
- * non-interrupt code.
- * \param[out] buf Location to receive the data.
+ * Enable protection of m_count by noInterrupts()/interrupts.
- size_t memcpyOut(void* buf, size_t count) {
- uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
- size_t nwrite = 0;
- size_t n = m_count;
- while (nwrite != count) {
- n = minSize(Size - m_tail, count - nwrite);
- memcpyBuf(dst + nwrite, m_buf + m_tail, n);
- m_tail = advance(m_tail, n);
- nwrite += n;
- m_count -= nwrite;
- return nwrite;
+ void endISR() { m_inISR = false; }
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ // See write(), read(), beginISR() and endISR().
+ size_t __attribute__((error("use write(buf, count), beginISR(), endISR()")))
+ memcpyIn(const void* buf, size_t count);
+ size_t __attribute__((error("use read(buf, count), beginISR(), endISR()")))
+ memcpyOut(void* buf, size_t count);
+#endif // DOXYGEN_SHOULD_SKIP_THIS
@@ -211,7 +154,7 @@ class RingBuf : public Print {
@@ -234,34 +177,77 @@ class RingBuf : public Print {
return write((const uint8_t*)str, &buf[sizeof(buf)] - str);
+ /** Read data from RingBuf.
+ * \param[out] buf destination for data.
+ * \param[in] count number of bytes to read.
+ * \return Actual count of bytes read.
+ size_t read(void* buf, size_t count) {
+ size_t n = bytesFree();
+ if (count > n) {
+ count = n;
+ uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
+ n = minSize(Size - m_tail, count);
+ if (n == count) {
+ memcpyBuf(dst, m_buf + m_tail, n);
+ m_tail = advance(m_tail, n);
+ memcpyBuf(dst + n, m_buf, count - n);
+ m_tail = count - n;
+ adjustCount(-count);
+ * Efficient read for small types.
+ * \param[in] data location for data item.
+ * \return true for success else false.
+ bool read(Type* data) {
+ if (bytesUsed() < sizeof(Type)) {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
+ for (size_t i = 0; i < sizeof(Type); i++) {
+ ptr[i] = m_buf[m_tail];
+ m_tail = advance(m_tail);
+ adjustCount(-sizeof(Type));
* Read data into the RingBuf from the underlying file.
* the number of bytes read may be less than count if
* bytesFree is less than count.
- * This function may be used in non-interrupt code with
- * memcopyOut() in an ISR.
+ * This function must not be used in an ISR.
* \param[in] count number of bytes to be read.
- * \return Number of bytes actually read.
+ * \return Number of bytes actually read or negative for read error.
- size_t readIn(size_t count) {
- size_t n = bytesFree(); // Protected from interrupts.
+ int readIn(size_t count) {
if (count > n) {
count = n;
- if ((size_t)m_file->read(m_buf + m_head, n) != n) {
+ n = minSize(Size - m_head, count);
+ auto rtn = m_file->read(m_buf + m_head, n);
+ if (rtn <= 0) {
+ size_t nread = rtn;
+ if (n < count && nread == n) {
+ rtn = m_file->read(m_buf, count - n);
+ if (rtn > 0) {
+ nread += rtn;
+ m_head = advance(m_head, nread);
+ adjustCount(nread);
return nread;
@@ -270,25 +256,36 @@ class RingBuf : public Print {
size_t n = bytesUsed();
- return writeOut(n) == n;
+ return n ? writeOut(n) == n : true;
* Copy data to the RingBuf from buf.
+ * No data will be copied if count is greater than bytesFree.
* Use getWriteError() to check for print errors and
- * clearWriteError() to clear error.
+ * clearWriteError() to clear the error.
* \param[in] buf Location of data to be written.
* \param[in] count number of bytes to be written.
* \return Number of bytes actually written.
- if (count > bytesFree()) {
+ if (bytesFree() < count) {
setWriteError();
+ return 0;
- return memcpyIn(buf, count);
+ const uint8_t* src = (const uint8_t*)buf;
+ size_t n = minSize(Size - m_head, count);
+ memcpyBuf(m_buf + m_head, src, n);
+ m_head = advance(m_head, n);
+ memcpyBuf(m_buf, src + n, count - n);
+ m_head = count - n;
+ adjustCount(count);
* Copy str to RingBuf.
@@ -296,9 +293,7 @@ class RingBuf : public Print {
* \param[in] str Location of data to be written.
- return Print::write(str);
+ size_t write(const char* str) { return Print::write(str); }
* Override virtual function in Print for efficiency.
@@ -309,13 +304,35 @@ class RingBuf : public Print {
size_t write(const uint8_t* buf, size_t count) override {
return write((const void*)buf, count);
+ * Efficient write for small types.
+ * \param[in] data Item to be written.
+ * \return Number of bytes actually written.
+ size_t write(Type data) {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(&data);
+ if (bytesFree() < sizeof(Type)) {
+ setWriteError();
+ m_buf[m_head] = ptr[i];
+ m_head = advance(m_head);
+ adjustCount(sizeof(Type));
+ return sizeof(Type);
* Required function for Print.
* \param[in] data Byte to be written.
+ * Try to force devirtualization by using final and always_inline.
- size_t write(uint8_t data) override {
- return write(&data, 1);
+ size_t write(uint8_t data) final __attribute__((always_inline)) {
+ // Use this if above does not compile size_t write(uint8_t data) final {
+ return write<uint8_t>(data);
* Write data to file from RingBuf buffer.
@@ -324,43 +341,60 @@ class RingBuf : public Print {
* The number of bytes written may be less than count if
* bytesUsed is less than count or if an error occurs.
- * memcopyIn() in an ISR.
+ * This function must only be used in non-interrupt code.
size_t writeOut(size_t count) {
size_t n = bytesUsed(); // Protected from interrupts;
- if (m_file->write(m_buf + m_tail, n) != n) {
+ auto rtn = m_file->write(m_buf + m_tail, n);
+ size_t nwrite = rtn;
+ if (n < count && nwrite == n) {
+ rtn = m_file->write(m_buf, count - n);
+ nwrite += rtn;
+ m_tail = advance(m_tail, nwrite);
+ adjustCount(-nwrite);
return nwrite;
uint8_t __attribute__((aligned(4))) m_buf[Size];
- F* m_file = nullptr;
+ F* m_file;
volatile size_t m_count;
size_t m_head;
size_t m_tail;
+ volatile bool m_inISR;
+ void adjustCount(int amount) {
+ m_count += amount;
+ size_t advance(size_t index) {
+ if (!((Size - 1) & Size)) {
+ return (index + 1) & (Size - 1);
+ return index + 1 < Size ? index + 1 : 0;
size_t advance(size_t index, size_t n) {
index += n;
return index < Size ? index : index - Size;
// avoid macro MIN
- size_t minSize(size_t a, size_t b) {return a < b ? a : b;}
+ size_t minSize(size_t a, size_t b) { return a < b ? a : b; }
#endif // RingBuf_h
@@ -22,13 +22,19 @@
+ * \file
+ * \brief Top level include for SPI and SDIO cards.
#ifndef SdCard_h
#define SdCard_h
-#include "SdioCard.h"
#include "SdSpiCard.h"
+#include "SdioCard.h"
+/** Type for both SPI and SDIO cards. */
typedef SdCardInterface SdCard;
-#else // HAS_SDIO_CLASS
+#else // HAS_SDIO_CLASS
+/** Type for SPI card. */
typedef SdSpiCard SdCard;
#endif // HAS_SDIO_CLASS
/** Determine card configuration type.
@@ -36,13 +42,19 @@ typedef SdSpiCard SdCard;
* \param[in] cfg Card configuration.
* \return true if SPI.
-inline bool isSpi(SdSpiConfig cfg) {(void)cfg; return true;}
+inline bool isSpi(SdSpiConfig cfg) {
+ (void)cfg;
-inline bool isSpi(SdioConfig cfg) {(void)cfg; return false;}
+inline bool isSpi(SdioConfig cfg) {
* \class SdCardFactory
* \brief Setup a SPI card or SDIO card.
@@ -67,7 +79,7 @@ class SdCardFactory {
m_sdioCard.begin(config);
return &m_sdioCard;
@@ -25,21 +25,28 @@
#include "SdCardInfo.h"
#undef SD_CARD_ERROR
-#define SD_CARD_ERROR(e, m) case SD_CARD_ERROR_##e: pr->print(F(#e)); break;
+#define SD_CARD_ERROR(e, m) \
+ case SD_CARD_ERROR_##e: \
+ pr->print(F(#e)); \
void printSdErrorSymbol(print_t* pr, uint8_t code) {
pr->print(F("SD_CARD_ERROR_"));
switch (code) {
SD_ERROR_CODE_LIST
- default: pr->print(F("UNKNOWN"));
+ pr->print(F("UNKNOWN"));
-#define SD_CARD_ERROR(e, m) case SD_CARD_ERROR_##e: pr->print(F(m)); break;
+ pr->print(F(m)); \
void printSdErrorText(print_t* pr, uint8_t code) {
- switch
- (code) {
+ switch (code) {
- default: pr->print(F("Unknown error"));
+ pr->print(F("Unknown error"));
@@ -22,9 +22,14 @@
+ * \brief Definitions for SD cards.
#ifndef SdCardInfo_h
#define SdCardInfo_h
#include <stdint.h>
#include "../common/SysCall.h"
// Based on the document:
@@ -43,73 +48,81 @@
// SD card errors
// See the SD Specification for command info.
-#define SD_ERROR_CODE_LIST\
- SD_CARD_ERROR(NONE, "No error")\
- SD_CARD_ERROR(CMD0, "Card reset failed")\
- SD_CARD_ERROR(CMD2, "SDIO read CID")\
- SD_CARD_ERROR(CMD3, "SDIO publish RCA")\
- SD_CARD_ERROR(CMD6, "Switch card function")\
- SD_CARD_ERROR(CMD7, "SDIO card select")\
- SD_CARD_ERROR(CMD8, "Send and check interface settings")\
- SD_CARD_ERROR(CMD9, "Read CSD data")\
- SD_CARD_ERROR(CMD10, "Read CID data")\
- SD_CARD_ERROR(CMD12, "Stop multiple block read")\
- SD_CARD_ERROR(CMD13, "Read card status")\
- SD_CARD_ERROR(CMD17, "Read single block")\
- SD_CARD_ERROR(CMD18, "Read multiple blocks")\
- SD_CARD_ERROR(CMD24, "Write single block")\
- SD_CARD_ERROR(CMD25, "Write multiple blocks")\
- SD_CARD_ERROR(CMD32, "Set first erase block")\
- SD_CARD_ERROR(CMD33, "Set last erase block")\
- SD_CARD_ERROR(CMD38, "Erase selected blocks")\
- SD_CARD_ERROR(CMD58, "Read OCR register")\
- SD_CARD_ERROR(CMD59, "Set CRC mode")\
- SD_CARD_ERROR(ACMD6, "Set SDIO bus width")\
- SD_CARD_ERROR(ACMD13, "Read extended status")\
- SD_CARD_ERROR(ACMD23, "Set pre-erased count")\
- SD_CARD_ERROR(ACMD41, "Activate card initialization")\
- SD_CARD_ERROR(ACMD51, "Read SCR data")\
- SD_CARD_ERROR(READ_TOKEN, "Bad read data token")\
- SD_CARD_ERROR(READ_CRC, "Read CRC error")\
- SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout")\
- SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.")\
- SD_CARD_ERROR(READ_START, "Bad readStart argument")\
- SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout")\
- SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed")\
- SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete")\
- SD_CARD_ERROR(WRITE_DATA, "Write data not accepted")\
- SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout")\
- SD_CARD_ERROR(WRITE_START, "Bad writeStart argument")\
- SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming")\
- SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout")\
- SD_CARD_ERROR(DMA, "DMA transfer failed")\
- SD_CARD_ERROR(ERASE, "Card did not accept erase commands")\
- SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase")\
- SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout")\
- SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized")\
- SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config")\
+/** Define error codes and brief description. */
+#define SD_ERROR_CODE_LIST \
+ SD_CARD_ERROR(NONE, "No error") \
+ SD_CARD_ERROR(CMD0, "Card reset failed") \
+ SD_CARD_ERROR(CMD2, "SDIO read CID") \
+ SD_CARD_ERROR(CMD3, "SDIO publish RCA") \
+ SD_CARD_ERROR(CMD6, "Switch card function") \
+ SD_CARD_ERROR(CMD7, "SDIO card select") \
+ SD_CARD_ERROR(CMD8, "Send and check interface settings") \
+ SD_CARD_ERROR(CMD9, "Read CSD data") \
+ SD_CARD_ERROR(CMD10, "Read CID data") \
+ SD_CARD_ERROR(CMD12, "Stop multiple block read") \
+ SD_CARD_ERROR(CMD13, "Read card status") \
+ SD_CARD_ERROR(CMD17, "Read single block") \
+ SD_CARD_ERROR(CMD18, "Read multiple blocks") \
+ SD_CARD_ERROR(CMD24, "Write single block") \
+ SD_CARD_ERROR(CMD25, "Write multiple blocks") \
+ SD_CARD_ERROR(CMD32, "Set first erase block") \
+ SD_CARD_ERROR(CMD33, "Set last erase block") \
+ SD_CARD_ERROR(CMD38, "Erase selected blocks") \
+ SD_CARD_ERROR(CMD58, "Read OCR register") \
+ SD_CARD_ERROR(CMD59, "Set CRC mode") \
+ SD_CARD_ERROR(ACMD6, "Set SDIO bus width") \
+ SD_CARD_ERROR(ACMD13, "Read extended status") \
+ SD_CARD_ERROR(ACMD23, "Set pre-erased count") \
+ SD_CARD_ERROR(ACMD41, "Activate card initialization") \
+ SD_CARD_ERROR(ACMD51, "Read SCR data") \
+ SD_CARD_ERROR(READ_TOKEN, "Bad read data token") \
+ SD_CARD_ERROR(READ_CRC, "Read CRC error") \
+ SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout") \
+ SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.") \
+ SD_CARD_ERROR(READ_START, "Bad readStart argument") \
+ SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout") \
+ SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed") \
+ SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete") \
+ SD_CARD_ERROR(WRITE_DATA, "Write data not accepted") \
+ SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout") \
+ SD_CARD_ERROR(WRITE_START, "Bad writeStart argument") \
+ SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming") \
+ SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout") \
+ SD_CARD_ERROR(DMA, "DMA transfer failed") \
+ SD_CARD_ERROR(ERASE, "Card did not accept erase commands") \
+ SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase") \
+ SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout") \
+ SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized") \
+ SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config") \
SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command")
enum {
+/** Macro for generation of error codes using an enum. */
#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e,
- SD_CARD_ERROR_UNKNOWN
+ SD_CARD_ERROR_UNKNOWN
+/** Print the enum symbol for an error code.
+ * \param[in] pr Print stream.
+ * \param[in] code enum value for error.
void printSdErrorSymbol(print_t* pr, uint8_t code);
+/** Print text for an error code.
void printSdErrorText(print_t* pr, uint8_t code);
// card types
/** Standard capacity V1 SD card */
-const uint8_t SD_CARD_TYPE_SD1 = 1;
+const uint8_t SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
-const uint8_t SD_CARD_TYPE_SD2 = 2;
+const uint8_t SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
const uint8_t SD_CARD_TYPE_SDHC = 3;
// SD operation timeouts
-/** CMD0 retry count */
-const uint8_t SD_CMD0_RETRY = 10;
/** command timeout ms */
const uint16_t SD_CMD_TIMEOUT = 300;
/** erase timeout ms */
@@ -186,7 +199,7 @@ const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30;
/** The transferred sector length is not allowed for this card. */
const uint32_t CARD_STATUS_SECTOR_LEN_ERROR = 1UL << 29;
/** An error in the sequence of erase commands occurred. */
-const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL <<28;
+const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL << 28;
/** An invalid selection of write-sectors for erase occurred. */
const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27;
/** Set when the host attempts to write to a protected sector. */
@@ -207,7 +220,7 @@ const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20;
const uint32_t CARD_STATUS_ERROR = 1UL << 19;
// bits 19, 18, and 17 reserved.
/** Permanent WP set or attempt to change read only values of CSD. */
-const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL <<16;
+const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL << 16;
/** partial address space was erased due to write protect. */
const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15;
/** The command has been executed without using the internal ECC. */
@@ -260,10 +273,10 @@ const uint8_t DATA_RES_MASK = 0X1F;
const uint8_t DATA_RES_ACCEPTED = 0X05;
- * \class CID
- * \brief Card IDentification (CID) register.
+ * \class cid_t
+ * \brief Card Identification (CID) register.
-typedef struct CID {
+struct cid_t {
// byte 0
/** Manufacturer ID */
uint8_t mid;
@@ -287,27 +300,25 @@ typedef struct CID {
uint8_t crc;
// Extract big endian fields.
/** \return major revision number. */
- int prvN() const {return prv >> 4;}
+ int prvN() const { return prv >> 4; }
/** \return minor revision number. */
- int prvM() const {return prv & 0XF;}
+ int prvM() const { return prv & 0XF; }
/** \return Manufacturing Year. */
- int mdtYear() const {return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4);}
+ int mdtYear() const { return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4); }
/** \return Manufacturing Month. */
- int mdtMonth() const {return mdt[1] & 0XF;}
+ int mdtMonth() const { return mdt[1] & 0XF; }
/** \return Product Serial Number. */
uint32_t psn() const {
- return (uint32_t)psn8[0] << 24 |
- (uint32_t)psn8[1] << 16 |
- (uint32_t)psn8[2] << 8 |
- (uint32_t)psn8[3];
+ return (uint32_t)psn8[0] << 24 | (uint32_t)psn8[1] << 16 |
+ (uint32_t)psn8[2] << 8 | (uint32_t)psn8[3];
-} __attribute__((packed)) cid_t;
+} __attribute__((packed));
- * \class CSD
+ * \class csd_t
* \brief Union of old and new style CSD register.
-typedef struct CSD {
+struct csd_t {
/** union of all CSD versions */
uint8_t csd[16];
@@ -331,45 +342,45 @@ typedef struct CSD {
/** \return true if erase granularity is single block. */
- bool eraseSingleBlock() const {return csd[10] & 0X40;}
+ bool eraseSingleBlock() const { return csd[10] & 0X40; }
/** \return erase size in 512 byte blocks if eraseSingleBlock is false. */
- int eraseSize() const {return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1;}
+ int eraseSize() const { return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1; }
/** \return true if the contents is copied or true if original. */
- bool copy() const {return csd[14] & 0X40;}
+ bool copy() const { return csd[14] & 0X40; }
/** \return true if the entire card is permanently write protected. */
- bool permWriteProtect() const {return csd[14] & 0X20;}
+ bool permWriteProtect() const { return csd[14] & 0X20; }
/** \return true if the entire card is temporarily write protected. */
- bool tempWriteProtect() const {return csd[14] & 0X10;}
-} csd_t;
+ bool tempWriteProtect() const { return csd[14] & 0X10; }
+};
- * \class SCR
+ * \class scr_t
* \brief SCR register.
-typedef struct SCR {
+struct scr_t {
/** Bytes 0-3 SD Association, bytes 4-7 reserved for manufacturer. */
uint8_t scr[8];
/** \return SCR_STRUCTURE field - must be zero.*/
- uint8_t srcStructure() {return scr[0] >> 4;}
+ uint8_t srcStructure() const { return scr[0] >> 4; }
/** \return SD_SPEC field 0 - v1.0 or V1.01, 1 - 1.10, 2 - V2.00 or greater */
- uint8_t sdSpec() {return scr[0] & 0XF;}
+ uint8_t sdSpec() const { return scr[0] & 0XF; }
/** \return false if all zero, true if all one. */
- bool dataAfterErase() {return 0X80 & scr[1];}
+ bool dataAfterErase() const { return scr[1] & 0X80; }
/** \return CPRM Security Version. */
- uint8_t sdSecurity() {return (scr[1] >> 4) & 0X7;}
+ uint8_t sdSecurity() const { return (scr[1] >> 4) & 0X7; }
/** \return 0101b. */
- uint8_t sdBusWidths() {return scr[1] & 0XF;}
+ uint8_t sdBusWidths() const { return scr[1] & 0XF; }
/** \return true if V3.0 or greater. */
- bool sdSpec3() {return scr[2] & 0X80;}
+ bool sdSpec3() const { return scr[2] & 0X80; }
/** \return if true and sdSpecX is zero V4.xx. */
- bool sdSpec4() {return scr[2] & 0X4;}
+ bool sdSpec4() const { return scr[2] & 0X4; }
/** \return nonzero for version 5 or greater if sdSpec == 2,
sdSpec3 == true. Version is return plus four.*/
- uint8_t sdSpecX() {return (scr[2] & 0X3) << 2 | scr[3] >> 6;}
+ uint8_t sdSpecX() const { return (scr[2] & 0X3) << 2 | scr[3] >> 6; }
/** \return bit map for support CMD58/59, CMD48/49, CMD23, and CMD20 */
- uint8_t cmdSupport() {return scr[3] &0XF;}
+ uint8_t cmdSupport() const { return scr[3] & 0XF; }
/** \return SD spec version */
- int16_t sdSpecVer() {
+ int16_t sdSpecVer() const {
if (sdSpec() > 2) {
} else if (sdSpec() < 2) {
@@ -379,42 +390,88 @@ typedef struct SCR {
} else if (!sdSpec4() && !sdSpecX()) {
return 300;
- return 400 + 100*sdSpecX();
+ return 400 + 100 * sdSpecX();
-} scr_t;
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ * \class sds_t
+ * \brief SD Status.
// fields are big endian
-typedef struct SdStatus {
- //
+struct sds_t {
+ /** byte 0, bit 7-6 width, bit 5 secured mode, bits 4-0 reserved. */
uint8_t busWidthSecureMode;
+ /** byte 1 reserved */
uint8_t reserved1;
- // byte 2
+ /** byte 2-3 zero for SD rd/wr memory card. */
uint8_t sdCardType[2];
- // byte 4
+ /** byte 4-7 size of protected area big endian */
uint8_t sizeOfProtectedArea[4];
- // byte 8
- uint8_t speedClass;
- // byte 9
+ /** byte 8 speed class. */
+ uint8_t speed;
+ /** byte 9 performance move */
uint8_t performanceMove;
- // byte 10
+ /** byte 10 AU size code. */
uint8_t auSize;
- // byte 11
+ /** byte 11-12 erase size big endian */
uint8_t eraseSize[2];
- // byte 13
+ /** byte 13 erase timeout and erase offset */
uint8_t eraseTimeoutOffset;
- // byte 14
- uint8_t uhsSpeedAuSize;
- // byte 15
- uint8_t videoSpeed;
- // byte 16
+ /** byte 14 */
+ uint8_t uhsClassAuSize;
+ /** byte 15 */
+ uint8_t videoSpeedClass;
+ /** byte 16-17 */
uint8_t vscAuSize[2];
- // byte 18
+ /** byte 18-21 */
uint8_t susAddr[3];
- // byte 21
- uint8_t reserved2[3];
- // byte 24
+ /** byte 21 */
+ uint8_t appPerfClass;
+ /** byte 22 */
+ uint8_t perfEnhance;
+ /** byte 23 */
+ uint8_t discardFule;
+ /** byte 24 */
uint8_t reservedManufacturer[40];
-} SdStatus_t;
-#endif // DOXYGEN_SHOULD_SKIP_THIS
+ /** \return appClass. */
+ int appClass() { return appPerfClass; }
+ /** \return AU size in KB. or zero for error. */
+ uint32_t auSizeKB() {
+ // 0XF mask and uint16_t array helps compiler optimize size on Uno.
+ uint8_t val = (auSize >> 4) & 0XF;
+ static const uint16_t au[] = {0, 16, 32, 64, 128,
+ 256, 512, 1024, 2048, 4096,
+ 8192, 12288, 16384, 24576, 32768};
+ return val < 0XF ? au[val] : 65536UL;
+ /** \return current bus width or -1 for error. */
+ uint8_t busWidth() const {
+ uint8_t w = busWidthSecureMode >> 6;
+ return w == 2 ? 4 : w == 0 ? 1 : -1;
+ /** \return true is discard operation is supported else true. */
+ bool discard() const { return discardFule & 2; }
+ /** \return eraseSize in AUs. */
+ uint16_t eraseSizeAU() const {
+ return (uint16_t)eraseSize[0] << 8 | (uint16_t)eraseSize[1];
+ /** \return eraseTimeout seconds. */
+ uint8_t eraseTimeout() const { return eraseTimeoutOffset >> 2; }
+ /** \return eraseOffset seconds. */
+ uint8_t eraseOffset() const { return eraseTimeoutOffset & 3; }
+ /** \return true if full user logical erase is supported else false. */
+ bool fule() const { return discardFule & 1; }
+ /** \return true for secure mode else false. */
+ bool secureMode() const { return busWidthSecureMode & 0X20; }
+ /** \return speed class or -1 for error. */
+ int speedClass() const {
+ return speed < 4 ? 2 * speed : speed == 4 ? 10 : -1;
+ /** \return UHS Speed Grade. */
+ int uhsClass() const { return uhsClassAuSize >> 4; }
+ /** \return Video Speed */
+ int videoClass() { return videoSpeedClass; }
#endif // SdCardInfo_h
@@ -22,6 +22,10 @@
+ * \brief Abstract interface for an SD card.
#ifndef SdCardInterface_h
#define SdCardInterface_h
#include "../common/FsBlockDeviceInterface.h"
@@ -39,9 +43,7 @@ class SdCardInterface : public FsBlockDeviceInterface {
virtual bool cardCMD6(uint32_t arg, uint8_t* status) = 0;
- /** end use of card */
- virtual void end() = 0;
- /** Erase a range of sectors.
+ /** Erase a range of sectors.
* \param[in] firstSector The address of the first sector in the range.
* \param[in] lastSector The address of the last sector in the range.
@@ -53,12 +55,10 @@ class SdCardInterface : public FsBlockDeviceInterface {
virtual uint8_t errorCode() const = 0;
/** \return error data. */
virtual uint32_t errorData() const = 0;
- /** \return true if card is busy. */
- virtual bool isBusy() = 0;
/** \return false by default */
- virtual bool hasDedicatedSpi() {return false;}
+ virtual bool hasDedicatedSpi() { return false; }
- bool virtual isDedicatedSpi() {return false;}
+ bool virtual isDedicatedSpi() { return false; }
/** Set SPI sharing state
* \param[in] value desired state.
* \return false by default.
@@ -75,7 +75,7 @@ class SdCardInterface : public FsBlockDeviceInterface {
virtual bool readCID(cid_t* cid) = 0;
* Read a card's CSD register.
* \param[out] csd pointer to area for returned data.
@@ -94,16 +94,14 @@ class SdCardInterface : public FsBlockDeviceInterface {
* \param[out] scr Value of SCR register.
- virtual bool readSCR(scr_t *scr) = 0;
- * Determine the size of an SD flash memory card.
- * \return The number of 512 byte data sectors in the card
- * or zero if an error occurs.
+ virtual bool readSCR(scr_t* scr) = 0;
+ /** Return the 64 byte SD Status register.
+ * \param[out] sds location for 64 status bytes.
- virtual uint32_t sectorCount() = 0;
+ virtual bool readSDS(sds_t* sds) = 0;
/** \return card status. */
- virtual uint32_t status() {return 0XFFFFFFFF;}
+ virtual uint32_t status() { return 0XFFFFFFFF; }
/** Return the card type: SD V1, SD V2 or SDHC/SDXC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC.
@@ -27,14 +27,11 @@
class Timeout {
Timeout() {}
- explicit Timeout(uint16_t ms) {set(ms);}
- uint16_t millis16() {return millis();}
- void set(uint16_t ms) {
- m_endTime = ms + millis16();
- bool timedOut() {
- return (int16_t)(m_endTime - millis16()) < 0;
+ explicit Timeout(uint16_t ms) { set(ms); }
+ uint16_t millis16() { return millis(); }
+ void set(uint16_t ms) { m_endTime = ms + millis16(); }
+ bool timedOut() { return (int16_t)(m_endTime - millis16()) < 0; }
uint16_t m_endTime;
@@ -77,48 +74,44 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
// uses the x^16,x^12,x^5,x^1 polynomial.
static const uint16_t crctab[] PROGMEM = {
static const uint16_t crctab[] = {
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
- 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
- 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
- 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
- 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
- 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
- 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
- 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
- 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
- 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
- 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
- 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
- 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
- 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
- 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
- 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
- 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
- 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
- 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
- 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
- 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
- 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
- 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
-};
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
+ 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
+ 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
+ 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
+ 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
+ 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
+ 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
+ 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
+ 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
+ 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
+ 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
+ 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
+ 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
+ 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
+ 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
+ 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
+ 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
+ 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
+ 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
+ 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
+ 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
+ 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
+ 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
+ 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
+ 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
+ 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
uint16_t crc = 0;
for (size_t i = 0; i < n; i++) {
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
crc = crctab[(crc >> 8 ^ data[i]) & 0XFF] ^ (crc << 8);
@@ -131,10 +124,9 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
Timeout timeout;
- m_spiActive = false;
- m_beginCalled = false;
+ // Restore state to creator.
+ initSharedSpiCard();
m_errorCode = SD_CARD_ERROR_NONE;
- m_type = 0;
m_csPin = spiConfig.csPin;
#if SPI_DRIVER_SELECT >= 2
m_spiDriverPtr = spiConfig.spiPort;
@@ -145,32 +137,28 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
sdCsInit(m_csPin);
spiUnselect();
- spiSetSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ);
+ spiSetSckSpeed(1000UL * SD_MAX_INIT_RATE_KHZ);
spiBegin(spiConfig);
m_beginCalled = true;
uint32_t arg;
- m_state = IDLE_STATE;
spiStart();
// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) {
- spiSend(0XFF);
+ spiReceive();
spiSelect();
- // command to go idle in SPI mode
- for (uint8_t i = 1;; i++) {
+ timeout.set(SD_INIT_TIMEOUT);
+ // command to go idle in SPI mode
if (cardCommand(CMD0, 0) == R1_IDLE_STATE) {
- if (i == SD_CMD0_RETRY) {
+ if (timeout.timedOut()) {
error(SD_CARD_ERROR_CMD0);
- // Force any active transfer to end for an already initialized card.
- for (uint8_t j = 0; j < 0XFF; j++) {
#if USE_SD_CRC
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
@@ -179,21 +167,26 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
#endif // USE_SD_CRC
// check SD version
- if (!(cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
- type(SD_CARD_TYPE_SD2);
+ if (cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND) {
+ type(SD_CARD_TYPE_SD1);
+ // Skip first three bytes.
m_status = spiReceive();
- if (m_status != 0XAA) {
+ if (m_status == 0XAA) {
+ type(SD_CARD_TYPE_SD2);
error(SD_CARD_ERROR_CMD8);
- type(SD_CARD_TYPE_SD1);
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
- timeout.set(SD_INIT_TIMEOUT);
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
// check for timeout
if (timeout.timedOut()) {
@@ -201,7 +194,6 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
@@ -220,7 +212,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
spiSetSckSpeed(spiConfig.maxSck);
spiStop();
@@ -236,7 +228,7 @@ bool SharedSpiCard::cardCMD6(uint32_t arg, uint8_t* status) {
@@ -267,7 +259,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
// send message
spiSend(buf, 6);
-#else // USE_SD_CRC
+#else // USE_SD_CRC
// send command
spiSend(cmd | 0x40);
@@ -285,7 +277,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
spiReceive();
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
- uint16_t n = 0;
+ uint8_t n = 0;
} while (m_status & 0X80 && ++n < 10);
@@ -294,7 +286,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
void SharedSpiCard::end() {
if (m_beginCalled) {
- spiStop();
+ syncDevice();
spiEnd();
m_beginCalled = false;
@@ -319,9 +311,8 @@ bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
firstSector <<= 9;
lastSector <<= 9;
- if (cardCommand(CMD32, firstSector)
- || cardCommand(CMD33, lastSector)
- || cardCommand(CMD38, 0)) {
+ if (cardCommand(CMD32, firstSector) || cardCommand(CMD33, lastSector) ||
+ cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
@@ -332,7 +323,7 @@ bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
@@ -357,9 +348,7 @@ bool SharedSpiCard::isBusy() {
-bool SharedSpiCard::readData(uint8_t* dst) {
- return readData(dst, 512);
+bool SharedSpiCard::readData(uint8_t* dst) { return readData(dst, 512); }
bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
@@ -391,14 +380,14 @@ bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
error(SD_CARD_ERROR_READ_CRC);
// discard crc
@@ -412,14 +401,14 @@ bool SharedSpiCard::readOCR(uint32_t* ocr) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
p[3 - i] = spiReceive();
-#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
p[i] = spiReceive();
#endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -437,7 +426,7 @@ bool SharedSpiCard::readRegister(uint8_t cmd, void* buf) {
@@ -454,7 +443,7 @@ bool SharedSpiCard::readSCR(scr_t* scr) {
@@ -474,7 +463,7 @@ bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
@@ -489,7 +478,7 @@ bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
return readStop();
@@ -504,25 +493,25 @@ bool SharedSpiCard::readStart(uint32_t sector) {
m_state = READ_STATE;
-bool SharedSpiCard::readStatus(SdStatus* status) {
- uint8_t* dst = reinterpret_cast<uint8_t*>(status);
+bool SharedSpiCard::readSDS(sds_t* sds) {
+ uint8_t* dst = reinterpret_cast<uint8_t*>(sds);
// retrun is R2 so read extra status byte.
if (cardAcmd(ACMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_ACMD13);
- if (!readData(dst, 64)) {
+ if (!readData(dst, sizeof(sds_t))) {
@@ -536,7 +525,7 @@ bool SharedSpiCard::readStop() {
@@ -547,6 +536,7 @@ uint32_t SharedSpiCard::sectorCount() {
void SharedSpiCard::spiStart() {
+ SPI_ASSERT_NOT_ACTIVE;
if (!m_spiActive) {
spiActivate();
m_spiActive = true;
@@ -557,6 +547,7 @@ void SharedSpiCard::spiStart() {
void SharedSpiCard::spiStop() {
+ SPI_ASSERT_ACTIVE;
if (m_spiActive) {
// Insure MISO goes to low Z.
@@ -597,7 +588,7 @@ bool SharedSpiCard::writeData(const uint8_t* src) {
@@ -606,7 +597,7 @@ bool SharedSpiCard::writeData(const uint8_t* src) {
bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
uint16_t crc = CRC_CCITT(src, 512);
uint16_t crc = 0XFFFF;
spiSend(token);
@@ -621,7 +612,7 @@ bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
@@ -655,13 +646,13 @@ bool SharedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
-bool SharedSpiCard::writeSectors(uint32_t sector,
- const uint8_t* src, size_t ns) {
+bool SharedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
+ size_t ns) {
if (!writeStart(sector)) {
@@ -672,7 +663,7 @@ bool SharedSpiCard::writeSectors(uint32_t sector,
return writeStop();
@@ -689,7 +680,7 @@ bool SharedSpiCard::writeStart(uint32_t sector) {
m_state = WRITE_STATE;
@@ -703,7 +694,7 @@ bool SharedSpiCard::writeStop() {
m_state = IDLE_STATE;
error(SD_CARD_ERROR_STOP_TRAN);
@@ -721,8 +712,7 @@ bool DedicatedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
return readSectors(sector, dst, 1);
-bool DedicatedSpiCard::readSectors(
- uint32_t sector, uint8_t* dst, size_t ns) {
+bool DedicatedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
if (sdState() != READ_STATE || sector != m_curSector) {
if (!readStart(sector)) {
@@ -737,7 +727,7 @@ bool DedicatedSpiCard::readSectors(
m_curSector += ns;
return m_dedicatedSpi ? true : readStop();
@@ -756,8 +746,8 @@ bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
return SharedSpiCard::writeSector(sector, src);
-bool DedicatedSpiCard::writeSectors(
- uint32_t sector, const uint8_t* src, size_t ns) {
+bool DedicatedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
if (sdState() != WRITE_STATE || m_curSector != sector) {
@@ -24,25 +24,43 @@
- * \brief SdSpiCard class for V2 SD/SDHC cards
+ * \brief Classes for SPI access to SD/SDHC cards.
#ifndef SdSpiCard_h
#define SdSpiCard_h
+#include "../SpiDriver/SdSpiDriver.h"
#include "SdCardInterface.h"
-#include "../SpiDriver/SdSpiDriver.h"
/** Verify correct SPI active if non-zero. */
#define CHECK_SPI_ACTIVE 0
#if CHECK_SPI_ACTIVE
/** Check SPI active. */
-#define SPI_ASSERT_ACTIVE {if (!m_spiActive) {\
- Serial.print(F("SPI_ASSERTACTIVE"));\
- Serial.println(__LINE__);}}
+#define SPI_ASSERT_ACTIVE \
+ if (!m_spiActive) { \
+ Serial.print(F("SPI_ASSERT_ACTIVE")); \
+ Serial.println(__LINE__); \
+ while (true) \
+ ; \
+ } \
+#define SPI_ASSERT_NOT_ACTIVE \
+ if (m_spiActive) { \
+ Serial.print(F("SPI_ASSERT_NOT_ACTIVE")); \
#else // CHECK_SPI_ACTIVE
-/** Do not check SPI active. */
+/** Check for SPI active. */
#define SPI_ASSERT_ACTIVE
+/** Check for SPI not active. */
+#define SPI_ASSERT_NOT_ACTIVE
#endif // CHECK_SPI_ACTIVE
@@ -53,7 +71,7 @@
class SharedSpiCard : public SdCardInterface {
#elif USE_BLOCK_DEVICE_INTERFACE
class SharedSpiCard : public FsBlockDeviceInterface {
class SharedSpiCard {
@@ -64,7 +82,7 @@ class SharedSpiCard {
/** SD is in multi-sector write state. */
static const uint8_t WRITE_STATE = 2;
/** Construct an instance of SharedSpiCard. */
- SharedSpiCard() {}
+ SharedSpiCard() { initSharedSpiCard(); }
/** Initialize the SD card.
* \param[in] spiConfig SPI card configuration.
@@ -103,21 +121,18 @@ class SharedSpiCard {
* \param[in] code value for error code.
void error(uint8_t code) {
-// (void)code;
+ // (void)code;
m_errorCode = code;
- * \return code for the last error. See SdCardInfo.h for a list of error codes.
+ * \return code for the last error. See SdCardInfo.h for a list of error
+ * codes.
- uint8_t errorCode() const {
- return m_errorCode;
+ uint8_t errorCode() const { return m_errorCode; }
/** \return error data for last error. */
- uint32_t errorData() const {
- return m_status;
+ uint32_t errorData() const { return m_status; }
/** \return false for shared class. */
- bool hasDedicatedSpi() {return false;}
+ bool hasDedicatedSpi() { return false; }
* Check for busy. MISO low indicates the card is busy.
@@ -125,7 +140,7 @@ class SharedSpiCard {
/** \return false, can't be in dedicated state. */
- bool isDedicatedSpi() {return false;}
+ bool isDedicatedSpi() { return false; }
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
@@ -135,9 +150,7 @@ class SharedSpiCard {
- bool readCID(cid_t* cid) {
- return readRegister(CMD10, cid);
+ bool readCID(cid_t* cid) { return readRegister(CMD10, cid); }
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
@@ -146,9 +159,7 @@ class SharedSpiCard {
- bool readCSD(csd_t* csd) {
- return readRegister(CMD9, csd);
+ bool readCSD(csd_t* csd) { return readRegister(CMD9, csd); }
/** Read one data sector in a multiple sector read sequence
* \param[out] dst Pointer to the location for the data to be read.
@@ -196,18 +207,18 @@ class SharedSpiCard {
bool readStart(uint32_t sector);
- /** Return the 64 byte card status
* \param[out] status location for 64 status bytes.
- bool readStatus(SdStatus* status);
+ bool readSDS(sds_t* status);
/** End a read multiple sectors sequence.
bool readStop();
/** \return SD multi-sector read/write state */
- uint8_t sdState() {return m_state;}
+ uint8_t sdState() { return m_state; }
* Determine the size of an SD flash memory card.
@@ -237,9 +248,7 @@ class SharedSpiCard {
- uint8_t type() const {
- return m_type;
+ uint8_t type() const { return m_type; }
* Write a 512 byte sector to an SD card.
@@ -288,32 +297,18 @@ class SharedSpiCard {
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);
- void spiSelect() {
- sdCsWrite(m_csPin, false);
+ void spiSelect() { sdCsWrite(m_csPin, false); }
void spiStart();
void spiStop();
- void spiUnselect() {
- sdCsWrite(m_csPin, true);
- void type(uint8_t value) {
- m_type = value;
+ void spiUnselect() { sdCsWrite(m_csPin, true); }
+ void type(uint8_t value) { m_type = value; }
bool waitReady(uint16_t ms);
bool writeData(uint8_t token, const uint8_t* src);
#if SPI_DRIVER_SELECT < 2
- void spiActivate() {
- m_spiDriver.activate();
- void spiBegin(SdSpiConfig spiConfig) {
- m_spiDriver.begin(spiConfig);
- void spiDeactivate() {
- m_spiDriver.deactivate();
- void spiEnd() {
- m_spiDriver.end();
+ void spiActivate() { m_spiDriver.activate(); }
+ void spiBegin(SdSpiConfig spiConfig) { m_spiDriver.begin(spiConfig); }
+ void spiDeactivate() { m_spiDriver.deactivate(); }
+ void spiEnd() { m_spiDriver.end(); }
uint8_t spiReceive() {
SPI_ASSERT_ACTIVE;
return m_spiDriver.receive();
@@ -330,23 +325,13 @@ class SharedSpiCard {
m_spiDriver.send(buf, n);
- void spiSetSckSpeed(uint32_t maxSck) {
- m_spiDriver.setSckSpeed(maxSck);
+ void spiSetSckSpeed(uint32_t maxSck) { m_spiDriver.setSckSpeed(maxSck); }
SdSpiDriver m_spiDriver;
#else // SPI_DRIVER_SELECT < 2
- m_spiDriverPtr->activate();
- m_spiDriverPtr->begin(spiConfig);
- m_spiDriverPtr->deactivate();
- m_spiDriverPtr->end();
+ void spiActivate() { m_spiDriverPtr->activate(); }
+ void spiBegin(SdSpiConfig spiConfig) { m_spiDriverPtr->begin(spiConfig); }
+ void spiDeactivate() { m_spiDriverPtr->deactivate(); }
+ void spiEnd() { m_spiDriverPtr->end(); }
return m_spiDriverPtr->receive();
@@ -363,21 +348,27 @@ class SharedSpiCard {
m_spiDriverPtr->send(buf, n);
- m_spiDriverPtr->setSckSpeed(maxSck);
+ void spiSetSckSpeed(uint32_t maxSck) { m_spiDriverPtr->setSckSpeed(maxSck); }
SdSpiDriver* m_spiDriverPtr;
#endif // SPI_DRIVER_SELECT < 2
- bool m_beginCalled = false;
+ void initSharedSpiCard() {
+ m_beginCalled = false;
+ m_csPin = 0;
+ m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
+ m_spiActive = false;
+ m_state = IDLE_STATE;
+ m_status = 0;
+ m_type = 0;
+ bool m_beginCalled;
SdCsPin_t m_csPin;
- uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
- bool m_spiActive;
+ uint8_t m_errorCode;
+ bool m_spiActive;
uint8_t m_state;
uint8_t m_status;
- uint8_t m_type = 0;
+ uint8_t m_type;
* \class DedicatedSpiCard
@@ -386,16 +377,16 @@ class SharedSpiCard {
class DedicatedSpiCard : public SharedSpiCard {
/** Construct an instance of DedicatedSpiCard. */
- DedicatedSpiCard() {}
+ DedicatedSpiCard() = default;
bool begin(SdSpiConfig spiConfig);
/** \return true, can be in dedicaded state. */
- bool hasDedicatedSpi() {return true;}
+ bool hasDedicatedSpi() { return true; }
/** \return true if in dedicated SPI state. */
- bool isDedicatedSpi() {return m_dedicatedSpi;}
+ bool isDedicatedSpi() { return m_dedicatedSpi; }
* Read a 512 byte sector from an SD card.
@@ -437,7 +428,7 @@ class DedicatedSpiCard : public SharedSpiCard {
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
- uint32_t m_curSector;
+ uint32_t m_curSector = 0;
bool m_dedicatedSpi = false;
@@ -22,12 +22,17 @@
+ * \brief Classes for SDIO cards.
#ifndef SdioCard_h
#define SdioCard_h
+/** Use programmed I/O with FIFO. */
#define FIFO_SDIO 0
+/** Use programmed I/O with DMA. */
#define DMA_SDIO 1
* \class SdioConfig
@@ -42,9 +47,10 @@ class SdioConfig {
explicit SdioConfig(uint8_t opt) : m_options(opt) {}
/** \return SDIO card options. */
- uint8_t options() {return m_options;}
+ uint8_t options() { return m_options; }
/** \return true if DMA_SDIO. */
- bool useDma() {return m_options & DMA_SDIO;}
+ bool useDma() { return m_options & DMA_SDIO; }
uint8_t m_options = FIFO_SDIO;
@@ -73,7 +79,7 @@ class SdioCard : public SdCardInterface {
void end() {}
- uint32_t __attribute__((error("use sectorCount()"))) cardSize();
+ uint32_t __attribute__((error("use sectorCount()"))) cardSize();
/** Erase a range of sectors.
@@ -89,7 +95,8 @@ class SdioCard : public SdCardInterface {
bool erase(uint32_t firstSector, uint32_t lastSector);
uint8_t errorCode() const;
@@ -158,7 +165,12 @@ class SdioCard : public SdCardInterface {
- bool readSCR(scr_t *scr);
+ bool readSCR(scr_t* scr);
+ bool readSDS(sds_t* sds);
/** Start a read multiple sectors sequence.
* \param[in] sector Address of first sector in sequence.
@@ -186,7 +198,7 @@ class SdioCard : public SdCardInterface {
/** \return SDIO card status. */
uint32_t status();
* \return The number of 512 byte data sectors in the card
@@ -24,6 +24,7 @@
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
#include "SdioTeensy.h"
#include "SdioCard.h"
@@ -36,39 +37,34 @@ const uint32_t CMD8_RETRIES = 3;
const uint32_t BUSY_TIMEOUT_MICROS = 1000000;
const uint32_t SDHC_IRQSTATEN_MASK =
- SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
- SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
- SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
- SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN |
- SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN |
- SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
+ SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN | SDHC_IRQSTATEN_DEBESEN |
+ SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
+ SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN | SDHC_IRQSTATEN_CTOESEN |
+ SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
const uint32_t SDHC_IRQSTAT_CMD_ERROR =
- SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE |
- SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
+ SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE | SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
-const uint32_t SDHC_IRQSTAT_DATA_ERROR =
- SDHC_IRQSTAT_AC12E | SDHC_IRQSTAT_DEBE |
- SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE;
+const uint32_t SDHC_IRQSTAT_DATA_ERROR = SDHC_IRQSTAT_AC12E |
+ SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE |
+ SDHC_IRQSTAT_DTOE;
const uint32_t SDHC_IRQSTAT_ERROR =
- SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR |
- SDHC_IRQSTAT_DATA_ERROR;
+ SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR | SDHC_IRQSTAT_DATA_ERROR;
const uint32_t SDHC_IRQSIGEN_MASK =
- SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN |
- SDHC_IRQSIGEN_DEBEIEN | SDHC_IRQSIGEN_DCEIEN |
- SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
- SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN |
- SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN;
+ SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN | SDHC_IRQSIGEN_DEBEIEN |
+ SDHC_IRQSIGEN_DCEIEN | SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
+ SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN | SDHC_IRQSIGEN_CTOEIEN |
+ SDHC_IRQSIGEN_TCIEN;
const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0);
-const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
- SDHC_XFERTYP_RSPTYP(2);
+const uint32_t CMD_RESP_R1 =
+ SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(2);
-const uint32_t CMD_RESP_R1b = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
- SDHC_XFERTYP_RSPTYP(3);
+const uint32_t CMD_RESP_R1b =
+ SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(3);
const uint32_t CMD_RESP_R2 = SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(1);
@@ -86,26 +82,23 @@ const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
-const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL |
- SDHC_XFERTYP_BCEN;
+const uint32_t DATA_READ_MULTI_PGM =
+ DATA_READ | SDHC_XFERTYP_MSBSEL | SDHC_XFERTYP_BCEN;
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
-const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_MSBSEL |
+const uint32_t DATA_WRITE_MULTI_PGM =
+ SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_MSBSEL | SDHC_XFERTYP_BCEN;
// Use low bits for SDHC_MIX_CTRL since bits 15-0 of SDHC_XFERTYP are reserved.
-const uint32_t SDHC_MIX_CTRL_MASK = SDHC_MIX_CTRL_DMAEN | SDHC_MIX_CTRL_BCEN |
- SDHC_MIX_CTRL_AC12EN |
- SDHC_MIX_CTRL_DDR_EN |
- SDHC_MIX_CTRL_DTDSEL |
- SDHC_MIX_CTRL_MSBSEL |
- SDHC_MIX_CTRL_NIBBLE_POS |
- SDHC_MIX_CTRL_AC23EN;
+const uint32_t SDHC_MIX_CTRL_MASK =
+ SDHC_MIX_CTRL_DMAEN | SDHC_MIX_CTRL_BCEN | SDHC_MIX_CTRL_AC12EN |
+ SDHC_MIX_CTRL_DDR_EN | SDHC_MIX_CTRL_DTDSEL | SDHC_MIX_CTRL_MSBSEL |
+ SDHC_MIX_CTRL_NIBBLE_POS | SDHC_MIX_CTRL_AC23EN;
const uint32_t DATA_READ = SDHC_MIX_CTRL_DTDSEL | SDHC_XFERTYP_DPSEL;
@@ -116,7 +109,6 @@ const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_MIX_CTRL_MSBSEL |
const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_MIX_CTRL_MSBSEL;
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_DMAEN;
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_MIX_CTRL_MSBSEL |
@@ -128,10 +120,13 @@ const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_MSBSEL;
const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;
+const uint32_t ACMD13_XFERTYP =
+ SDHC_XFERTYP_CMDINX(ACMD13) | CMD_RESP_R1 | DATA_READ_DMA;
const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;
-const uint32_t ACMD51_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD51) | CMD_RESP_R1 |
- DATA_READ_DMA;
+const uint32_t ACMD51_XFERTYP =
+ SDHC_XFERTYP_CMDINX(ACMD51) | CMD_RESP_R1 | DATA_READ_DMA;
const uint32_t CMD0_XFERTYP = SDHC_XFERTYP_CMDINX(CMD0) | CMD_RESP_NONE;
@@ -139,8 +134,8 @@ const uint32_t CMD2_XFERTYP = SDHC_XFERTYP_CMDINX(CMD2) | CMD_RESP_R2;
const uint32_t CMD3_XFERTYP = SDHC_XFERTYP_CMDINX(CMD3) | CMD_RESP_R6;
-const uint32_t CMD6_XFERTYP = SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 |
+const uint32_t CMD6_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 | DATA_READ_DMA;
const uint32_t CMD7_XFERTYP = SDHC_XFERTYP_CMDINX(CMD7) | CMD_RESP_R1b;
@@ -152,28 +147,28 @@ const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2;
const uint32_t CMD11_XFERTYP = SDHC_XFERTYP_CMDINX(CMD11) | CMD_RESP_R1;
-const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b |
- SDHC_XFERTYP_CMDTYP(3);
+const uint32_t CMD12_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b | SDHC_XFERTYP_CMDTYP(3);
const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1;
-const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
+const uint32_t CMD17_DMA_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 | DATA_READ_DMA;
-const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
- DATA_READ_MULTI_DMA;
+const uint32_t CMD18_DMA_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | DATA_READ_MULTI_DMA;
-const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
- DATA_READ_MULTI_PGM;
+const uint32_t CMD18_PGM_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | DATA_READ_MULTI_PGM;
-const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
- DATA_WRITE_DMA;
+const uint32_t CMD24_DMA_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 | DATA_WRITE_DMA;
-const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
- DATA_WRITE_MULTI_DMA;
+const uint32_t CMD25_DMA_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | DATA_WRITE_MULTI_DMA;
-const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
- DATA_WRITE_MULTI_PGM;
+const uint32_t CMD25_PGM_XFERTYP =
+ SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | DATA_WRITE_MULTI_PGM;
const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;
@@ -212,12 +207,20 @@ static uint32_t m_ocr;
static cid_t m_cid;
static csd_t m_csd;
static scr_t m_scr;
+static sds_t m_sds;
-#define DBG_TRACE Serial.print("TRACE."); Serial.println(__LINE__); delay(200);
+#define DBG_TRACE \
+ Serial.print("TRACE."); \
+ delay(200);
#define USE_DEBUG_MODE 0
#if USE_DEBUG_MODE
-#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
- Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}
+#define DBG_IRQSTAT() \
+ if (SDHC_IRQSTAT) { \
+ Serial.print(__LINE__); \
+ Serial.print(" IRQSTAT "); \
+ Serial.println(SDHC_IRQSTAT, HEX); \
static void printRegs(uint32_t line) {
uint32_t blkattr = SDHC_BLKATTR;
uint32_t xfertyp = SDHC_XFERTYP;
@@ -234,36 +237,68 @@ static void printRegs(uint32_t line) {
Serial.print(xfertyp >> 24);
Serial.print(" TYP");
Serial.print((xfertyp >> 2) & 3);
- if (xfertyp & SDHC_XFERTYP_DPSEL) {Serial.print(" DPSEL");}
+ if (xfertyp & SDHC_XFERTYP_DPSEL) {
+ Serial.print(" DPSEL");
Serial.print("PRSSTAT ");
Serial.print(prsstat, HEX);
- if (prsstat & SDHC_PRSSTAT_BREN) {Serial.print(" BREN");}
- if (prsstat & SDHC_PRSSTAT_BWEN) {Serial.print(" BWEN");}
- if (prsstat & SDHC_PRSSTAT_RTA) {Serial.print(" RTA");}
- if (prsstat & SDHC_PRSSTAT_WTA) {Serial.print(" WTA");}
- if (prsstat & SDHC_PRSSTAT_SDOFF) {Serial.print(" SDOFF");}
- if (prsstat & SDHC_PRSSTAT_PEROFF) {Serial.print(" PEROFF");}
- if (prsstat & SDHC_PRSSTAT_HCKOFF) {Serial.print(" HCKOFF");}
- if (prsstat & SDHC_PRSSTAT_IPGOFF) {Serial.print(" IPGOFF");}
- if (prsstat & SDHC_PRSSTAT_SDSTB) {Serial.print(" SDSTB");}
- if (prsstat & SDHC_PRSSTAT_DLA) {Serial.print(" DLA");}
- if (prsstat & SDHC_PRSSTAT_CDIHB) {Serial.print(" CDIHB");}
- if (prsstat & SDHC_PRSSTAT_CIHB) {Serial.print(" CIHB");}
+ if (prsstat & SDHC_PRSSTAT_BREN) {
+ Serial.print(" BREN");
+ if (prsstat & SDHC_PRSSTAT_BWEN) {
+ Serial.print(" BWEN");
+ if (prsstat & SDHC_PRSSTAT_RTA) {
+ Serial.print(" RTA");
+ if (prsstat & SDHC_PRSSTAT_WTA) {
+ Serial.print(" WTA");
+ if (prsstat & SDHC_PRSSTAT_SDOFF) {
+ Serial.print(" SDOFF");
+ if (prsstat & SDHC_PRSSTAT_PEROFF) {
+ Serial.print(" PEROFF");
+ if (prsstat & SDHC_PRSSTAT_HCKOFF) {
+ Serial.print(" HCKOFF");
+ if (prsstat & SDHC_PRSSTAT_IPGOFF) {
+ Serial.print(" IPGOFF");
+ if (prsstat & SDHC_PRSSTAT_SDSTB) {
+ Serial.print(" SDSTB");
+ if (prsstat & SDHC_PRSSTAT_DLA) {
+ Serial.print(" DLA");
+ if (prsstat & SDHC_PRSSTAT_CDIHB) {
+ Serial.print(" CDIHB");
+ if (prsstat & SDHC_PRSSTAT_CIHB) {
+ Serial.print(" CIHB");
Serial.print("PROCTL ");
Serial.print(proctl, HEX);
if (proctl & SDHC_PROCTL_SABGREQ) Serial.print(" SABGREQ");
Serial.print(" EMODE");
- Serial.print((proctl >>4) & 3);
+ Serial.print((proctl >> 4) & 3);
Serial.print(" DWT");
- Serial.print((proctl >>1) & 3);
+ Serial.print((proctl >> 1) & 3);
Serial.print("IRQSTAT ");
Serial.print(irqstat, HEX);
- if (irqstat & SDHC_IRQSTAT_BGE) {Serial.print(" BGE");}
- if (irqstat & SDHC_IRQSTAT_TC) {Serial.print(" TC");}
- if (irqstat & SDHC_IRQSTAT_CC) {Serial.print(" CC");}
+ if (irqstat & SDHC_IRQSTAT_BGE) {
+ Serial.print(" BGE");
+ if (irqstat & SDHC_IRQSTAT_TC) {
+ Serial.print(" TC");
+ if (irqstat & SDHC_IRQSTAT_CC) {
+ Serial.print(" CC");
Serial.print("\nm_irqstat ");
Serial.println(m_irqstat, HEX);
@@ -298,12 +333,12 @@ static void sdIrs() {
static void enableGPIO(bool enable) {
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
- const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
+ const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
const uint32_t PORT_PUP = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;
PORTE_PCR0 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D1
PORTE_PCR1 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D0
- PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
+ PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
PORTE_PCR3 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_CMD
PORTE_PCR4 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D3
PORTE_PCR5 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D2
@@ -317,7 +352,7 @@ static void initClock() {
// Enable SDHC clock.
SIM_SCGC3 |= SIM_SCGC3_SDHC;
-static uint32_t baseClock() { return F_CPU;}
+static uint32_t baseClock() { return F_CPU; }
@@ -335,13 +370,13 @@ static void enableGPIO(bool enable) {
const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE |
#if defined(ARDUINO_TEENSY41)
IOMUXC_SW_PAD_CTL_PAD_DSE(7) |
-#else // defined(ARDUINO_TEENSY41)
+#else // defined(ARDUINO_TEENSY41)
IOMUXC_SW_PAD_CTL_PAD_DSE(4) | ///// WHG
#endif // defined(ARDUINO_TEENSY41)
IOMUXC_SW_PAD_CTL_PAD_SPEED(2);
- const uint32_t DATA_MASK = CLOCK_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE |
- IOMUXC_SW_PAD_CTL_PAD_PUS(1);
+ const uint32_t DATA_MASK =
+ CLOCK_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE | IOMUXC_SW_PAD_CTL_PAD_PUS(1);
if (enable) {
gpioMux(0);
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; // DAT2
@@ -365,20 +400,20 @@ static void initClock() {
/* Enable USDHC clock. */
CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON);
CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK);
- CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
-// CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); / &0x7 WHG
+ CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
+ // CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); / &0x7 WHG
CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((1));
static uint32_t baseClock() {
uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1;
- return (528000000U * 3)/((CCM_ANALOG_PFD_528 & 0x3F)/6)/divider;
+ return (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider;
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Static functions.
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
- return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
+ return cardCommand(CMD55_XFERTYP, rca) && cardCommand(xfertyp, arg);
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
@@ -402,8 +437,25 @@ static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
- return (m_irqstat & SDHC_IRQSTAT_CC) &&
- !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
+ return (m_irqstat & SDHC_IRQSTAT_CC) && !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
+static bool cardACMD13(sds_t* scr) {
+ // ACMD13 returns 64 bytes.
+ if (waitTimeout(isBusyCMD13)) {
+ return sdError(SD_CARD_ERROR_CMD13);
+ enableDmaIrs();
+ SDHC_DSADDR = (uint32_t)scr;
+ SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
+ SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
+ if (!cardAcmd(m_rca, ACMD13_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_ACMD13);
+ if (!waitDmaStatus()) {
+ return sdError(SD_CARD_ERROR_DMA);
static bool cardACMD51(scr_t* scr) {
@@ -412,7 +464,7 @@ static bool cardACMD51(scr_t* scr) {
return sdError(SD_CARD_ERROR_CMD13);
enableDmaIrs();
- SDHC_DSADDR = (uint32_t)scr;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(8);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
if (!cardAcmd(m_rca, ACMD51_XFERTYP, 0)) {
@@ -435,7 +487,7 @@ static void initSDHC() {
// Disable GPIO clock.
enableGPIO(false);
-#if defined (__IMXRT1062__)
+#if defined(__IMXRT1062__)
SDHC_MIX_CTRL |= 0x80000000;
#endif // (__IMXRT1062__)
@@ -454,7 +506,7 @@ static void initSDHC() {
SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK;
attachInterruptVector(IRQ_SDHC, sdIrs);
- NVIC_SET_PRIORITY(IRQ_SDHC, 6*16);
+ NVIC_SET_PRIORITY(IRQ_SDHC, 6 * 16);
NVIC_ENABLE_IRQ(IRQ_SDHC);
// Send 80 clocks to card.
@@ -475,32 +527,22 @@ static bool isBusyCommandComplete() {
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
-static bool isBusyCommandInhibit() {
- return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
+static bool isBusyCommandInhibit() { return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB; }
-static bool isBusyDat() {
- return SDHC_PRSSTAT & (1 << 24) ? false : true;
+static bool isBusyDat() { return SDHC_PRSSTAT & (1 << 24) ? false : true; }
-static bool isBusyDMA() {
- return m_dmaBusy;
+static bool isBusyDMA() { return m_dmaBusy; }
-static bool isBusyFifoRead() {
- return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
+static bool isBusyFifoRead() { return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN); }
-static bool isBusyFifoWrite() {
- return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
+static bool isBusyFifoWrite() { return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN); }
static bool isBusyTransferComplete() {
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
-static bool rdWrSectors(uint32_t xfertyp,
- uint32_t sector, uint8_t* buf, size_t n) {
+static bool rdWrSectors(uint32_t xfertyp, uint32_t sector, uint8_t* buf,
+ size_t n) {
if ((3 & (uint32_t)buf) || n == 0) {
return sdError(SD_CARD_ERROR_DMA);
@@ -508,10 +550,10 @@ static bool rdWrSectors(uint32_t xfertyp,
- SDHC_DSADDR = (uint32_t)buf;
+ SDHC_DSADDR = (uint32_t)buf;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
- if (!cardCommand(xfertyp, m_highCapacity ? sector : 512*sector)) {
+ if (!cardCommand(xfertyp, m_highCapacity ? sector : 512 * sector)) {
return waitDmaStatus();
@@ -525,7 +567,7 @@ static bool readReg16(uint32_t xfertyp, void* data) {
uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3};
for (int i = 0; i < 15; i++) {
- d[14 - i] = sr[i/4] >> 8*(i%4);
+ d[14 - i] = sr[i / 4] >> 8 * (i % 4);
d[15] = 0;
@@ -536,16 +578,17 @@ static void setSdclk(uint32_t kHzMax) {
const uint32_t SDCLKFS_LIMIT = 0X100;
uint32_t dvs = 1;
uint32_t sdclkfs = 1;
- uint32_t maxSdclk = 1000*kHzMax;
+ uint32_t maxSdclk = 1000 * kHzMax;
uint32_t base = baseClock();
- while ((base/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
+ while ((base / (sdclkfs * DVS_LIMIT) > maxSdclk) &&
+ (sdclkfs < SDCLKFS_LIMIT)) {
sdclkfs <<= 1;
- while ((base/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
+ while ((base / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
dvs++;
- m_sdClkKhz = base/(1000*sdclkfs*dvs);
+ m_sdClkKhz = base / (1000 * sdclkfs * dvs);
sdclkfs >>= 1;
dvs--;
@@ -554,11 +597,12 @@ static void setSdclk(uint32_t kHzMax) {
// Change dividers.
- uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
- | SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK);
+ uint32_t sysctl =
+ SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_DVS_MASK |
+ SDHC_SYSCTL_SDCLKFS_MASK);
- SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs)
- | SDHC_SYSCTL_SDCLKFS(sdclkfs);
+ SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs) |
+ SDHC_SYSCTL_SDCLKFS(sdclkfs);
// Wait until the SDHC clock is stable.
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) {
@@ -667,14 +711,15 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
SDHC_SYSCTL |= SDHC_SYSCTL_RSTA;
- while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {}
+ while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {
// Must support 3.2-3.4 Volts
arg = m_version2 ? 0X40300000 : 0x00300000;
int m = micros();
if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
- ((micros() - m) > BUSY_TIMEOUT_MICROS)) {
+ ((micros() - m) > BUSY_TIMEOUT_MICROS)) {
return sdError(SD_CARD_ERROR_ACMD41);
} while ((SDHC_CMDRSP0 & 0x80000000) == 0);
@@ -713,11 +758,13 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
if (!cardACMD51(&m_scr)) {
+ if (!cardACMD13(&m_sds)) {
// Determine if High Speed mode is supported and set frequency.
// Check status[16] for error 0XF or status[16] for new mode 0X1.
uint8_t status[64];
- if (m_scr.sdSpec() > 0 &&
- cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
+ if (m_scr.sdSpec() > 0 && cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
kHzSdClk = 50000;
@@ -741,7 +788,7 @@ bool SdioCard::cardCMD6(uint32_t arg, uint8_t* status) {
- SDHC_DSADDR = (uint32_t)status;
+ SDHC_DSADDR = (uint32_t)status;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
if (!cardCommand(CMD6_XFERTYP, arg)) {
@@ -774,7 +821,7 @@ bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
return sdError(SD_CARD_ERROR_CMD32);
if (!cardCommand(CMD33_XFERTYP, lastSector)) {
- return sdError(SD_CARD_ERROR_CMD33);
+ return sdError(SD_CARD_ERROR_CMD33);
if (!cardCommand(CMD38_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD38);
@@ -785,17 +832,11 @@ bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
-uint8_t SdioCard::errorCode() const {
+uint8_t SdioCard::errorCode() const { return m_errorCode; }
-uint32_t SdioCard::errorData() const {
- return m_irqstat;
+uint32_t SdioCard::errorData() const { return m_irqstat; }
-uint32_t SdioCard::errorLine() const {
- return m_errorLine;
+uint32_t SdioCard::errorLine() const { return m_errorLine; }
bool SdioCard::isBusy() {
if (m_sdioConfig.useDma()) {
@@ -812,7 +853,7 @@ bool SdioCard::isBusy() {
m_transferActive = false;
stopTransmission(false);
@@ -821,17 +862,15 @@ bool SdioCard::isBusy() {
-uint32_t SdioCard::kHzSdClk() {
- return m_sdClkKhz;
+uint32_t SdioCard::kHzSdClk() { return m_sdClkKhz; }
bool SdioCard::readCID(cid_t* cid) {
- memcpy(cid, &m_cid, 16);
+ memcpy(cid, &m_cid, sizeof(cid_t));
bool SdioCard::readCSD(csd_t* csd) {
- memcpy(csd, &m_csd, 16);
+ memcpy(csd, &m_csd, sizeof(csd_t));
@@ -849,7 +888,7 @@ bool SdioCard::readData(uint8_t* dst) {
if (waitTimeout(isBusyFifoRead)) {
return sdError(SD_CARD_ERROR_READ_FIFO);
- for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
+ for (uint32_t iw = 0; iw < 512 / (4 * FIFO_WML); iw++) {
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
for (uint32_t i = 0; i < FIFO_WML; i++) {
@@ -871,7 +910,12 @@ bool SdioCard::readOCR(uint32_t* ocr) {
bool SdioCard::readSCR(scr_t* scr) {
- memcpy(scr, &m_scr, 8);
+ memcpy(scr, &m_scr, sizeof(scr_t));
+bool SdioCard::readSDS(sds_t* sds) {
+ memcpy(sds, &m_sds, sizeof(sds_t));
@@ -931,7 +975,7 @@ bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n) {
- if (!readSector(sector + i, dst + i*512UL)) {
+ if (!readSector(sector + i, dst + i * 512UL)) {
@@ -949,28 +993,22 @@ bool SdioCard::readStart(uint32_t sector) {
#if defined(__IMXRT1062__)
// Infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
+#else // defined(__IMXRT1062__)
// Errata - can't do infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(MAX_BLKCNT) | SDHC_BLKATTR_BLKSIZE(512);
- if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
+ if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512 * sector)) {
return sdError(SD_CARD_ERROR_CMD18);
-bool SdioCard::readStop() {
- return transferStop();
+bool SdioCard::readStop() { return transferStop(); }
-uint32_t SdioCard::sectorCount() {
- return m_csd.capacity();
+uint32_t SdioCard::sectorCount() { return m_csd.capacity(); }
-uint32_t SdioCard::status() {
- return statusCMD13();
+uint32_t SdioCard::status() { return statusCMD13(); }
bool SdioCard::stopTransmission(bool blocking) {
m_curState = IDLE_STATE;
@@ -998,8 +1036,8 @@ bool SdioCard::syncDevice() {
uint8_t SdioCard::type() const {
- return m_version2 ? m_highCapacity ?
- SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
+ return m_version2 ? m_highCapacity ? SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2
+ : SD_CARD_TYPE_SD1;
bool SdioCard::writeData(const uint8_t* src) {
@@ -1016,7 +1054,7 @@ bool SdioCard::writeData(const uint8_t* src) {
if (waitTimeout(isBusyFifoWrite)) {
return sdError(SD_CARD_ERROR_WRITE_FIFO);
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) {
@@ -1057,7 +1095,7 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
if (!syncDevice()) {
- if (!writeStart(sector )) {
+ if (!writeStart(sector)) {
m_curSector = sector;
@@ -1087,7 +1125,7 @@ bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n) {
- if (!writeSector(sector + i, src + i*512UL)) {
+ if (!writeSector(sector + i, src + i * 512UL)) {
@@ -1104,17 +1142,15 @@ bool SdioCard::writeStart(uint32_t sector) {
- if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
+ if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512 * sector)) {
return sdError(SD_CARD_ERROR_CMD25);
-bool SdioCard::writeStop() {
+bool SdioCard::writeStop() { return transferStop(); }
#endif // defined(__MK64FX512__) defined(__MK66FX1M0__) defined(__IMXRT1062__)
@@ -1,277 +1,530 @@
+ * \brief Definitions for Teensy HDHC.
#ifndef SdioTeensy_h
#define SdioTeensy_h
// From Paul's SD.h driver.
-#define MAKE_REG_MASK(m,s) (((uint32_t)(((uint32_t)(m) << s))))
-#define MAKE_REG_GET(x,m,s) (((uint32_t)(((uint32_t)(x)>>s) & m)))
-#define MAKE_REG_SET(x,m,s) (((uint32_t)(((uint32_t)(x) & m) << s)))
+#define MAKE_REG_MASK(m, s) (((uint32_t)(((uint32_t)(m) << s))))
+#define MAKE_REG_GET(x, m, s) (((uint32_t)(((uint32_t)(x) >> s) & m)))
+#define MAKE_REG_SET(x, m, s) (((uint32_t)(((uint32_t)(x)&m) << s)))
-#define SDHC_BLKATTR_BLKSIZE_MASK MAKE_REG_MASK(0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
-#define SDHC_BLKATTR_BLKSIZE(n) MAKE_REG_SET(n,0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
-#define SDHC_BLKATTR_BLKCNT_MASK MAKE_REG_MASK(0x1FFF,16) //((uint32_t)0x1FFF<<16)
-#define SDHC_BLKATTR_BLKCNT(n) MAKE_REG_SET(n,0x1FFF,16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count For Current Transfer
+#define SDHC_BLKATTR_BLKSIZE_MASK \
+ MAKE_REG_MASK( \
+ 0x1FFF, 0) // uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
+#define SDHC_BLKATTR_BLKSIZE(n) \
+ MAKE_REG_SET(n, 0x1FFF, \
+ 0) // uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
+#define SDHC_BLKATTR_BLKCNT_MASK \
+ MAKE_REG_MASK(0x1FFF, 16) //((uint32_t)0x1FFF<<16)
+#define SDHC_BLKATTR_BLKCNT(n) \
+ MAKE_REG_SET(n, 0x1FFF, 16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count
+ // For Current Transfer
-#define SDHC_XFERTYP_CMDINX(n) MAKE_REG_SET(n,0x3F,24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
-#define SDHC_XFERTYP_CMDTYP(n) MAKE_REG_SET(n,0x3,22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
-#define SDHC_XFERTYP_DPSEL MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data Present Select
-#define SDHC_XFERTYP_CICEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Command Index Check Enable
-#define SDHC_XFERTYP_CCCEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command CRC Check Enable
-#define SDHC_XFERTYP_RSPTYP(n) MAKE_REG_SET(n,0x3,16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
-#define SDHC_XFERTYP_MSBSEL MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Multi/Single Block Select
-#define SDHC_XFERTYP_DTDSEL MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Data Transfer Direction Select
-#define SDHC_XFERTYP_AC12EN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 Enable
-#define SDHC_XFERTYP_BCEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Block Count Enable
-#define SDHC_XFERTYP_DMAEN MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000001) // DMA Enable
+#define SDHC_XFERTYP_CMDINX(n) \
+ MAKE_REG_SET(n, 0x3F, 24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
+#define SDHC_XFERTYP_CMDTYP(n) \
+ MAKE_REG_SET(n, 0x3, 22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
+#define SDHC_XFERTYP_DPSEL \
+ MAKE_REG_MASK(0x1, 21) //((uint32_t)0x00200000) // Data Present Select
+#define SDHC_XFERTYP_CICEN \
+ MAKE_REG_MASK(0x1, \
+ 20) //((uint32_t)0x00100000) // Command Index Check Enable
+#define SDHC_XFERTYP_CCCEN \
+ 19) //((uint32_t)0x00080000) // Command CRC Check Enable
+#define SDHC_XFERTYP_RSPTYP(n) \
+ MAKE_REG_SET(n, 0x3, \
+ 16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
+#define SDHC_XFERTYP_MSBSEL \
+ MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Multi/Single Block Select
+#define SDHC_XFERTYP_DTDSEL \
+ 0x1, 4) //((uint32_t)0x00000010) // Data Transfer Direction Select
+#define SDHC_XFERTYP_AC12EN \
+ MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Auto CMD12 Enable
+#define SDHC_XFERTYP_BCEN \
+ MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Block Count Enable
+#define SDHC_XFERTYP_DMAEN \
+ MAKE_REG_MASK(0x3, 0) //((uint32_t)0x00000001) // DMA Enable
-#define SDHC_PRSSTAT_DLSL_MASK MAKE_REG_MASK(0xFF,24) //((uint32_t)0xFF000000) // DAT Line Signal Level
-#define SDHC_PRSSTAT_CLSL MAKE_REG_MASK(0x1,23) //((uint32_t)0x00800000) // CMD Line Signal Level
-#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1,19) //
-#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1,18) //
-#define SDHC_PRSSTAT_CINS MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Card Inserted
-#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1,15)
-#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1,12)
-#define SDHC_PRSSTAT_BREN MAKE_REG_MASK(0x1,11) //((uint32_t)0x00000800) // Buffer Read Enable
-#define SDHC_PRSSTAT_BWEN MAKE_REG_MASK(0x1,10) //((uint32_t)0x00000400) // Buffer Write Enable
-#define SDHC_PRSSTAT_RTA MAKE_REG_MASK(0x1,9) //((uint32_t)0x00000200) // Read Transfer Active
-#define SDHC_PRSSTAT_WTA MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Write Transfer Active
-#define SDHC_PRSSTAT_SDOFF MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
-#define SDHC_PRSSTAT_PEROFF MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
-#define SDHC_PRSSTAT_HCKOFF MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
-#define SDHC_PRSSTAT_IPGOFF MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
-#define SDHC_PRSSTAT_SDSTB MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // SD Clock Stable
-#define SDHC_PRSSTAT_DLA MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Data Line Active
-#define SDHC_PRSSTAT_CDIHB MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
-#define SDHC_PRSSTAT_CIHB MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Inhibit (CMD)
+#define SDHC_PRSSTAT_DLSL_MASK \
+ MAKE_REG_MASK(0xFF, 24) //((uint32_t)0xFF000000) // DAT Line Signal Level
+#define SDHC_PRSSTAT_CLSL \
+ MAKE_REG_MASK(0x1, 23) //((uint32_t)0x00800000) // CMD Line Signal Level
+#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1, 19) //
+#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1, 18) //
+#define SDHC_PRSSTAT_CINS \
+ MAKE_REG_MASK(0x1, 16) //((uint32_t)0x00010000) // Card Inserted
+#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1, 15)
+#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1, 12)
+#define SDHC_PRSSTAT_BREN \
+ MAKE_REG_MASK(0x1, 11) //((uint32_t)0x00000800) // Buffer Read Enable
+#define SDHC_PRSSTAT_BWEN \
+ MAKE_REG_MASK(0x1, 10) //((uint32_t)0x00000400) // Buffer Write Enable
+#define SDHC_PRSSTAT_RTA \
+ MAKE_REG_MASK(0x1, 9) //((uint32_t)0x00000200) // Read Transfer Active
+#define SDHC_PRSSTAT_WTA \
+ MAKE_REG_MASK(0x1, 8) //((uint32_t)0x00000100) // Write Transfer Active
+#define SDHC_PRSSTAT_SDOFF \
+ 0x1, 7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
+#define SDHC_PRSSTAT_PEROFF \
+ 0x1, 6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
+#define SDHC_PRSSTAT_HCKOFF \
+ 0x1, 5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
+#define SDHC_PRSSTAT_IPGOFF \
+ 0x1, 4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
+#define SDHC_PRSSTAT_SDSTB \
+ MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // SD Clock Stable
+#define SDHC_PRSSTAT_DLA \
+ MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Data Line Active
+#define SDHC_PRSSTAT_CDIHB \
+ MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
+#define SDHC_PRSSTAT_CIHB \
+ MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Command Inhibit (CMD)
-#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1,30) //
-#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n,0x7,12) //
-#define SDHC_PROCTL_WECRM MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Wakeup Event Enable On SD Card Removal
-#define SDHC_PROCTL_WECINS MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Wakeup Event Enable On SD Card Insertion
-#define SDHC_PROCTL_WECINT MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Wakeup Event Enable On Card Interrupt
-#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1,20) //
-#define SDHC_PROCTL_IABG MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Interrupt At Block Gap
-#define SDHC_PROCTL_RWCTL MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Read Wait Control
-#define SDHC_PROCTL_CREQ MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Continue Request
-#define SDHC_PROCTL_SABGREQ MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Stop At Block Gap Request
-#define SDHC_PROCTL_DMAS(n) MAKE_REG_SET(n,0x3,8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
-#define SDHC_PROCTL_CDSS MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Detect Signal Selection
-#define SDHC_PROCTL_CDTL MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Detect Test Level
-#define SDHC_PROCTL_EMODE(n) MAKE_REG_SET(n,0x3,4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
-#define SDHC_PROCTL_EMODE_MASK MAKE_REG_MASK(0x3,4) //(uint32_t)((0x3)<<4) // Endian Mode
-#define SDHC_PROCTL_D3CD MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
-#define SDHC_PROCTL_DTW(n) MAKE_REG_SET(n,0x3,1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width, 0=1bit, 1=4bit, 2=8bit
-#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3,1) //((uint32_t)0x00000006)
-#define SDHC_PROCTL_LCTL MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // LED Control
+#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1, 30) //
+#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n, 0x7, 12) //
+#define SDHC_PROCTL_WECRM \
+ MAKE_REG_MASK(0x1, 26) //((uint32_t)0x04000000) // Wakeup Event Enable On
+ // SD Card Removal
+#define SDHC_PROCTL_WECINS \
+ MAKE_REG_MASK(0x1, 25) //((uint32_t)0x02000000) // Wakeup Event Enable On
+ // SD Card Insertion
+#define SDHC_PROCTL_WECINT \
+ MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Wakeup Event Enable On
+ // Card Interrupt
+#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1, 20) //
+#define SDHC_PROCTL_IABG \
+ MAKE_REG_MASK(0x1, 19) //((uint32_t)0x00080000) // Interrupt At Block Gap
+#define SDHC_PROCTL_RWCTL \
+ MAKE_REG_MASK(0x1, 18) //((uint32_t)0x00040000) // Read Wait Control
+#define SDHC_PROCTL_CREQ \
+ MAKE_REG_MASK(0x1, 17) //((uint32_t)0x00020000) // Continue Request
+#define SDHC_PROCTL_SABGREQ \
+ 16) //((uint32_t)0x00010000) // Stop At Block Gap Request
+#define SDHC_PROCTL_DMAS(n) \
+ MAKE_REG_SET(n, 0x3, 8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
+#define SDHC_PROCTL_CDSS \
+ 7) //((uint32_t)0x00000080) // Card Detect Signal Selection
+#define SDHC_PROCTL_CDTL \
+ MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Card Detect Test Level
+#define SDHC_PROCTL_EMODE(n) \
+ MAKE_REG_SET(n, 0x3, 4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
+#define SDHC_PROCTL_EMODE_MASK \
+ MAKE_REG_MASK(0x3, 4) //(uint32_t)((0x3)<<4) // Endian Mode
+#define SDHC_PROCTL_D3CD \
+ 3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
+#define SDHC_PROCTL_DTW(n) \
+ MAKE_REG_SET(n, 0x3, 1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width,
+ // 0=1bit, 1=4bit, 2=8bit
+#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3, 1) //((uint32_t)0x00000006)
+#define SDHC_PROCTL_LCTL \
+ MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // LED Control
-#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1,28) //
-#define SDHC_SYSCTL_INITA MAKE_REG_MASK(0x1,27) //((uint32_t)0x08000000) // Initialization Active
-#define SDHC_SYSCTL_RSTD MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Software Reset For DAT Line
-#define SDHC_SYSCTL_RSTC MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Software Reset For CMD Line
-#define SDHC_SYSCTL_RSTA MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Software Reset For ALL
-#define SDHC_SYSCTL_DTOCV(n) MAKE_REG_SET(n,0xF,16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
-#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF,16) //((uint32_t)0x000F0000)
-#define SDHC_SYSCTL_SDCLKFS(n) MAKE_REG_SET(n,0xFF,8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
-#define SDHC_SYSCTL_SDCLKFS_MASK MAKE_REG_MASK(0xFF,8) //((uint32_t)0x0000FF00)
-#define SDHC_SYSCTL_DVS(n) MAKE_REG_SET(n,0xF,4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
-#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF,4) //((uint32_t)0x000000F0)
+#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1, 28) //
+#define SDHC_SYSCTL_INITA \
+ MAKE_REG_MASK(0x1, 27) //((uint32_t)0x08000000) // Initialization Active
+#define SDHC_SYSCTL_RSTD \
+ 0x1, 26) //((uint32_t)0x04000000) // Software Reset For DAT Line
+#define SDHC_SYSCTL_RSTC \
+ 0x1, 25) //((uint32_t)0x02000000) // Software Reset For CMD Line
+#define SDHC_SYSCTL_RSTA \
+ MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Software Reset For ALL
+#define SDHC_SYSCTL_DTOCV(n) \
+ MAKE_REG_SET( \
+ n, 0xF, \
+ 16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
+#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF, 16) //((uint32_t)0x000F0000)
+#define SDHC_SYSCTL_SDCLKFS(n) \
+ MAKE_REG_SET(n, 0xFF, \
+ 8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
+#define SDHC_SYSCTL_SDCLKFS_MASK \
+ MAKE_REG_MASK(0xFF, 8) //((uint32_t)0x0000FF00)
+#define SDHC_SYSCTL_DVS(n) \
+ MAKE_REG_SET(n, 0xF, 4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
+#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF, 4) //((uint32_t)0x000000F0)
-#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
-#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
-#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
-#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable
+#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
+#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
+#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
+#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable
-#define SDHC_IRQSTAT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error
-#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1,26) //
-#define SDHC_IRQSTAT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error
-#define SDHC_IRQSTAT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error
-#define SDHC_IRQSTAT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error
-#define SDHC_IRQSTAT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error
-#define SDHC_IRQSTAT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error
-#define SDHC_IRQSTAT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error
-#define SDHC_IRQSTAT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error
-#define SDHC_IRQSTAT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error
-#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1,14) //
-#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1,12) //
-#define SDHC_IRQSTAT_CINT MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt
-#define SDHC_IRQSTAT_CRM MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal
-#define SDHC_IRQSTAT_CINS MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion
-#define SDHC_IRQSTAT_BRR MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready
-#define SDHC_IRQSTAT_BWR MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready
-#define SDHC_IRQSTAT_DINT MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt
-#define SDHC_IRQSTAT_BGE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event
-#define SDHC_IRQSTAT_TC MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete
-#define SDHC_IRQSTAT_CC MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete
+#define SDHC_IRQSTAT_DMAE \
+ MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // DMA Error
+#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1, 26) //
+#define SDHC_IRQSTAT_AC12E \
+ MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Auto CMD12 Error
+#define SDHC_IRQSTAT_DEBE \
+ MAKE_REG_MASK(0x1, 22) //((uint32_t)0x00400000) // Data End Bit Error
+#define SDHC_IRQSTAT_DCE \
+ MAKE_REG_MASK(0x1, 21) //((uint32_t)0x00200000) // Data CRC Error
+#define SDHC_IRQSTAT_DTOE \
+ MAKE_REG_MASK(0x1, 20) //((uint32_t)0x00100000) // Data Timeout Error
+#define SDHC_IRQSTAT_CIE \
+ MAKE_REG_MASK(0x1, 19) //((uint32_t)0x00080000) // Command Index Error
+#define SDHC_IRQSTAT_CEBE \
+ MAKE_REG_MASK(0x1, 18) //((uint32_t)0x00040000) // Command End Bit Error
+#define SDHC_IRQSTAT_CCE \
+ MAKE_REG_MASK(0x1, 17) //((uint32_t)0x00020000) // Command CRC Error
+#define SDHC_IRQSTAT_CTOE \
+ MAKE_REG_MASK(0x1, 16) //((uint32_t)0x00010000) // Command Timeout Error
+#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1, 14) //
+#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1, 12) //
+#define SDHC_IRQSTAT_CINT \
+ MAKE_REG_MASK(0x1, 8) //((uint32_t)0x00000100) // Card Interrupt
+#define SDHC_IRQSTAT_CRM \
+ MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Card Removal
+#define SDHC_IRQSTAT_CINS \
+ MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Card Insertion
+#define SDHC_IRQSTAT_BRR \
+ MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Buffer Read Ready
+#define SDHC_IRQSTAT_BWR \
+ MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Buffer Write Ready
+#define SDHC_IRQSTAT_DINT \
+ MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // DMA Interrupt
+#define SDHC_IRQSTAT_BGE \
+ MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Block Gap Event
+#define SDHC_IRQSTAT_TC \
+ MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Transfer Complete
+#define SDHC_IRQSTAT_CC \
+ MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Command Complete
-#define SDHC_IRQSTATEN_DMAESEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Status Enable
-#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1,26) //
-#define SDHC_IRQSTATEN_AC12ESEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
-#define SDHC_IRQSTATEN_DEBESEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
-#define SDHC_IRQSTATEN_DCESEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
-#define SDHC_IRQSTATEN_DTOESEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
-#define SDHC_IRQSTATEN_CIESEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Status Enable
-#define SDHC_IRQSTATEN_CEBESEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
-#define SDHC_IRQSTATEN_CCESEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
-#define SDHC_IRQSTATEN_CTOESEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
-#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1,14) //
-#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1,12) //
-#define SDHC_IRQSTATEN_CINTSEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
-#define SDHC_IRQSTATEN_CRMSEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Status Enable
-#define SDHC_IRQSTATEN_CINSEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Status Enable
-#define SDHC_IRQSTATEN_BRRSEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
-#define SDHC_IRQSTATEN_BWRSEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
-#define SDHC_IRQSTATEN_DINTSEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
-#define SDHC_IRQSTATEN_BGESEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
-#define SDHC_IRQSTATEN_TCSEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
-#define SDHC_IRQSTATEN_CCSEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Status Enable
+#define SDHC_IRQSTATEN_DMAESEN \
+ MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // DMA Error Status Enable
+#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1, 26) //
+#define SDHC_IRQSTATEN_AC12ESEN \
+ 0x1, 24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
+#define SDHC_IRQSTATEN_DEBESEN \
+ 0x1, \
+ 22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
+#define SDHC_IRQSTATEN_DCESEN \
+ 0x1, 21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
+#define SDHC_IRQSTATEN_DTOESEN \
+ 20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
+#define SDHC_IRQSTATEN_CIESEN \
+ 19) //((uint32_t)0x00080000) // Command Index Error Status Enable
+#define SDHC_IRQSTATEN_CEBESEN \
+ 18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
+#define SDHC_IRQSTATEN_CCESEN \
+ 0x1, 17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
+#define SDHC_IRQSTATEN_CTOESEN \
+ 16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
+#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1, 14) //
+#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1, 12) //
+#define SDHC_IRQSTATEN_CINTSEN \
+ 8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
+#define SDHC_IRQSTATEN_CRMSEN \
+ 7) //((uint32_t)0x00000080) // Card Removal Status Enable
+#define SDHC_IRQSTATEN_CINSEN \
+ 6) //((uint32_t)0x00000040) // Card Insertion Status Enable
+#define SDHC_IRQSTATEN_BRRSEN \
+ 0x1, 5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
+#define SDHC_IRQSTATEN_BWRSEN \
+ 0x1, 4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
+#define SDHC_IRQSTATEN_DINTSEN \
+ 3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
+#define SDHC_IRQSTATEN_BGESEN \
+ 0x1, 2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
+#define SDHC_IRQSTATEN_TCSEN \
+ 0x1, 1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
+#define SDHC_IRQSTATEN_CCSEN \
+ 0x1, 0) //((uint32_t)0x00000001) // Command Complete Status Enable
-#define SDHC_IRQSIGEN_DMAEIEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
-#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1,26) //
-#define SDHC_IRQSIGEN_AC12EIEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
-#define SDHC_IRQSIGEN_DEBEIEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
-#define SDHC_IRQSIGEN_DCEIEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
-#define SDHC_IRQSIGEN_DTOEIEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
-#define SDHC_IRQSIGEN_CIEIEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
-#define SDHC_IRQSIGEN_CEBEIEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Interrupt Enable
-#define SDHC_IRQSIGEN_CCEIEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
-#define SDHC_IRQSIGEN_CTOEIEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Interrupt Enable
-#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1,14) //
-#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1,12) //
-#define SDHC_IRQSIGEN_CINTIEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
-#define SDHC_IRQSIGEN_CRMIEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
-#define SDHC_IRQSIGEN_CINSIEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
-#define SDHC_IRQSIGEN_BRRIEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
-#define SDHC_IRQSIGEN_BWRIEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
-#define SDHC_IRQSIGEN_DINTIEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
-#define SDHC_IRQSIGEN_BGEIEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
-#define SDHC_IRQSIGEN_TCIEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
-#define SDHC_IRQSIGEN_CCIEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable
+#define SDHC_IRQSIGEN_DMAEIEN \
+ 28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
+#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1, 26) //
+#define SDHC_IRQSIGEN_AC12EIEN \
+ 24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
+#define SDHC_IRQSIGEN_DEBEIEN \
+ 22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
+#define SDHC_IRQSIGEN_DCEIEN \
+ 0x1, 21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
+#define SDHC_IRQSIGEN_DTOEIEN \
+ 20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
+#define SDHC_IRQSIGEN_CIEIEN \
+ 19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
+#define SDHC_IRQSIGEN_CEBEIEN \
+ // Interrupt Enable
+#define SDHC_IRQSIGEN_CCEIEN \
+ 17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
+#define SDHC_IRQSIGEN_CTOEIEN \
+#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1, 14) //
+#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1, 12) //
+#define SDHC_IRQSIGEN_CINTIEN \
+ 0x1, 8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
+#define SDHC_IRQSIGEN_CRMIEN \
+ 0x1, 7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
+#define SDHC_IRQSIGEN_CINSIEN \
+ 0x1, 6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
+#define SDHC_IRQSIGEN_BRRIEN \
+ 5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
+#define SDHC_IRQSIGEN_BWRIEN \
+ 4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
+#define SDHC_IRQSIGEN_DINTIEN \
+ 0x1, 3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
+#define SDHC_IRQSIGEN_BGEIEN \
+ 0x1, 2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
+#define SDHC_IRQSIGEN_TCIEN \
+ 1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
+#define SDHC_IRQSIGEN_CCIEN \
+ 0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable
-#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1,23) //
-#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1,22) //
-#define SDHC_AC12ERR_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Command Not Issued By Auto CMD12 Error
-#define SDHC_AC12ERR_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
-#define SDHC_AC12ERR_AC12CE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
-#define SDHC_AC12ERR_AC12EBE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
-#define SDHC_AC12ERR_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
-#define SDHC_AC12ERR_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed
+#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1, 23) //
+#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1, 22) //
+#define SDHC_AC12ERR_CNIBAC12E \
+ MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Command Not Issued By
+ // Auto CMD12 Error
+#define SDHC_AC12ERR_AC12IE \
+ MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
+#define SDHC_AC12ERR_AC12CE \
+ MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
+#define SDHC_AC12ERR_AC12EBE \
+ MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
+#define SDHC_AC12ERR_AC12TOE \
+ MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
+#define SDHC_AC12ERR_AC12NE \
+ MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed
-#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1,26) //
-#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1,25) //
-#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1,24) //
-#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1,23) //
-#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1,22) //
-#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1,21) //
-#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1,20) //
-#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x7,16) //
-#define SDHC_HTCAPBLT_RETUN_MODE MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x3,14) //
-#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1,13) //
-#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n,0xF,8) //
+#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1, 26) //
+#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1, 25) //
+#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1, 24) //
+#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1, 23) //
+#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1, 22) //
+#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1, 21) //
+#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1, 20) //
+#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP), 0x7, 16) //
+#define SDHC_HTCAPBLT_RETUN_MODE \
+ MAKE_REG_GET((USDHC1_HOST_CTRL_CAP), 0x3, 14) //
+#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1, 13) //
+#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n, 0xF, 8) //
-#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F,24) //
-#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F,8) //
-#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF,16) //
-#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF,0) //
-#define SDHC_WML_WR_BRSTLEN(n) MAKE_REG_SET(n,0x1F,24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
-#define SDHC_WML_RD_BRSTLEN(n) MAKE_REG_SET(n,0x1F,8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
-#define SDHC_WML_WR_WML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
-#define SDHC_WML_RD_WML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
-#define SDHC_WML_WRWML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
-#define SDHC_WML_RDWML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
+#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F, 24) //
+#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F, 8) //
+#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF, 16) //
+#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF, 0) //
+#define SDHC_WML_WR_BRSTLEN(n) \
+ MAKE_REG_SET(n, 0x1F, 24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
+#define SDHC_WML_RD_BRSTLEN(n) \
+ MAKE_REG_SET(n, 0x1F, 8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
+#define SDHC_WML_WR_WML(n) \
+ 16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
+#define SDHC_WML_RD_WML(n) \
+ 0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
+#define SDHC_WML_WRWML(n) \
+#define SDHC_WML_RDWML(n) \
// Teensy 4.0 only
-#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1,0) //
-#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1,1) //
-#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1,2) //
-#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1,3) //
-#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1,4) //
-#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1,5) //
-#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1,6) //
-#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1,7) //
+#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1, 0) //
+#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1, 1) //
+#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1, 2) //
+#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1, 3) //
+#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1, 4) //
+#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1, 5) //
+#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1, 6) //
+#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1, 7) //
-#define SDHC_FEVT_CINT MAKE_REG_MASK(0x1,31) //((uint32_t)0x80000000) // Force Event Card Interrupt
-#define SDHC_FEVT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // Force Event DMA Error
-#define SDHC_FEVT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
-#define SDHC_FEVT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
-#define SDHC_FEVT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Force Event Data CRC Error
-#define SDHC_FEVT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
-#define SDHC_FEVT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Force Event Command Index Error
-#define SDHC_FEVT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
-#define SDHC_FEVT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Force Event Command CRC Error
-#define SDHC_FEVT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
-#define SDHC_FEVT_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Force Event Command Not Executed By Auto Command 12 Error
-#define SDHC_FEVT_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Force Event Auto Command 12 Index Error
-#define SDHC_FEVT_AC12EBE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Force Event Auto Command 12 End Bit Error
-#define SDHC_FEVT_AC12CE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
-#define SDHC_FEVT_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Force Event Auto Command 12 Time Out Error
-#define SDHC_FEVT_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Force Event Auto Command 12 Not Executed
+#define SDHC_FEVT_CINT \
+ 31) //((uint32_t)0x80000000) // Force Event Card Interrupt
+#define SDHC_FEVT_DMAE \
+ MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // Force Event DMA Error
+#define SDHC_FEVT_AC12E \
+ 0x1, 24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
+#define SDHC_FEVT_DEBE \
+ 0x1, 22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
+#define SDHC_FEVT_DCE \
+ 21) //((uint32_t)0x00200000) // Force Event Data CRC Error
+#define SDHC_FEVT_DTOE \
+ 0x1, 20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
+#define SDHC_FEVT_CIE \
+ 0x1, 19) //((uint32_t)0x00080000) // Force Event Command Index Error
+#define SDHC_FEVT_CEBE \
+ 18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
+#define SDHC_FEVT_CCE \
+ 0x1, 17) //((uint32_t)0x00020000) // Force Event Command CRC Error
+#define SDHC_FEVT_CTOE \
+ 16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
+#define SDHC_FEVT_CNIBAC12E \
+ MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Force Event Command Not
+ // Executed By Auto Command 12 Error
+#define SDHC_FEVT_AC12IE \
+ MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Force Event Auto Command
+ // 12 Index Error
+#define SDHC_FEVT_AC12EBE \
+ MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // Force Event Auto Command
+ // 12 End Bit Error
+#define SDHC_FEVT_AC12CE \
+ 2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
+#define SDHC_FEVT_AC12TOE \
+ MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Force Event Auto Command
+ // 12 Time Out Error
+#define SDHC_FEVT_AC12NE \
+ MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Force Event Auto Command
+ // 12 Not Executed
-#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008)
-#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004)
-#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000003)
+#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008)
+#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004)
+#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3, 0) //((uint32_t)0x00000003)
-#define SDHC_MMCBOOT_BOOTBLKCNT(n) MAKE_REG_MASK(0xFF,16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap value of automatic mode
-#define SDHC_MMCBOOT_AUTOSABGEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // enable auto stop at block gap function
-#define SDHC_MMCBOOT_BOOTEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Boot Mode Enable
-#define SDHC_MMCBOOT_BOOTMODE MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Boot Mode Select
-#define SDHC_MMCBOOT_BOOTACK MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Boot Ack Mode Select
-#define SDHC_MMCBOOT_DTOCVACK(n) MAKE_REG_MASK(0xF,0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
-//#define SDHC_HOSTVER (*(volatile uint32_t*)0x400B10FC) // Host Controller Version
+#define SDHC_MMCBOOT_BOOTBLKCNT(n) \
+ MAKE_REG_MASK(0xFF, 16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap
+ // value of automatic mode
+#define SDHC_MMCBOOT_AUTOSABGEN \
+ MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // enable auto stop at
+ // block gap function
+#define SDHC_MMCBOOT_BOOTEN \
+ MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Boot Mode Enable
+#define SDHC_MMCBOOT_BOOTMODE \
+ MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Boot Mode Select
+#define SDHC_MMCBOOT_BOOTACK \
+ MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Boot Ack Mode Select
+#define SDHC_MMCBOOT_DTOCVACK(n) \
+ 0xF, \
+ 0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
+// #define SDHC_HOSTVER (*(volatile uint32_t*)0x400B10FC) // Host Controller
+// Version
#define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
-#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
-#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f<<8)
-#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) (((n)<<8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
-#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f<<16)
-#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) (((n)<<16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
+#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n)&CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
+#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f << 8)
+#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) \
+ (((n) << 8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
+#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f << 16)
+#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) \
+ (((n) << 16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD3_FRAC_MASK ((0x3f<<24)
-#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) (((n)<<24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)
+#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) \
+ (((n) << 24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)
-#define SDHC_DSADDR (USDHC1_DS_ADDR ) // DMA System Address register
-#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
-#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
-#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
-#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
-#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
-#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
-#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
-#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
-#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
-#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
-#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
-#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
-#define SDHC_IRQSTATEN (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
-#define SDHC_IRQSIGEN (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
-#define SDHC_AC12ERR (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
-#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
-#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
-#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
-#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
-#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
-#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
-#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
-#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
-#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
+#define SDHC_DSADDR (USDHC1_DS_ADDR) // DMA System Address register
+#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
+#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
+#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
+#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
+#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
+#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
+#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
+#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
+#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
+#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
+#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
+#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
+#define SDHC_IRQSTATEN \
+ (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
+#define SDHC_IRQSIGEN \
+ (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
+#define SDHC_AC12ERR \
+ (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
+#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
+#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
+#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
+#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
+#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
+#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
+#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
+#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
+#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
-#define IRQ_SDHC IRQ_SDHC1
+#define IRQ_SDHC IRQ_SDHC1
#define SDHC_MAX_DVS (0xF + 1U)
#define SDHC_MAX_CLKFS (0xFF + 1U)
#define SDHC_PREV_DVS(x) ((x) -= 1U)
#define SDHC_PREV_CLKFS(x, y) ((x) >>= (y))
-#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7<<11)
-#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7)<<11)
+#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7 << 11)
+#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7) << 11)
-#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1<)<0)
-#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1)<<12)
-#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1)<<13)
-#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1)<<16)
-#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3)<<6)
-#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3)<<14)
-#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3)<<14)
-#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3)
-#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3)
+#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1 <) < 0)
+#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1) << 12)
+#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1) << 13)
+#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1) << 16)
+#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3) << 6)
+#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3) << 14)
+#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3) << 14)
+#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7) << 3)
+#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7) << 3)
#endif // SdioTeensy_h
@@ -28,19 +28,19 @@
* \brief main SdFs include file.
-#include "SdCard/SdCard.h"
#include "FatLib/FatLib.h"
#include "FsLib/FsLib.h"
+#include "SdCard/SdCard.h"
#if INCLUDE_SDIOS
#endif // INCLUDE_SDIOS
/** SdFat version for cpp use. */
-#define SD_FAT_VERSION 20200
+#define SD_FAT_VERSION 20202
/** SdFat version as string. */
-#define SD_FAT_VERSION_STR "2.2.0"
+#define SD_FAT_VERSION_STR "2.2.2"
* \class SdBase
@@ -93,7 +93,7 @@ class SdBase : public Vol {
/** \return Pointer to SD card object. */
- SdCard* card() {return m_card;}
+ SdCard* card() { return m_card; }
/** Initialize SD card in SPI mode.
@@ -136,7 +136,8 @@ class SdBase : public Vol {
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
/** %Print error info and halt.
@@ -197,7 +198,7 @@ class SdBase : public Vol {
/** \return true if can be in dedicated SPI state */
- bool hasDedicatedSpi() {return m_card ? m_card->hasDedicatedSpi() : false;}
+ bool hasDedicatedSpi() { return m_card ? m_card->hasDedicatedSpi() : false; }
@@ -205,7 +206,8 @@ class SdBase : public Vol {
void initErrorHalt(print_t* pr) {
initErrorPrint(pr);
@@ -244,7 +246,7 @@ class SdBase : public Vol {
- bool isDedicatedSpi() {return m_card ? m_card->isDedicatedSpi() : false;}
+ bool isDedicatedSpi() { return m_card ? m_card->isDedicatedSpi() : false; }
/** %Print volume FAT/exFAT type.
@@ -325,7 +327,7 @@ class SdBase : public Vol {
/** \return SD card error data. */
- uint8_t sdErrorData() {return m_card ? m_card->errorData() : 0;}
+ uint8_t sdErrorData() { return m_card ? m_card->errorData() : 0; }
@@ -339,57 +341,51 @@ class SdBase : public Vol {
/** \return pointer to base volume */
- Vol* vol() {return reinterpret_cast<Vol*>(this);}
+ Vol* vol() { return reinterpret_cast<Vol*>(this); }
/** Initialize file system after call to cardBegin.
- bool volumeBegin() {
- return Vol::begin(m_card);
+ bool volumeBegin() { return Vol::begin(m_card); }
/** Print error details after begin() fails. */
- void initErrorPrint() {
- initErrorPrint(&Serial);
+ void initErrorPrint() { initErrorPrint(&Serial); }
/** %Print msg to Serial and halt.
* \param[in] msg Message to print.
- void errorHalt(const __FlashStringHelper* msg) {
- errorHalt(&Serial, msg);
+ void errorHalt(const __FlashStringHelper* msg) { errorHalt(&Serial, msg); }
/** %Print error info to Serial and halt. */
- void errorHalt() {errorHalt(&Serial);}
+ void errorHalt() { errorHalt(&Serial); }
- void errorHalt(const char* msg) {errorHalt(&Serial, msg);}
+ void errorHalt(const char* msg) { errorHalt(&Serial, msg); }
/** %Print error info and halt. */
- void initErrorHalt() {initErrorHalt(&Serial);}
+ void initErrorHalt() { initErrorHalt(&Serial); }
/** %Print msg, any SD error code.
- void errorPrint(const char* msg) {errorPrint(&Serial, msg);}
- /** %Print msg, any SD error code.
+ void errorPrint(const char* msg) { errorPrint(&Serial, msg); }
+ /** %Print msg, any SD error code.
- void errorPrint(const __FlashStringHelper* msg) {errorPrint(&Serial, msg);}
+ void errorPrint(const __FlashStringHelper* msg) { errorPrint(&Serial, msg); }
- void initErrorHalt(const char* msg) {initErrorHalt(&Serial, msg);}
+ void initErrorHalt(const char* msg) { initErrorHalt(&Serial, msg); }
@@ -473,9 +469,7 @@ class SdFile : public PrintFile<SdBaseFile> {
* \param[in] path path for file.
- SdFile(const char* path, oflag_t oflag) {
+ SdFile(const char* path, oflag_t oflag) { open(path, oflag); }
/** Set the date/time callback function
* \param[in] dateTime The user's call back function. The callback
@@ -502,13 +496,11 @@ class SdFile : public PrintFile<SdBaseFile> {
* sync() maintains the last access date and last modify date/time.
- static void dateTimeCallback(
- void (*dateTime)(uint16_t* date, uint16_t* time)) {
+ static void dateTimeCallback(void (*dateTime)(uint16_t* date,
+ uint16_t* time)) {
FsDateTime::setCallback(dateTime);
/** Cancel the date/time callback function. */
- static void dateTimeCallbackCancel() {
- FsDateTime::clearCallback();
+ static void dateTimeCallbackCancel() { FsDateTime::clearCallback(); }
#endif // SdFat_h
@@ -122,14 +122,28 @@
#define SPI_DRIVER_SELECT 0
- * If USE_SPI_ARRAY_TRANSFER is non-zero and the standard SPI library is
- * use, the array transfer function, transfer(buf, size), will be used.
- * This option will allocate up to a 512 byte temporary buffer for send.
+ * If USE_SPI_ARRAY_TRANSFER is one and the standard SPI library is
+ * use, the array transfer function, transfer(buf, count), will be used.
+ * This option will allocate a 512 byte temporary buffer for send.
* This may be faster for some boards. Do not use this with AVR boards.
+ * Warning: the next options are often fastest but only available for some
+ * non-Arduino board packages.
+ * If USE_SPI_ARRAY_TRANSFER is two use transfer(nullptr, buf, count) for
+ * receive and transfer(buf, nullptr, count) for send.
+ * If USE_SPI_ARRAY_TRANSFER is three use transfer(nullptr, buf, count) for
+ * receive and transfer(buf, rxTmp, count) for send. Try this with Adafruit
+ * SAMD51.
+ * If USE_SPI_ARRAY_TRANSFER is four use transfer(txTmp, buf, count) for
+ * receive and transfer(buf, rxTmp, count) for send. Try this with STM32.
#ifndef USE_SPI_ARRAY_TRANSFER
#define USE_SPI_ARRAY_TRANSFER 0
#endif // USE_SPI_ARRAY_TRANSFER
* SD maximum initialization clock rate.
@@ -161,7 +175,8 @@
#ifndef USE_BLOCK_DEVICE_INTERFACE
#define USE_BLOCK_DEVICE_INTERFACE 0
#endif // USE_BLOCK_DEVICE_INTERFACE
* SD_CHIP_SELECT_MODE defines how the functions
* void sdCsInit(SdCsPin_t pin) {pinMode(pin, OUTPUT);}
* and
@@ -346,8 +361,8 @@ typedef uint8_t SdCsPin_t;
* Set USE_SIMPLE_LITTLE_ENDIAN nonzero for little endian processors
* with no memory alignment restrictions.
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\
- && (defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED))
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && \
+ (defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED))
#define USE_SIMPLE_LITTLE_ENDIAN 1
#else // __BYTE_ORDER_
#define USE_SIMPLE_LITTLE_ENDIAN 0
@@ -394,11 +409,11 @@ typedef uint8_t SdCsPin_t;
#endif // BUILTIN_SDCARD
// SPI for built-in card.
#ifndef SDCARD_SPI
-#define SDCARD_SPI SPI1
+#define SDCARD_SPI SPI1
#define SDCARD_MISO_PIN 59
#define SDCARD_MOSI_PIN 61
-#define SDCARD_SCK_PIN 60
-#define SDCARD_SS_PIN 62
+#define SDCARD_SCK_PIN 60
+#define SDCARD_SS_PIN 62
#endif // SDCARD_SPI
#define HAS_SDIO_CLASS 1
@@ -409,15 +424,13 @@ typedef uint8_t SdCsPin_t;
* Determine the default SPI configuration.
-#if defined(ARDUINO_ARCH_APOLLO3)\
- || (defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF))\
- || (defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm))\
- || defined(ESP8266) || defined(ESP32)\
- || defined(PLATFORM_ID)\
- || defined(ARDUINO_SAM_DUE)\
- || defined(STM32_CORE_VERSION)\
- || defined(__STM32F1__) || defined(__STM32F4__)\
- || (defined(CORE_TEENSY) && defined(__arm__))
+#if defined(ARDUINO_ARCH_APOLLO3) || \
+ (defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF)) || \
+ (defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm)) || \
+ defined(ESP8266) || defined(ESP32) || defined(PLATFORM_ID) || \
+ defined(ARDUINO_SAM_DUE) || defined(STM32_CORE_VERSION) || \
+ defined(__STM32F1__) || defined(__STM32F4__) || \
+ (defined(CORE_TEENSY) && defined(__arm__))
#define SD_HAS_CUSTOM_SPI 1
#else // SD_HAS_CUSTOM_SPI
// Use standard SPI library.
@@ -38,6 +38,8 @@
class SdSpiArduinoDriver {
+ SdSpiArduinoDriver() = default;
/** Activate SPI hardware. */
void activate();
/** Initialize the SPI bus.
@@ -55,12 +57,12 @@ class SdSpiArduinoDriver {
uint8_t receive();
/** Receive multiple bytes.
- * \param[out] buf Buffer to receive the data.
- * \param[in] count Number of bytes to receive.
- * \return Zero for no error or nonzero error code.
+ * \param[out] buf Buffer to receive the data.
+ * \param[in] count Number of bytes to receive.
+ * \return Zero for no error or nonzero error code.
uint8_t receive(uint8_t* buf, size_t count);
/** Send a byte.
@@ -82,7 +84,7 @@ class SdSpiArduinoDriver {
- SPIClass *m_spi;
+ SPIClass* m_spi = nullptr;
SPISettings m_spiSettings;
/** Typedef for use of SdSpiArduinoDriver */
@@ -25,9 +25,7 @@
#include "SdSpiDriver.h"
#if defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_ARCH_APOLLO3)
-void SdSpiArduinoDriver::activate() {
- m_spi->beginTransaction(m_spiSettings);
+void SdSpiArduinoDriver::activate() { m_spi->beginTransaction(m_spiSettings); }
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
if (spiConfig.spiPort) {
@@ -38,17 +36,11 @@ void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
m_spi->begin();
-void SdSpiArduinoDriver::deactivate() {
- m_spi->endTransaction();
+void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); }
-void SdSpiArduinoDriver::end() {
- m_spi->end();
+void SdSpiArduinoDriver::end() { m_spi->end(); }
-uint8_t SdSpiArduinoDriver::receive() {
- return m_spi->transfer(0XFF);
+uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); }
uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
memset(buf, 0XFF, count);
@@ -56,24 +48,22 @@ uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
-void SdSpiArduinoDriver::send(uint8_t data) {
- m_spi->transfer(data);
+void SdSpiArduinoDriver::send(uint8_t data) { m_spi->transfer(data); }
void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
// If not a multiple of four. Command with CRC used six byte send.
- while (count%4) {
+ while (count % 4) {
send(*buf++);
count--;
// Convert byte array to 4 byte array.
- uint32_t myArray[count/4]; // NOLINT
- for (int x = 0; x < count/4; x++) {
+ uint32_t myArray[count / 4]; // NOLINT
+ for (int x = 0; x < count / 4; x++) {
myArray[x] = ((uint32_t)buf[(x * 4) + 3] << (8 * 3)) |
((uint32_t)buf[(x * 4) + 2] << (8 * 2)) |
((uint32_t)buf[(x * 4) + 1] << (8 * 1)) |
((uint32_t)buf[(x * 4) + 0] << (8 * 0));
- m_spi->transfer(reinterpret_cast<void *>(myArray), count);
+ m_spi->transfer(reinterpret_cast<void*>(myArray), count);
#endif // defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_ARCH_APOLLO3)
@@ -25,7 +25,7 @@
#ifndef SdSpiAvr_h
#define SdSpiAvr_h
// Use of in-line for AVR to save flash.
-#define nop asm volatile ("nop\n\t")
+#define nop asm volatile("nop\n\t")
inline void SdSpiArduinoDriver::activate() {
SPI.beginTransaction(m_spiSettings);
@@ -36,17 +36,11 @@ inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
-inline void SdSpiArduinoDriver::deactivate() {
+inline void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); }
-inline void SdSpiArduinoDriver::end() {
- SPI.end();
+inline void SdSpiArduinoDriver::end() { SPI.end(); }
-inline uint8_t SdSpiArduinoDriver::receive() {
+inline uint8_t SdSpiArduinoDriver::receive() { return SPI.transfer(0XFF); }
inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
if (count == 0) {
@@ -58,12 +52,14 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
// nops optimize loop for 16MHz CPU 8 MHz SPI
nop;
- while (!(SPSR & _BV(SPIF))) {}
+ while (!(SPSR & _BV(SPIF))) {
uint8_t in = SPDR;
SPDR = 0XFF;
*buf++ = in;
*buf = SPDR;
#elif defined(SPI_RXCIF_bm)
SPI0.DATA = 0XFF;
@@ -73,12 +69,14 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
- while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {}
+ while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {
uint8_t in = SPI0.DATA;
*buf = SPI0.DATA;
#else // SPSR
#error Unsupported AVR CPU - edit SdFatConfig.h to use standard SPI library.
@@ -86,11 +84,9 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
-inline void SdSpiArduinoDriver::send(uint8_t data) {
+inline void SdSpiArduinoDriver::send(uint8_t data) { SPI.transfer(data); }
-inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
+inline void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
@@ -101,10 +97,12 @@ inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
- while (!(SPSR & (1 << SPIF))) {}
+ while (!(SPSR & (1 << SPIF))) {
SPDR = b;
SPI0.DATA = *buf++;
while (--count) {
@@ -113,10 +111,12 @@ inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
SPI0.DATA = b;
#endif // SPSR
@@ -30,8 +30,9 @@
#include <avr/interrupt.h>
#ifndef HIGH
#define HIGH 1
#endif // HIGH
@@ -79,10 +80,10 @@ inline void unoPinMode(uint8_t pin, uint8_t mode) {
sei();
-#define UNO_SS 10
+#define UNO_SS 10
#define UNO_MOSI 11
#define UNO_MISO 12
-#define UNO_SCK 13
+#define UNO_SCK 13
* \class SdSpiDriverBareUno
@@ -116,16 +117,14 @@ class SdSpiDriverBareUno {
* \return The byte.
- return transfer(0XFF);
+ uint8_t receive() { return transfer(0XFF); }
@@ -133,7 +132,8 @@ class SdSpiDriverBareUno {
uint8_t* pr = buf;
while (--count > 0) {
*pr++ = in;
@@ -141,7 +141,8 @@ class SdSpiDriverBareUno {
*pr = SPDR;
@@ -149,9 +150,7 @@ class SdSpiDriverBareUno {
* \param[in] data Byte to send
- transfer(data);
+ void send(uint8_t data) { transfer(data); }
/** Send multiple bytes.
* \param[in] buf Buffer for data to be sent.
@@ -164,18 +163,18 @@ class SdSpiDriverBareUno {
SPDR = *buf++;
uint8_t b = *buf++;
// nops to optimize loop for 16MHz CPU 8 MHz SPI
/** Set CS low. */
- void select() {
- unoDigitalWrite(m_csPin, LOW);
+ void select() { unoDigitalWrite(m_csPin, LOW); }
/** Save high speed SPISettings after SD initialization.
* \param[in] spiConfig SPI options.
@@ -186,13 +185,12 @@ class SdSpiDriverBareUno {
static uint8_t transfer(uint8_t data) {
SPDR = data;
- while (!(SPSR & _BV(SPIF))) {} // wait
+ } // wait
return SPDR;
/** Set CS high. */
- void unselect() {
- unoDigitalWrite(m_csPin, HIGH);
+ void unselect() { unoDigitalWrite(m_csPin, HIGH); }
@@ -51,12 +51,12 @@ class SdSpiBaseClass {
virtual uint8_t receive() = 0;
virtual uint8_t receive(uint8_t* buf, size_t count) = 0;
@@ -73,6 +73,6 @@ class SdSpiBaseClass {
* \param[in] maxSck Maximum SCK frequency.
- virtual void setSckSpeed(uint32_t maxSck) {(void)maxSck;}
+ virtual void setSckSpeed(uint32_t maxSck) { (void)maxSck; }
#endif // SdSpiBaseClass_h
@@ -26,22 +26,14 @@
#if ENABLE_ARDUINO_FEATURES
#if SD_CHIP_SELECT_MODE == 0
-void sdCsInit(SdCsPin_t pin) {
- pinMode(pin, OUTPUT);
+void sdCsInit(SdCsPin_t pin) { pinMode(pin, OUTPUT); }
-void sdCsWrite(SdCsPin_t pin, bool level) {
- digitalWrite(pin, level);
+void sdCsWrite(SdCsPin_t pin, bool level) { digitalWrite(pin, level); }
#elif SD_CHIP_SELECT_MODE == 1
-__attribute__((weak))
+__attribute__((weak)) void sdCsInit(SdCsPin_t pin) { pinMode(pin, OUTPUT); }
+__attribute__((weak)) void sdCsWrite(SdCsPin_t pin, bool level) {
digitalWrite(pin, level);
#endif // SD_CHIP_SELECT_MODE == 0
@@ -52,19 +52,24 @@ const uint8_t DEDICATED_SPI = 1;
* \param[in] opt option field of SdSpiConfig.
* \return true for dedicated SPI.
-inline bool spiOptionDedicated(uint8_t opt) {return opt & DEDICATED_SPI;}
+inline bool spiOptionDedicated(uint8_t opt) { return opt & DEDICATED_SPI; }
-inline bool spiOptionDedicated(uint8_t opt) {(void)opt; return false;}
+inline bool spiOptionDedicated(uint8_t opt) {
+ (void)opt;
+/** The user will call begin. Useful for custom SPI configurations. */
+const uint8_t USER_SPI_BEGIN = 2;
/** SPISettings for SCK frequency in Hz. */
#define SD_SCK_HZ(maxSpeed) (maxSpeed)
/** SPISettings for SCK frequency in MHz. */
-#define SD_SCK_MHZ(maxMhz) (1000000UL*(maxMhz))
+#define SD_SCK_MHZ(maxMhz) (1000000UL * (maxMhz))
// SPI divisor constants - obsolete.
/** Set SCK to max rate. */
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
@@ -93,8 +98,8 @@ typedef SdSpiSoftDriver SpiPort_t;
class SdSpiBaseClass;
/** Port type for extrernal SPI driver. */
typedef SdSpiBaseClass SpiPort_t;
-#else // SPI_DRIVER_SELECT
-typedef void* SpiPort_t;
+#else // SPI_DRIVER_SELECT
+typedef void* SpiPort_t;
@@ -103,15 +108,15 @@ typedef void* SpiPort_t;
class SdSpiConfig {
- /** SdSpiConfig constructor.
+ /** SdSpiConfig constructor.
* \param[in] cs Chip select pin.
* \param[in] opt Options.
* \param[in] maxSpeed Maximum SCK frequency.
* \param[in] port The SPI port to use.
- SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed, SpiPort_t* port) :
- csPin(cs), options(opt), maxSck(maxSpeed), spiPort(port) {}
+ SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed, SpiPort_t* port)
+ : csPin(cs), options(opt), maxSck(maxSpeed), spiPort(port) {}
/** SdSpiConfig constructor.
@@ -119,8 +124,8 @@ class SdSpiConfig {
- SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed) :
- csPin(cs), options(opt), maxSck(maxSpeed) {}
+ SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed)
+ : csPin(cs), options(opt), maxSck(maxSpeed) {}
@@ -42,13 +42,9 @@
#define SPI_RX_IDX 2
/* Disable DMA Controller. */
-static void dmac_disable() {
- DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
+static void dmac_disable() { DMAC->DMAC_EN &= (~DMAC_EN_ENABLE); }
/* Enable DMA Controller. */
-static void dmac_enable() {
- DMAC->DMAC_EN = DMAC_EN_ENABLE;
+static void dmac_enable() { DMAC->DMAC_EN = DMAC_EN_ENABLE; }
/* Disable DMA Channel. */
static void dmac_channel_disable(uint32_t ul_num) {
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
@@ -67,14 +63,15 @@ static void spiDmaRX(uint8_t* dst, uint16_t count) {
dmac_channel_disable(SPI_DMAC_RX_CH);
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
- DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
- DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
- DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
- DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
- DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
+ DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
+ DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA =
+ count | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
+ DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB =
+ DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
- DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
- DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
+ DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG =
+ DMAC_CFG_SRC_PER(SPI_RX_IDX) | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD |
+ DMAC_CFG_FIFOCFG_ASAP_CFG;
dmac_channel_enable(SPI_DMAC_RX_CH);
@@ -89,16 +86,17 @@ static void spiDmaTX(const uint8_t* src, uint16_t count) {
dmac_channel_disable(SPI_DMAC_TX_CH);
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
- DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
- DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
+ DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
+ DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA =
- DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
- DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
+ DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB =
+ DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
- DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
- DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
+ DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG =
+ DMAC_CFG_DST_PER(SPI_TX_IDX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD |
+ DMAC_CFG_FIFOCFG_ALAP_CFG;
dmac_channel_enable(SPI_DMAC_TX_CH);
@@ -141,39 +139,36 @@ void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
#endif // USE_SAM3X_DMAC
+void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); }
+void SdSpiArduinoDriver::end() { SPI.end(); }
static inline uint8_t spiTransfer(uint8_t b) {
Spi* pSpi = SPI0;
pSpi->SPI_TDR = b;
- while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
+ while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {
b = pSpi->SPI_RDR;
return b;
- return spiTransfer(0XFF);
+uint8_t SdSpiArduinoDriver::receive() { return spiTransfer(0XFF); }
int rtn = 0;
#if USE_SAM3X_DMAC
// clear overrun error
- while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {pSpi->SPI_RDR;}
+ while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {
+ pSpi->SPI_RDR;
spiDmaRX(buf, count);
spiDmaTX(0, count);
while (!dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
- if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
+ if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
rtn = 2;
@@ -183,34 +178,39 @@ uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
if (pSpi->SPI_SR & SPI_SR_OVRES) {
rtn |= 1;
-#else // USE_SAM3X_DMAC
+#else // USE_SAM3X_DMAC
for (size_t i = 0; i < count; i++) {
pSpi->SPI_TDR = 0XFF;
buf[i] = pSpi->SPI_RDR;
- spiTransfer(data);
+void SdSpiArduinoDriver::send(uint8_t data) { spiTransfer(data); }
-void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
+void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
spiDmaTX(buf, count);
- while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
-#else // #if USE_SAM3X_DMAC
- while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
+ while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {
+#else // #if USE_SAM3X_DMAC
+ while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {
pSpi->SPI_TDR = buf[i];
- while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
+ while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {
#endif // #if USE_SAM3X_DMAC
// leave RDR empty
#endif // defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_SAM_DUE)