Add SDIO support for RP2040/RP2350

This commit is contained in:
Bill Greiman 2025-01-01 07:54:38 -08:00
parent 052d38e2c6
commit 67e26476f1
99 changed files with 4283 additions and 1531 deletions

View file

@ -1,3 +1,65 @@
### Warning: This version has major internal changes.
SdFat version 2.3.0 has major changes to implement RP2040/RP2350 SDIO.
In addition there are number of bug fixes.
Begin by running the Rp2040SdioSetup example to try RP2040/RP2350 SDIO.
This example requires a SDIO Card socket with the following six lines.
CLK - A clock signal sent to the card by the MCU.
CMD - A bidirectional line for for commands and responses.
DAT[0:3] - Four bidirectional lines for data transfer.
CLK and CMD can be connected to any GPIO pins. DAT[0:3] can be connected
to any four consecutive GPIO pins in the order DAT0, DAT1, DAT2, DAT3.
Here is an example of SDIO for Pico using an Adafruit socket, PiCowbell
Proto and PiCowbell Proto Doubler.
![Alt text](images/SdioSpi.jpg)
This Socket supports SDIO with:
```
#define RP_CLK_GPIO 10
#define RP_CMD_GPIO 11
#define RP_DAT0_GPIO 12 // DAT1: GPIO13 DAT2: GPIO14, DAT3: GPIO15.
```
It also can be used on SPI1 with:
```
const uint8_t SD_CS_PIN = 15;
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK, &SPI1)
// In setup
SPI1.setSCK(10);
SPI1.setTX(11);
SPI1.setRX(12);
```
This setup gets the following result in the bench example using SDIO.
<pre>
FILE_SIZE_MB = 5
BUF_SIZE = 512 bytes
Starting write test, please wait.
write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
15014.05,1165,32,32
15289.54,1249,32,32
Starting read test, please wait.
read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
15624.00,58,32,32
15624.00,51,32,32
</pre>
File copy constructors and file assignment operators have been made private by
default in 2.2.3 to prevent call by value and multiple copies of file instances.

View file

@ -1,4 +1,4 @@
# Doxyfile 1.9.6
# Doxyfile 1.10.0
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -63,6 +63,12 @@ PROJECT_BRIEF =
PROJECT_LOGO =
# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
# when the HTML document is shown. Doxygen will copy the logo to the output
# directory.
PROJECT_ICON =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
@ -363,6 +369,17 @@ MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
# generate identifiers for the Markdown headings. Note: Every identifier is
# unique.
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
# sequence number starting at 0 and GITHUB use the lower case version of title
# with any whitespace replaced by '-' and punctuation characters removed.
# The default value is: DOXYGEN.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
MARKDOWN_ID_STYLE = DOXYGEN
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
@ -487,6 +504,14 @@ LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
# If the TIMESTAMP tag is set different from NO then each generated page will
# contain the date or date and time when the page was generated. Setting this to
# NO can help when comparing the output of multiple runs.
# Possible values are: YES, NO, DATETIME and DATE.
# The default value is: NO.
TIMESTAMP = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -872,7 +897,14 @@ WARN_IF_UNDOC_ENUM_VAL = NO
# 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
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
# write the warning messages in between other messages but write them at the end
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
# besides being in the defined file also be shown at the end of a run, unless
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
# The default value is: NO.
WARN_AS_ERROR = NO
@ -926,7 +958,9 @@ INPUT = ../src \
../src/SpiDriver \
mainpage.h \
../src/FsLib \
../src/FsLib
../src/FsLib \
../src/SdCard/TeensySdio \
../src/SdCard/Rp2040Sdio
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -959,12 +993,12 @@ INPUT_FILE_ENCODING =
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice.
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
@ -1016,7 +1050,9 @@ EXCLUDE = ../src/common/FsStructs.h \
../src/common/PrintBasic.h \
../src/common/PrintBasic.cpp \
../src/SpiDriver/SdSpiBareUnoDriver.h \
../src/iostream/StreamBaseClass.cpp
../src/iostream/StreamBaseClass.cpp \
../src/SdCard/Rp2040Sdio/DbgLog.h \
../src/common/FsStructs.h
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@ -1039,9 +1075,6 @@ EXCLUDE_PATTERNS =
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# 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/*
EXCLUDE_SYMBOLS =
@ -1155,7 +1188,8 @@ FORTRAN_COMMENT_AFTER = 72
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# multi-line macros, enums or list initialized variables directly into the
# documentation.
# The default value is: NO.
INLINE_SOURCES = NO
@ -1424,15 +1458,6 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
@ -1452,6 +1477,33 @@ HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
# dynamically folded and expanded in the generated HTML source code.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_CODE_FOLDING = YES
# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in
# the top right corner of code and text fragments that allows the user to copy
# its content to the clipboard. Note this only works if supported by the browser
# and the web page is served via a secure context (see:
# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
# protocol.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COPY_CLIPBOARD = YES
# Doxygen stores a couple of settings persistently in the browser (via e.g.
# cookies). By default these settings apply to all HTML pages generated by
# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
# the settings under a project specific key, such that the user preferences will
# be stored separately.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_PROJECT_COOKIE =
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
@ -1582,6 +1634,16 @@ BINARY_TOC = NO
TOC_EXPAND = NO
# The SITEMAP_URL tag is used to specify the full URL of the place where the
# generated documentation will be placed on the server by the user during the
# deployment of the documentation. The generated sitemap is called sitemap.xml
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
# is specified no sitemap is generated. For information about the sitemap
# protocol see https://www.sitemaps.org
# This tag requires that the tag GENERATE_HTML is set to YES.
SITEMAP_URL =
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@ -2070,9 +2132,16 @@ PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help.
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
# hit at every error; missing files that TeX tries to input or request from
# keyboard input (\read on a not open input stream) cause the job to abort,
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
# but there is no possibility of user interaction just like in batch mode,
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
# each error, asking for user intervention.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -2093,14 +2162,6 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
@ -2266,7 +2327,7 @@ DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
@ -2277,6 +2338,28 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
# database with symbols found by doxygen stored in tables.
# The default value is: NO.
GENERATE_SQLITE3 = NO
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
# in front of it.
# The default directory is: sqlite3.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_OUTPUT = sqlite3
# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
# database file will be recreated with each doxygen run. If set to NO, doxygen
# will warn if a database file is already found and not modify it.
# The default value is: YES.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_RECREATE_DB = YES
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
@ -2423,15 +2506,15 @@ TAGFILES =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
# will be listed in the class and namespace index. If set to NO, only the
# inherited external classes will be listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# in the topic index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
@ -2445,16 +2528,9 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
# 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.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@ -2463,7 +2539,7 @@ HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
@ -2516,13 +2592,19 @@ DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
DOT_FONTPATH =
# 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.
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
# generate a graph for each documented class showing the direct and indirect
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
# CLASS_GRAPH tag is set to BUILTIN, then 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. Explicit enabling an inheritance
# graph or choosing a different representation for an inheritance graph of a
# specific class, can be accomplished by means of the command \inheritancegraph.
# Disabling an inheritance graph can be accomplished by means of the command
# \hideinheritancegraph.
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
# The default value is: YES.
CLASS_GRAPH = YES
@ -2530,15 +2612,21 @@ CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
# graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the
# class with other documented classes.
# class with other documented classes. Explicit enabling a collaboration graph,
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
# command \collaborationgraph. Disabling a collaboration graph can be
# accomplished by means of the command \hidecollaborationgraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to 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. See also the chapter Grouping
# in the manual.
# groups, showing the direct groups dependencies. Explicit enabling a group
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
# of the command \groupgraph. Disabling a directory graph can be accomplished by
# means of the command \hidegroupgraph. See also the chapter Grouping in the
# manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2580,8 +2668,8 @@ DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# significantly it will be wrapped across multiple lines. Some heuristics are
# applied to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2598,7 +2686,9 @@ TEMPLATE_RELATIONS = NO
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
# can be accomplished by means of the command \includegraph. Disabling an
# include graph can be accomplished by means of the command \hideincludegraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2607,7 +2697,10 @@ INCLUDE_GRAPH = YES
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
# set to YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
# an included by graph can be accomplished by means of the command
# \hideincludedbygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2647,7 +2740,10 @@ GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between the
# files in the directories.
# files in the directories. Explicit enabling a directory graph, when
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
# \directorygraph. Disabling a directory graph can be accomplished by means of
# the command \hidedirectorygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2663,7 +2759,7 @@ 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:
# http://www.graphviz.org/)).
# https://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
@ -2700,11 +2796,12 @@ DOT_PATH =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
# 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.
# If left empty dia is assumed to be found in the default search path.
MSCFILE_DIRS =
DIA_PATH =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
@ -2781,3 +2878,19 @@ GENERATE_LEGEND = YES
# The default value is: YES.
DOT_CLEANUP = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
# use a built-in version of mscgen tool to produce the charts. Alternatively,
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
# specifying prog as the value, doxygen will call the tool as prog -T
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
# output file formats "png", "eps", "svg", and "ismap".
MSCGEN_TOOL =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =

View file

@ -1,4 +1,4 @@
2022-07-01
2025-01-01
Run the SdErrorCode example to produce an updated list.
@ -12,7 +12,7 @@ Code,Symbol - failed operation
0X06,SD_CARD_ERROR_CMD8 - Send and check interface settings
0X07,SD_CARD_ERROR_CMD9 - Read CSD data
0X08,SD_CARD_ERROR_CMD10 - Read CID data
0X09,SD_CARD_ERROR_CMD12 - Stop multiple block read
0X09,SD_CARD_ERROR_CMD12 - Stop multiple block transmission
0X0A,SD_CARD_ERROR_CMD13 - Read card status
0X0B,SD_CARD_ERROR_CMD17 - Read single block
0X0C,SD_CARD_ERROR_CMD18 - Read multiple blocks

Binary file not shown.

View file

@ -20,11 +20,10 @@
*/
#ifdef __AVR__
#include <SPI.h>
#include "SdFat.h"
#include "AvrAdcLogger.h"
#include "BufferedPrint.h"
#include "FreeStack.h"
#include "SdFat.h"
// Save SRAM if 328.
#ifdef __AVR_ATmega328P__

View file

@ -1,9 +1,9 @@
// Test and benchmark of the fast bufferedPrint class.
//
// Mainly for AVR but may improve print performance with other CPUs.
#include "BufferedPrint.h"
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "BufferedPrint.h"
// 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.
#define SD_FAT_TYPE 3
@ -28,13 +28,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -1,6 +1,7 @@
/*
* Example use of chdir(), ls(), mkdir(), and rmdir().
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "sdios.h"
@ -28,13 +29,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
//------------------------------------------------------------------------------
#if SD_FAT_TYPE == 0

View file

@ -3,9 +3,10 @@
//
// The maximum data rate will depend on the quality of your SD,
// the size of the FIFO, and using dedicated SPI.
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "ExFatLogger.h"
#include "FreeStack.h"
#include "SdFat.h"
//------------------------------------------------------------------------------
// This example was designed for exFAT but will support FAT16/FAT32.
// Note: Uno will not support SD_FAT_TYPE = 3.
@ -69,13 +70,16 @@ const uint32_t PREALLOCATE_SIZE_MiB = 1024UL;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
// Save SRAM if 328.
#ifdef __AVR_ATmega328P__
@ -92,7 +96,7 @@ void logRecord(data_t* data, uint16_t overrun) {
data->adc[0] = 0X8000 | overrun;
} else {
for (size_t i = 0; i < ADC_COUNT; i++) {
data->adc[i] = analogRead(i);
data->adc[i] = analogRead(A0 + i);
}
}
}

View file

@ -1,6 +1,7 @@
/*
* Print size, modify date/time, and name for all files in root.
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
@ -27,13 +28,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -1,3 +1,4 @@
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
@ -24,13 +25,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;
@ -126,7 +130,7 @@ void setup() {
if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
error("open failed");
}
// Write test data.
// Write test data. Test missing CRLF on last line.
file.print(
F("abc,123,456,7.89\r\n"
"def,-321,654,-9.87\r\n"
@ -143,6 +147,10 @@ void setup() {
if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
error("line too long");
}
if (line[n - 1] == '\n') {
// Remove new line.
line[n -1] = 0;
}
if (!parseLine(line)) {
error("parseLine failed");
}

View file

@ -0,0 +1,93 @@
// RP2040 PIO SDIO setup and test.
/*
This example requires a SDIO Card socket with the following six lines.
CLK - A clock signal sent to the card by the MCU.
CMD - A bidirectional line for for commands and responses.
DAT[0:3] - Four bidirectional lines for data transfer.
CLK and CMD can be connected to any GPIO pins. DAT[0:3] can be connected
to any four consecutive GPIO pins in the order DAT0, DAT1, DAT2, DAT3.
For testing, I use several RP2040/RP3350 boards.
The Adafruit Metro RP2040 which has a builtin SDIO socket.
https://learn.adafruit.com/adafruit-metro-rp2040
I use this SD socket breakout board for other boards.
https://learn.adafruit.com/adafruit-microsd-spi-sdio
Wires should be short since signals can be as faster than 50 MHz.
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
//------------------------------------------------------------------------------
// Example GPIO definitions I use for debug. Edit for your setup.
// Run this example as is to print the symbol for your variant.
//
#if defined(ARDUINO_ADAFRUIT_METRO_RP2040)
#define RP_CLK_GPIO 18
#define RP_CMD_GPIO 19
#define RP_DAT0_GPIO 20 // DAT1: GPIO21, DAT2: GPIO22, DAT3: GPIO23.
#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_2)
#define RP_CLK_GPIO 16
#define RP_CMD_GPIO 17
#define RP_DAT0_GPIO 18 // DAT1: GPIO19, DAT2: GPIO20, DAT3: GPIO21.
#elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2350_HSTX)
#define RP_CLK_GPIO 11
#define RP_CMD_GPIO 10
#define RP_DAT0_GPIO 22 // DAT1: GPIO23, DAT2: GPIO24, DAT3: GPIO25.
#endif // defined(ARDUINO_ADAFRUIT_METRO_RP2040))
#if defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#else // defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
#warning "Undefined SD_CONFIG. Run this program for the Variant Symbol."
#endif // defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
//------------------------------------------------------------------------------
// Class File is not defined by SdFat since the RP2040 system defines it.
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3
#if SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
void setup() {
Serial.begin(9600);
while (!Serial) {
yield();
}
Serial.println("Type any character to start\n");
while (!Serial.available()) {
yield();
}
Serial.print("Variant Symbol: ");
Serial.print("ARDUINO_");
Serial.println(BOARD_NAME);
Serial.println();
#if defined(SD_CONFIG)
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
Serial.println("Card successfully initialized.");
Serial.println("\nls:");
sd.ls(LS_A | LS_DATE | LS_SIZE); // Add LS_R for recursive list.
Serial.println("\nDone! Try the bench example next.");
#else // #if defined(SD_CONFIG)
Serial.println("Error: SD_CONFIG undefined for your board.");
Serial.println("Define RP_CLK_GPIO, RP_CMD_GPIO, and RP_DAT0_GPIO above.");
#endif
}
void loop() {}

View file

@ -35,13 +35,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -10,6 +10,7 @@
* For very small cards this program uses FAT16
* and the above SDFormatter uses FAT12.
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "sdios.h"
@ -40,13 +41,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
//==============================================================================
// Serial output stream
ArduinoOutStream cout(Serial);

View file

@ -6,6 +6,7 @@
* https://gurumeditation.org/1342/sd-memory-card-register-decoder/
* https://archive.goughlui.com/static/multicid.htm
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "sdios.h"
/*
@ -30,13 +31,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
//------------------------------------------------------------------------------
SdFs sd;

View file

@ -6,9 +6,9 @@
//
#include "ADC.h"
#include "DMAChannel.h"
#include "SdFat.h"
#include "FreeStack.h"
#include "RingBuf.h"
#include "SdFat.h"
// Pin must be on first ADC.
#define ADC_PIN A0

View file

@ -29,13 +29,13 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -5,9 +5,8 @@
// puts the controller in write mode and takes about 11 usec on a
// Teensy 4.1. About 5 usec is required to write a sector when the
// controller is in write mode.
#include "RingBuf.h"
#include "SdFat.h"
#include "RingBuf.h"
// Use Teensy SDIO
#define SD_CONFIG SdioConfig(FIFO_SDIO)

View file

@ -1,7 +1,16 @@
// Simple test of Unicode filename.
// Unicode is supported as UTF-8 encoded strings.
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
// 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.
#if defined __has_include
#if __has_include(<FS.h>)
#define SD_FAT_TYPE 3 // Can't use SdFat/File
#endif // __has_include(<FS.h>)
#endif // defined __has_include
// USE_UTF8_LONG_NAMES must be non-zero in SdFat/src/SdFatCongfig.h
#if USE_UTF8_LONG_NAMES
@ -11,10 +20,6 @@ const char* names[] = {u8"россиянин", u8"très élégant", u8"狗.txt",
// Remove files if non-zero.
#define REMOVE_UTF8_FILES 1
// 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.
#define SD_FAT_TYPE 0
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
@ -24,13 +29,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -1,13 +1,22 @@
/*
* This program is a simple binary write/read benchmark.
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "FreeStack.h"
#include "sdios.h"
// 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.
#define SD_FAT_TYPE 3
#if defined __has_include
#if __has_include(<FS.h>)
#define SD_FAT_TYPE 3 // Can't use SdFat/File
#endif // __has_include(<FS.h>)
#endif // defined __has_include
#ifndef SD_FAT_TYPE
#define SD_FAT_TYPE 0 // Use SdFat/File
#endif // SD_FAT_TYPE
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
@ -27,14 +36,24 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_CLOCK SD_SCK_MHZ(50)
// Example SDIO definition for RP2040/RP2350. See the Rp2040SdioSetup example.
#if defined(ARDUINO_ADAFRUIT_METRO_RP2040) && !defined(RP_CLK_GPIO)
#define RP_CLK_GPIO 18
#define RP_CMD_GPIO 19
#define RP_DAT0_GPIO 20 // DAT1: GPIO21, DAT2: GPIO22, DAT3: GPIO23.
#endif // defined(ARDUINO_ADAFRUIT_METRO_RP2040)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
// Set PRE_ALLOCATE true to pre-allocate file clusters.
const bool PRE_ALLOCATE = true;
@ -128,6 +147,11 @@ void setup() {
"\nSet ENABLE_DEDICATED_SPI nonzero in\n"
"SdFatConfig.h for best SPI performance.\n");
}
if (!SD_HAS_CUSTOM_SPI && !USE_SPI_ARRAY_TRANSFER && isSpi(SD_CONFIG)) {
cout << F(
"\nSetting USE_SPI_ARRAY_TRANSFER nonzero in\n"
"SdFatConfig.h may improve SPI performance.\n");
}
// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
}

View file

@ -1,6 +1,7 @@
/*
* This program demonstrates use of rename().
*/
#define DISABLE_FS_H_WARNING // Disable warning for type File not defined.
#include "SdFat.h"
#include "sdios.h"
@ -29,13 +30,16 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SPI_CLOCK SD_SCK_MHZ(50)
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(RP_CLK_GPIO) && defined(RP_CMD_GPIO) && defined(RP_DAT0_GPIO)
// See the Rp2040SdioSetup example for RP2040/RP2350 boards.
#define SD_CONFIG SdioConfig(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#else // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
#endif // HAS_TEENSY_SDIO
#if SD_FAT_TYPE == 0
SdFat sd;

View file

@ -1,2 +1,2 @@
sh cpplint.sh
bash cpplint.sh
pause

2236
extras/cpplint.py vendored

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,2 @@
#!/bin/sh
export PATH=/cygdrive/c/Python27:/cygdrive/c/Python27/DLLs:/cygdrive/c/Python27/Scripts:$PATH
echo $PATH
python cpplint.py --filter=-build/include,-runtime/references,-build/header_guard ../src/*.* ../src/*/*.* 2>cpplint.txt
#! /usr/bin/bash
./cpplint.py ../src/*.cpp ../src/*.h ../src/*/*.cpp ../src/*/*.h ../src/SdCard/*/*.cpp ../src/SdCard/*/*.h 2>cpplint.txt

View file

@ -1,3 +1,4 @@
pause
clang-format --style=Google -i *.cpp *.h
rem clang-format --style=Google -i DigitalIO/*.h
rem clang-format --style=Google -i DigitalIO/boards/*.h
@ -7,5 +8,6 @@ clang-format --style=Google -i FatLib/*.cpp FatLib/*.h
clang-format --style=Google -i FsLib/*.cpp FsLib/*.h
clang-format --style=Google -i iostream/*.cpp iostream/*.h
clang-format --style=Google -i SdCard/*.cpp SdCard/*.h
clang-format --style=Google -i SdCard/*/*.cpp SdCard/*/*.h
clang-format --style=Google -i SpiDriver/*.cpp SpiDriver/*.h
pause

BIN
images/SdioSpi.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

BIN
images/picowbell.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

View file

@ -1,5 +1,5 @@
name=SdFat
version=2.2.3
version=2.3.0
license=MIT
author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net>

1
src/.clang-format-ignore Normal file
View file

@ -0,0 +1 @@
SdCard/Rp2040Sdio/PioSdioCard.pio.h

3
src/CPPLINT.cfg Normal file
View file

@ -0,0 +1,3 @@
filter=-build/include,-runtime/references,-build/header_guard
filter=-whitespace/indent_namespace
exclude_files=SdFatDebugConfig.h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -33,7 +33,7 @@ static void printHex(print_t* pr, uint32_t val);
static void printHex64(print_t* pr, uint64_t n);
static void println64(print_t* pr, uint64_t n);
//------------------------------------------------------------------------------
static void dmpDirData(print_t* pr, DirGeneric_t* dir) {
static void dmpDirData(print_t* pr, const DirGeneric_t* dir) {
for (uint8_t k = 0; k < 31; k++) {
if (k) {
pr->write(' ');
@ -53,7 +53,7 @@ static uint16_t exFatDirChecksum(const void* dir, uint16_t checksum) {
}
//------------------------------------------------------------------------------
static uint16_t hashDir(DirName_t* dir, uint16_t hash) {
static uint16_t hashDir(const DirName_t* dir, uint16_t hash) {
for (uint8_t i = 0; i < 30; i += 2) {
uint16_t u = getLe16(dir->unicode + i);
if (!u) {
@ -266,7 +266,7 @@ static void println64(print_t* pr, uint64_t n) {
pr->println(str);
}
//------------------------------------------------------------------------------
static void printMbr(print_t* pr, MbrSector_t* mbr) {
static void printMbr(print_t* pr, const MbrSector_t* mbr) {
pr->print(F("mbrSig: 0x"));
pr->println(getLe16(mbr->signature), HEX);
for (int i = 0; i < 4; i++) {
@ -299,7 +299,7 @@ void ExFatPartition::checkUpcase(print_t* pr) {
pr->println(F("read root failed"));
return;
}
DirUpcase_t* dir = reinterpret_cast<DirUpcase_t*>(cache);
const DirUpcase_t* dir = reinterpret_cast<DirUpcase_t*>(cache);
pr->println(F("\nChecking upcase table"));
for (size_t i = 0; i < 16; i++) {
@ -383,7 +383,7 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
pr->println(F("cache read failed"));
return;
}
uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
const uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
for (size_t k = 0; k < 128; k++) {
if (0 == cluster % 8) {
if (k) {
@ -400,7 +400,7 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
}
//------------------------------------------------------------------------------
void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) {
uint8_t* cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ);
const uint8_t* cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ);
if (!cache) {
pr->println(F("dmpSector failed"));
return;
@ -553,7 +553,7 @@ void ExFatPartition::printUpcase(print_t* pr) {
uint32_t sector;
uint32_t size = 0;
uint32_t checksum = 0;
DirUpcase_t* dir;
const DirUpcase_t* dir;
sector = clusterStartSector(m_rootDirectoryCluster);
upcase = dataCachePrepare(sector, FsCache::CACHE_FOR_READ);
dir = reinterpret_cast<DirUpcase_t*>(upcase);
@ -601,7 +601,7 @@ bool ExFatPartition::printVolInfo(print_t* pr) {
pr->println(F("read mbr failed"));
return false;
}
MbrSector_t* mbr = reinterpret_cast<MbrSector_t*>(cache);
const MbrSector_t* mbr = reinterpret_cast<MbrSector_t*>(cache);
printMbr(pr, mbr);
uint32_t volStart = getLe32(mbr->part->relativeSectors);
uint32_t volSize = getLe32(mbr->part->totalSectors);

View file

@ -98,7 +98,7 @@ void ExFatFile::fgetpos(fspos_t* pos) const {
pos->cluster = m_curCluster;
}
//------------------------------------------------------------------------------
int ExFatFile::fgets(char* str, int num, char* delim) {
int ExFatFile::fgets(char* str, int num, const char* delim) {
char ch;
int n = 0;
int r = -1;
@ -136,7 +136,7 @@ void ExFatFile::fsetpos(const fspos_t* pos) {
}
//------------------------------------------------------------------------------
bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
DirFile_t* df = reinterpret_cast<DirFile_t*>(
const DirFile_t* df = reinterpret_cast<DirFile_t*>(
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
if (!df) {
DBG_FAIL_MACRO;
@ -151,7 +151,7 @@ fail:
}
//------------------------------------------------------------------------------
bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
DirFile_t* df = reinterpret_cast<DirFile_t*>(
const DirFile_t* df = reinterpret_cast<DirFile_t*>(
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
if (!df) {
DBG_FAIL_MACRO;
@ -166,7 +166,7 @@ fail:
}
//------------------------------------------------------------------------------
bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
DirFile_t* df = reinterpret_cast<DirFile_t*>(
const DirFile_t* df = reinterpret_cast<DirFile_t*>(
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
if (!df) {
DBG_FAIL_MACRO;
@ -223,7 +223,6 @@ bool ExFatFile::open(ExFatFile* dirFile, const char* path, oflag_t oflag) {
DBG_WARN_MACRO;
goto fail;
}
// tmpDir = *this;
tmpDir.copy(this);
dirFile = &tmpDir;
close();
@ -255,7 +254,6 @@ bool ExFatFile::openCwd() {
DBG_FAIL_MACRO;
goto fail;
}
// *this = *ExFatVolume::cwv()->vwd();
this->copy(ExFatVolume::cwv()->vwd());
rewind();
return true;
@ -633,7 +631,7 @@ int ExFatFile::read(void* buf, size_t count) {
DBG_FAIL_MACRO;
goto fail;
}
uint8_t* src = cache + sectorOffset;
const uint8_t* src = cache + sectorOffset;
memcpy(dst, src, n);
#if USE_MULTI_SECTOR_IO
} else if (toRead >= 2 * m_vol->bytesPerSector()) {

View file

@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ExFatFile_h
#define ExFatFile_h
#pragma once
/**
* \file
* \brief ExFatFile class
@ -247,7 +246,7 @@ class ExFatFile {
* 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);
int fgets(char* str, int num, const char* delim = nullptr);
/** \return The total number of bytes in a file. */
uint64_t fileSize() const { return m_validLength; }
/** \return Address of first sector or zero for empty file. */
@ -898,4 +897,3 @@ class ExFile : public StreamFile<ExFatFile, uint64_t> {
return tmpFile;
}
};
#endif // ExFatFile_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -143,7 +143,7 @@ size_t ExFatFile::printModifyDateTime(print_t* pr) {
}
//------------------------------------------------------------------------------
size_t ExFatFile::printName7(print_t* pr) {
DirName_t* dn;
const DirName_t* dn;
size_t n = 0;
uint8_t in;
uint8_t buf[15];
@ -174,7 +174,7 @@ fail:
}
//------------------------------------------------------------------------------
size_t ExFatFile::printName8(print_t* pr) {
DirName_t* dn;
const DirName_t* dn;
uint16_t hs = 0;
uint32_t cp;
size_t n = 0;
@ -211,7 +211,7 @@ size_t ExFatFile::printName8(print_t* pr) {
DBG_FAIL_MACRO;
goto fail;
}
char* str = FsUtf::cpToMb(cp, buf, buf + sizeof(buf));
const char* str = FsUtf::cpToMb(cp, buf, buf + sizeof(buf));
if (!str) {
DBG_FAIL_MACRO;
goto fail;

View file

@ -179,7 +179,6 @@ bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
goto fail;
}
}
// tmpDir = *this;
tmpDir.copy(this);
parent = &tmpDir;
close();
@ -313,7 +312,6 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
DBG_FAIL_MACRO;
goto fail;
}
// oldFile = *this;
oldFile.copy(this);
m_dirPos = file.m_dirPos;
m_setCount = file.m_setCount;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ExFatFormatter_h
#define ExFatFormatter_h
#pragma once
#include "../common/FsBlockDevice.h"
/**
* \class ExFatFormatter
@ -32,7 +31,7 @@
class ExFatFormatter {
public:
/** Constructor. */
ExFatFormatter() = default;
ExFatFormatter() = default; // cppcheck-suppress uninitMemberVar
/**
* Format an exFAT volume.
*
@ -55,4 +54,3 @@ class ExFatFormatter {
FsBlockDevice* m_dev;
uint8_t* m_secBuf;
};
#endif // ExFatFormatter_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -66,7 +66,7 @@ bool ExFatFile::cmpName(const DirName_t* dirName, ExName_t* fname) {
}
//------------------------------------------------------------------------------
size_t ExFatFile::getName7(char* name, size_t count) {
DirName_t* dn;
const DirName_t* dn;
size_t n = 0;
if (!isOpen()) {
DBG_FAIL_MACRO;
@ -100,10 +100,10 @@ fail:
}
//------------------------------------------------------------------------------
size_t ExFatFile::getName8(char* name, size_t count) {
char* end = name + count;
const char* end = name + count;
char* str = name;
char* ptr;
DirName_t* dn;
const DirName_t* dn;
uint16_t hs = 0;
uint32_t cp;
if (!isOpen()) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -36,7 +36,7 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
uint32_t bgnAlloc = start;
uint16_t sectorSize = 1 << m_bytesPerSectorShift;
size_t i = (start >> 3) & (sectorSize - 1);
uint8_t* cache;
const uint8_t* cache;
uint8_t mask = 1 << (start & 7);
while (true) {
uint32_t sector =
@ -136,7 +136,7 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) {
return n;
}
//------------------------------------------------------------------------------
uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) {
uint8_t* ExFatPartition::dirCache(const DirPos_t* pos, uint8_t options) {
uint32_t sector = clusterStartSector(pos->cluster);
sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift;
uint8_t* cache = dataCachePrepare(sector, options);
@ -164,7 +164,7 @@ int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
//------------------------------------------------------------------------------
// return -1 error, 0 EOC, 1 OK
int8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) {
uint8_t* cache;
const uint8_t* cache;
uint32_t next;
uint32_t sector;
@ -240,7 +240,7 @@ int32_t ExFatPartition::freeClusterCount() {
uint32_t nc = 0;
uint32_t sector = m_clusterHeapStartSector;
uint32_t usedCount = 0;
uint8_t* cache;
const uint8_t* cache;
while (true) {
cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
@ -267,8 +267,8 @@ int32_t ExFatPartition::freeClusterCount() {
//------------------------------------------------------------------------------
bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
pbs_t* pbs;
BpbExFat_t* bpb;
MbrSector_t* mbr;
const BpbExFat_t* bpb;
const MbrSector_t* mbr;
m_fatType = 0;
m_blockDev = dev;
cacheInit(m_blockDev);
@ -285,7 +285,7 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
DBG_FAIL_MACRO;
goto fail;
}
MbrPart_t* mp = mbr->part + part - 1;
const MbrPart_t* mp = mbr->part + part - 1;
if (mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) {
DBG_FAIL_MACRO;
goto fail;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ExFatPartition_h
#define ExFatPartition_h
#pragma once
/**
* \file
* \brief ExFatPartition include file.
@ -60,7 +59,7 @@ struct DirPos_t {
*/
class ExFatPartition {
public:
ExFatPartition() = default;
ExFatPartition() = default; // cppcheck-suppress uninitMemberVar
/** \return the number of bytes in a cluster. */
uint32_t bytesPerCluster() const { return m_bytesPerCluster; }
/** \return the power of two for bytesPerCluster. */
@ -177,7 +176,7 @@ class ExFatPartition {
return m_clusterHeapStartSector +
((cluster - 2) << m_sectorsPerClusterShift);
}
uint8_t* dirCache(DirPos_t* pos, uint8_t options);
uint8_t* dirCache(const DirPos_t* pos, uint8_t options);
int8_t dirSeek(DirPos_t* pos, uint32_t offset);
int8_t fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
@ -224,4 +223,3 @@ class ExFatPartition {
uint8_t m_fatType = 0;
uint8_t m_sectorsPerClusterShift;
};
#endif // ExFatPartition_h

View file

@ -37,7 +37,6 @@ bool ExFatVolume::chdir(const char* path) {
DBG_FAIL_MACRO;
goto fail;
}
// m_vwd = dir;
m_vwd.copy(&dir);
return true;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -25,7 +25,7 @@
#include "FatLib.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//------------------------------------------------------------------------------
static uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i) {
static uint16_t getLfnChar(const DirLfn_t* ldir, uint8_t i) {
if (i < 5) {
return getLe16(ldir->unicode1 + 2 * i);
} else if (i < 11) {
@ -245,7 +245,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
uint32_t sector = m_fatStartSector + start;
uint32_t cluster = nf * start;
for (uint32_t i = 0; i < count; i++) {
uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
const uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
if (!pc) {
pr->println(F("cache read failed"));
return;

View file

@ -197,7 +197,7 @@ fail:
}
//------------------------------------------------------------------------------
bool FatFile::dirEntry(DirFat_t* dst) {
DirFat_t* dir;
const DirFat_t* dir;
// Make sure fields on device are correct.
if (!sync()) {
DBG_FAIL_MACRO;
@ -237,7 +237,7 @@ uint32_t FatFile::dirSize() {
return 512UL * n;
}
//------------------------------------------------------------------------------
int FatFile::fgets(char* str, int num, char* delim) {
int FatFile::fgets(char* str, int num, const char* delim) {
char ch;
int n = 0;
int r = -1;
@ -354,7 +354,6 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
goto fail;
}
}
// tmpDir = *this;
tmpDir.copy(this);
parent = &tmpDir;
close();
@ -478,7 +477,6 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) {
DBG_WARN_MACRO;
goto fail;
}
// tmpDir = *this;
tmpDir.copy(this);
dirFile = &tmpDir;
close();
@ -497,7 +495,7 @@ bool FatFile::open(uint16_t index, oflag_t oflag) {
bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) {
if (index) {
// Find start of LFN.
DirLfn_t* ldir;
const DirLfn_t* ldir;
uint8_t n = index < 20 ? index : 20;
for (uint8_t i = 1; i <= n; i++) {
ldir = reinterpret_cast<DirLfn_t*>(dirFile->cacheDir(index - i));
@ -634,7 +632,6 @@ bool FatFile::openCwd() {
DBG_FAIL_MACRO;
goto fail;
}
// *this = *FatVolume::cwv()->vwd();
this->copy(FatVolume::cwv()->vwd());
rewind();
return true;
@ -645,7 +642,7 @@ fail:
//------------------------------------------------------------------------------
bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
uint8_t checksum = 0;
DirLfn_t* ldir;
const DirLfn_t* ldir;
uint8_t lfnOrd = 0;
uint16_t index;
@ -840,7 +837,7 @@ int FatFile::read(void* buf, size_t nbyte) {
DBG_FAIL_MACRO;
goto fail;
}
uint8_t* src = pc + offset;
const uint8_t* src = pc + offset;
memcpy(dst, src, n);
#if USE_MULTI_SECTOR_IO
} else if (toRead >= 2 * m_vol->bytesPerSector()) {
@ -968,7 +965,6 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
}
// sync() and cache directory entry
sync();
// oldFile = *this;
oldFile.copy(this);
dir = cacheDirEntry(FsCache::CACHE_FOR_READ);
if (!dir) {
@ -1064,7 +1060,7 @@ bool FatFile::rmdir() {
// make sure directory is empty
while (1) {
DirFat_t* dir = readDirCache(true);
const DirFat_t* dir = readDirCache(true);
if (!dir) {
// EOF if no error.
if (!getError()) {
@ -1108,7 +1104,7 @@ bool FatFile::rmRfStar() {
// remember position
index = m_curPosition / FS_DIR_SIZE;
DirFat_t* dir = readDirCache();
const DirFat_t* dir = readDirCache();
if (!dir) {
// At EOF if no error.
if (!getError()) {

View file

@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatFile_h
#define FatFile_h
#pragma once
/**
* \file
* \brief FatFile class
@ -330,7 +329,7 @@ class FatFile {
* 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);
int fgets(char* str, int num, const char* delim = nullptr);
/** \return The total number of bytes in a file. */
uint32_t fileSize() const { return m_fileSize; }
/** \return first sector of file or zero for empty file. */
@ -1030,7 +1029,7 @@ class FatFile {
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);
uint16_t getLfnChar(const DirLfn_t* ldir, uint8_t i);
uint8_t lfnChecksum(const uint8_t* name) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
@ -1045,8 +1044,8 @@ class FatFile {
bool parsePathName(const char* str, FatSfn_t* fname, const char** ptr);
bool mkdir(FatFile* parent, FatName_t* fname);
bool open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag);
bool open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag);
bool openSFN(FatSfn_t* fname);
bool open(FatFile* dirFile, const FatSfn_t* fname, oflag_t oflag);
bool openSFN(const FatSfn_t* fname);
bool openCachedEntry(FatFile* dirFile, uint16_t cacheIndex, oflag_t oflag,
uint8_t lfnOrd);
DirFat_t* readDirCache(bool skipReadOk = false);
@ -1098,4 +1097,3 @@ class File32 : public StreamFile<FatFile, uint32_t> {
return tmpFile;
}
};
#endif // FatFile_h

View file

@ -54,10 +54,9 @@ static void putLfnChar(DirLfn_t* ldir, uint8_t i, uint16_t c) {
}
//==============================================================================
bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
// FatFile dir = *this;
FatFile dir;
dir.copy(this);
DirLfn_t* ldir;
const DirLfn_t* ldir;
fname->reset();
for (uint8_t order = 1; order <= lfnOrd; order++) {
ldir = reinterpret_cast<DirLfn_t*>(dir.cacheDir(index - order));
@ -94,7 +93,6 @@ fail:
}
//------------------------------------------------------------------------------
bool FatFile::createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
// FatFile dir = *this;
FatFile dir;
dir.copy(this);
DirLfn_t* ldir;
@ -220,7 +218,7 @@ fail:
bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
uint8_t pos = fname->seqPos;
DirFat_t* dir;
const DirFat_t* dir;
uint16_t hex = 0;
DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
@ -284,7 +282,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
uint16_t freeTotal;
uint16_t time;
DirFat_t* dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
auto vol = dirFile->m_vol;
if (!dirFile->isDir() || isOpen()) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -28,7 +28,7 @@
//------------------------------------------------------------------------------
// open with filename in fname
#define SFN_OPEN_USES_CHKSUM 0
bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
bool FatFile::open(FatFile* dirFile, const FatSfn_t* fname, oflag_t oflag) {
uint16_t date;
uint16_t time;
uint8_t ms10;
@ -40,7 +40,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
uint16_t emptyIndex = 0;
uint16_t index = 0;
DirFat_t* dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
dirFile->rewind();
while (true) {
@ -156,7 +156,6 @@ bool FatFile::openExistingSFN(const char* path) {
if (*path == 0) {
return openRoot(vol);
}
// *this = *vol->vwd();
this->copy(vol->vwd());
do {
if (!parsePathName(path, &fname, &path)) {
@ -174,9 +173,9 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool FatFile::openSFN(FatSfn_t* fname) {
bool FatFile::openSFN(const FatSfn_t* fname) {
DirFat_t dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
auto vol = m_vol;
uint8_t lfnOrd = 0;
if (!isDir()) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatFormatter_h
#define FatFormatter_h
#pragma once
#include "../common/FsBlockDevice.h"
#include "../common/SysCall.h"
/**
@ -33,7 +32,7 @@
class FatFormatter {
public:
/** Constructor. */
FatFormatter() = default;
FatFormatter() = default; // cppcheck-suppress uninitMemberVar
/**
* Format a FAT volume.
*
@ -65,4 +64,3 @@ class FatFormatter {
uint8_t m_partType;
uint8_t m_sectorsPerCluster;
};
#endif // FatFormatter_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,6 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatLib_h
#define FatLib_h
#pragma once
#include "FatFormatter.h"
#include "FatVolume.h"
#endif // FatLib_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -27,7 +27,7 @@
#include "../common/FsUtf.h"
#include "FatLib.h"
//------------------------------------------------------------------------------
uint16_t FatFile::getLfnChar(DirLfn_t* ldir, uint8_t i) {
uint16_t FatFile::getLfnChar(const DirLfn_t* ldir, uint8_t i) {
if (i < 5) {
return getLe16(ldir->unicode1 + 2 * i);
} else if (i < 11) {
@ -51,7 +51,7 @@ size_t FatFile::getName(char* name, size_t size) {
//------------------------------------------------------------------------------
size_t FatFile::getName7(char* name, size_t size) {
FatFile dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
size_t n = 0;
if (!isOpen()) {
DBG_FAIL_MACRO;
@ -97,11 +97,11 @@ fail:
}
//------------------------------------------------------------------------------
size_t FatFile::getName8(char* name, size_t size) {
char* end = name + size;
const char* end = name + size;
char* str = name;
char* ptr;
FatFile dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
uint16_t hs = 0;
uint32_t cp;
if (!isOpen()) {
@ -169,8 +169,8 @@ size_t FatFile::getSFN(char* name, size_t size) {
char c;
uint8_t j = 0;
uint8_t lcBit = FAT_CASE_LC_BASE;
uint8_t* ptr;
DirFat_t* dir;
const uint8_t* ptr;
const DirFat_t* dir;
if (!isOpen()) {
DBG_FAIL_MACRO;
goto fail;
@ -234,7 +234,7 @@ size_t FatFile::printName(print_t* pr) {
//------------------------------------------------------------------------------
size_t FatFile::printName7(print_t* pr) {
FatFile dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
size_t n = 0;
uint8_t buf[13];
uint8_t i;
@ -280,12 +280,12 @@ fail:
//------------------------------------------------------------------------------
size_t FatFile::printName8(print_t* pr) {
FatFile dir;
DirLfn_t* ldir;
const DirLfn_t* ldir;
uint16_t hs = 0;
uint32_t cp;
size_t n = 0;
char buf[5];
char* end = buf + sizeof(buf);
const char* end = buf + sizeof(buf);
if (!isOpen()) {
DBG_FAIL_MACRO;
goto fail;
@ -329,7 +329,7 @@ size_t FatFile::printName8(print_t* pr) {
DBG_FAIL_MACRO;
goto fail;
}
char* str = FsUtf::cpToMb(cp, buf, end);
const char* str = FsUtf::cpToMb(cp, buf, end);
if (!str) {
DBG_FAIL_MACRO;
goto fail;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -157,7 +157,7 @@ fail:
int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t sector;
uint32_t next;
uint8_t* pc;
const uint8_t* pc;
// error if reserved cluster of beyond FAT
if (cluster < 2 || cluster > m_lastCluster) {
@ -362,14 +362,14 @@ int32_t FatPartition::freeClusterCount() {
n = todo;
}
if (fatType() == 16) {
uint16_t* p16 = reinterpret_cast<uint16_t*>(pc);
const uint16_t* p16 = reinterpret_cast<uint16_t*>(pc);
for (uint16_t i = 0; i < n; i++) {
if (p16[i] == 0) {
free++;
}
}
} else {
uint32_t* p32 = reinterpret_cast<uint32_t*>(pc);
const uint32_t* p32 = reinterpret_cast<uint32_t*>(pc);
for (uint16_t i = 0; i < n; i++) {
if (p32[i] == 0) {
free++;
@ -395,8 +395,8 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
uint32_t totalSectors;
m_blockDev = dev;
pbs_t* pbs;
BpbFat32_t* bpb;
MbrSector_t* mbr;
const BpbFat32_t* bpb;
const MbrSector_t* mbr;
uint8_t tmp;
m_fatType = 0;
m_allocSearchStart = 1;
@ -417,7 +417,7 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
DBG_FAIL_MACRO;
goto fail;
}
MbrPart_t* mp = mbr->part + part - 1;
const MbrPart_t* mp = mbr->part + part - 1;
if (mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) {
DBG_FAIL_MACRO;
goto fail;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatPartition_h
#define FatPartition_h
#pragma once
/**
* \file
* \brief FatPartition class
@ -53,7 +52,7 @@ class FatPartition {
public:
/** Create an instance of FatPartition
*/
FatPartition() = default;
FatPartition() = default; // cppcheck-suppress uninitMemberVar
/** \return The shift count required to multiply by bytesPerCluster. */
uint8_t bytesPerClusterShift() const {
@ -235,4 +234,3 @@ class FatPartition {
bool freeChain(uint32_t cluster);
bool isEOC(uint32_t cluster) const { return cluster > m_lastCluster; }
};
#endif // FatPartition

View file

@ -37,7 +37,6 @@ bool FatVolume::chdir(const char* path) {
DBG_FAIL_MACRO;
goto fail;
}
// m_vwd = dir;
m_vwd.copy(&dir);
return true;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatVolume_h
#define FatVolume_h
#pragma once
#include "FatFile.h"
/**
* \file
@ -344,4 +343,3 @@ class FatVolume : public FatPartition {
static FatVolume* m_cwv;
FatFile m_vwd;
};
#endif // FatVolume_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -53,7 +53,7 @@ inline char* stackPointer() {
const char FILL = 0x55;
void FillStack() {
char* p = stackBegin();
char* top = stackPointer();
const char* top = stackPointer();
while (p < top) {
*p++ = FILL;
}
@ -62,7 +62,7 @@ void FillStack() {
// May fail if malloc or new is used.
int UnusedStack() {
char* h = stackBegin();
char* top = stackPointer();
const char* top = stackPointer();
int n;
for (n = 0; (h + n) < top; n++) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FreeStack_h
#define FreeStack_h
#pragma once
/**
* \file
* \brief FreeStack() function.
@ -41,7 +40,7 @@ extern char __bss_end;
* \return The number of free bytes.
*/
inline int FreeStack() {
char* sp = reinterpret_cast<char*>(SP);
const char* sp = reinterpret_cast<char*>(SP);
return __brkval ? sp - __brkval : sp - &__bss_end;
}
#elif defined(ARDUINO_ARCH_APOLLO3)
@ -87,4 +86,3 @@ int UnusedStack();
inline void FillStack() {}
inline int UnusedStack() { return 0; }
#endif // defined(HAS_UNUSED_STACK)
#endif // FreeStack_h

View file

@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsFile_h
#define FsFile_h
#pragma once
/**
* \file
* \brief FsBaseFile include file.
@ -39,7 +38,7 @@
class FsBaseFile {
public:
/** Create an instance. */
FsBaseFile() = default;
FsBaseFile() = default; // cppcheck-suppress uninitMemberVar
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path for a file to be opened.
@ -47,6 +46,7 @@ class FsBaseFile {
* \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).
*/
// cppcheck-suppress uninitMemberVar
FsBaseFile(const char* path, oflag_t oflag) { open(path, oflag); }
/** Copy from to this.
@ -105,7 +105,7 @@ class FsBaseFile {
close();
}
}
#else // DESTRUCTOR_CLOSES_FILE
#else // DESTRUCTOR_CLOSES_FILE
~FsBaseFile() = default;
#endif // DESTRUCTOR_CLOSES_FILE
@ -345,10 +345,6 @@ class FsBaseFile {
bool isDir() const {
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(); }
/** \return True if this is a normal file. */
bool isFile() const {
return m_fFile ? m_fFile->isFile() : m_xFile ? m_xFile->isFile() : false;
@ -385,6 +381,12 @@ class FsBaseFile {
: m_xFile ? m_xFile->isSubDir()
: false;
}
/** \return True if this is a System file else false. */
bool isSystem() const {
return m_fFile ? m_fFile->isSystem()
: m_xFile ? m_xFile->isSystem()
: false;
}
/** \return True file is writable. */
bool isWritable() const {
return m_fFile ? m_fFile->isWritable()
@ -562,8 +564,6 @@ class FsBaseFile {
* \return true for success or false for failure.
*/
bool openRoot(FsVolume* vol);
/** \return the current file position. */
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;
@ -759,10 +759,6 @@ class FsBaseFile {
if (m_fFile) m_fFile->rewind();
if (m_xFile) m_xFile->rewind();
}
/** Rewind a file if it is a directory */
void rewindDirectory() {
if (isDir()) rewind();
}
/** Remove a directory file.
*
* The directory file will be removed only if it is empty and is not the
@ -776,13 +772,6 @@ class FsBaseFile {
* \return true for success or false for failure.
*/
bool rmdir();
/** Seek to a new position in the file, which must be between
* 0 and the size of the file (inclusive).
*
* \param[in] pos the new file position.
* \return true for success or false for failure.
*/
bool seek(uint64_t pos) { return seekSet(pos); }
/** Set the files position to current position + \a pos. See seekSet().
* \param[in] offset The new position in bytes from the current position.
* \return true for success or false for failure.
@ -805,8 +794,6 @@ class FsBaseFile {
: m_xFile ? m_xFile->seekSet(pos)
: false;
}
/** \return the file's size. */
uint64_t size() const { return fileSize(); }
/** The sync() call causes all modified data and directory fields
* to be written to the storage device.
*
@ -928,4 +915,3 @@ class FsFile : public StreamFile<FsBaseFile, uint64_t> {
return tmpFile;
}
};
#endif // FsFile_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsNew_h
#define FsNew_h
#pragma once
#include <stddef.h>
#include <stdint.h>
@ -36,11 +35,10 @@ typedef uint32_t newalign_t;
/** Dimension of aligned area. */
#define NEW_ALIGN_DIM(n) \
(((size_t)(n) + sizeof(newalign_t) - 1U) / sizeof(newalign_t))
((static_cast<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))
/** Custom new placement operator */
void* operator new(size_t size, newalign_t* ptr);
#endif // FsNew_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsVolume_h
#define FsVolume_h
#pragma once
/**
* \file
* \brief FsVolume include file.
@ -39,7 +38,7 @@ class FsFile;
*/
class FsVolume {
public:
FsVolume() = default;
FsVolume() = default; // cppcheck-suppress uninitMemberVar
~FsVolume() { end(); }
/** Get file's user settable attributes.
@ -399,4 +398,3 @@ class FsVolume {
FatVolume* m_fVol = nullptr;
ExFatVolume* m_xVol = nullptr;
};
#endif // FsVolume_h

View file

@ -1 +0,0 @@
exclude_files=SdioTeensy.h

View file

@ -0,0 +1 @@
exclude_files=PioSdioCard.pio.h

View file

@ -0,0 +1,162 @@
/**
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "Printable.h"
#define NUM64_HEX_A 'a'
#define ENABLE_DBG_MSG 1
#define DBG_LOG_PORT Serial
#if defined(DBG_FILE)
#elif defined(__FILE_NAME__)
#define DBG_FILE __FILE_NAME__
#else
#define DBG_FILE __FILE__
#endif
#if ENABLE_DBG_MSG
#define DBG_MSG(...) \
do { \
logmsgln(F(DBG_FILE), ":", __LINE__, " ", ##__VA_ARGS__); \
} while (0)
#else // ENABLE_DBG_MSG
#define DBG_MSG(...) \
do { \
} while (0)
#endif // ENABLE_DBG_MSG
// Print binary with byte and nibble separators.
class Bin : public Printable {
// Bin not supported for 64-bits.
explicit Bin(int64_t, uint8_t = 0) {}
explicit Bin(uint64_t, uint8_t = 0) {}
public:
template <typename T>
explicit Bin(T n, uint8_t p = 0) : n_(n), p_(p) {}
size_t printTo(Print& pr) const {
auto n = n_;
uint8_t p = p_ > 8 * sizeof(n) ? 8 * sizeof(n) : p_;
char buf[10 * sizeof(n) + 1];
char* end = buf + sizeof(buf);
char* str = end;
uint8_t i = 0;
do {
if (i && (i % 4) == 0) {
*--str = i % 8 ? '\'' : '|';
}
*--str = n & 1 ? '1' : '0';
n /= 2;
i++;
} while (n || i < p);
return pr.write(str, end - str);
}
uint32_t n_;
uint8_t p_;
};
// Print floating point with precision.
struct Dbl : public Printable {
Dbl(double n_, int p_) : n(n_), p(p_) {}
size_t printTo(Print& pr) const { return pr.print(n, p); }
double n;
int p;
};
// Print in hex format.
#if __cplusplus > 201700L
template <typename T>
struct Hex : public Printable {
explicit Hex(T n_) : n(n_) {}
size_t printTo(Print& pr) const { return pr.print(n, HEX); }
T n;
};
#else // __cplusplus > 201700L
class Hex : public Printable {
// No 64-bit support unless C++17 or better.
explicit Hex(int64_t) {}
explicit Hex(uint64_t) {}
public:
template <typename T>
explicit Hex(T n_) : n(n_) {}
size_t printTo(Print& pr) const { return pr.print(n, HEX); }
uint32_t n;
};
#endif // __cplusplus > 201700L
// For boards with no 64-bit print, lower case hex, alt binary or precision.
class Num : public Printable {
uint64_t n_;
uint8_t b_;
uint8_t p_;
char s_;
public:
template <typename T>
explicit Num(T n, uint8_t b = 0, uint8_t p = 0, char s = 0) : b_(b), p_(p) {
n_ = b == 10 && n < 0 ? -n : n;
s_ = b == 10 && n < 0 ? '-' : s;
}
size_t printTo(Print& pr) const {
char buf[8 * sizeof(uint64_t) + 1];
char* end = buf + sizeof(buf);
char* str = end;
uint64_t n = n_;
uint8_t p = p_ > 8 * sizeof(n) ? 8 * sizeof(n) : p_;
uint8_t base = b_ < 2 || b_ > 16 ? 10 : b_;
uint8_t i = 0;
do {
uint8_t d = n % base;
*--str = d < 10 ? d + '0' : d + NUM64_HEX_A - 10;
n /= base;
i++;
} while (n || i < p);
if (s_) {
*--str = s_;
}
return pr.write(str, end - str);
}
};
template <typename T>
size_t logmsg(T arg) {
return DBG_LOG_PORT.print(arg);
}
size_t logmsg(bool b) { return logmsg(b ? F("true") : F("false")); }
inline size_t logmsg() { return 0; }
template <typename T, typename... Types>
size_t logmsg(T var1, Types... var2) {
size_t n = logmsg(var1);
return n += logmsg(var2...);
}
template <typename... Types>
size_t logmsgln(Types... params) {
size_t n = logmsg(params...);
return n + logmsg("\r\n");
}

View file

@ -0,0 +1,56 @@
/**
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <Arduino.h>
#include "DbgLog.h"
//------------------------------------------------------------------------------
static inline void gpioStatus(uint gpio) {
logmsgln("gpio", gpio, " drive: ", gpio_get_drive_strength(gpio));
// logmsgln("gpio", gpio,
// " drive: ", static_cast<int>(gpio_get_drive_strength(gpio)));
logmsgln("gpio", gpio, " slew: ", gpio_get_slew_rate(gpio));
logmsgln("gpio", gpio, " hyst: ", gpio_is_input_hysteresis_enabled(gpio));
logmsgln("gpio", gpio, " pull: ", gpio_is_pulled_up(gpio));
}
//------------------------------------------------------------------------------
static inline void pioRegs(PIO pio) {
logmsgln("ctrl: 0b", Bin(pio->ctrl));
logmsgln("fstat: 0b", Bin(pio->fstat));
logmsgln("fdebug: 0b", Bin(pio->fdebug));
logmsgln("flevel: 0b", Bin(pio->flevel));
logmsgln("padout: 0b", Bin(pio->dbg_padout));
logmsgln("padoe: 0b", Bin(pio->dbg_padoe));
logmsgln("cfginfo: 0x", Hex(pio->dbg_cfginfo));
logmsgln("sync_bypass: 0b", Bin(pio->input_sync_bypass));
}
//------------------------------------------------------------------------------
static inline void pioSmRegs(PIO pio, uint sm) {
logmsgln("sm", sm, " clkdiv: 0x", Hex(pio->sm[sm].clkdiv));
logmsgln("sm", sm, " execctrl: 0x", Hex(pio->sm[sm].execctrl));
logmsgln("sm", sm, " shiftctrl: 0x", Hex(pio->sm[sm].shiftctrl));
logmsgln("sm", sm, " addr: 0x", Hex(pio->sm[sm].addr));
logmsgln("sm", sm, " pinctrl: 0x", Hex(pio->sm[sm].pinctrl));
}

View file

@ -0,0 +1,954 @@
/**
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef ARDUINO_ARCH_RP2040
#define DEBUG_FILE "PioSdioCard.cpp"
#include "../SdCardInfo.h"
#include "../SdioCard.h"
#include "PioDbgInfo.h"
#include "PioSdioCard.pio.h"
//------------------------------------------------------------------------------
// Do not enable - not implemented
#define HIGH_SPEED_MODE 0 // non-zero to debug High Speed Mode
// USE_DEBUG_MODE 0 - no debug, 1 - print message, 2 - Use scope/analyzer.
#define USE_DEBUG_MODE 0
const uint PIO_CLK_DIV_INIT = 2;
const uint PIO_CLK_DIV_RUN = 1;
const uint PIN_SDIO_UNDEFINED = 31u;
const uint DAT_FIFO_DEPTH = 8;
const uint CMD0_RETRIES = 10;
const uint CMD8_RETRIES = 3;
//==============================================================================
// Command definitions.
enum { RSP_R0 = 0, RSP_R1 = 1, RSP_R2 = 2, RSP_R3 = 3, RSP_R6 = 6, RSP_R7 = 7 };
class CmdRsp_t {
public:
CmdRsp_t(uint8_t idx_, uint8_t rsp_) : idx(idx_), rsp(rsp_) {}
uint8_t idx;
uint8_t rsp;
};
static const CmdRsp_t CMD0_R0(CMD0, RSP_R0);
static const CmdRsp_t CMD2_R2(CMD2, RSP_R2);
static const CmdRsp_t CMD3_R6(CMD3, RSP_R6);
static const CmdRsp_t CMD6_R1(CMD6, RSP_R1);
static const CmdRsp_t CMD7_R1(CMD7, RSP_R1);
static const CmdRsp_t CMD8_R7(CMD8, RSP_R7);
static const CmdRsp_t CMD9_R2(CMD9, RSP_R2);
static const CmdRsp_t CMD10_R2(CMD10, RSP_R2);
static const CmdRsp_t CMD12_R1(CMD12, RSP_R1);
static const CmdRsp_t CMD13_R1(CMD13, RSP_R1);
static const CmdRsp_t CMD18_R1(CMD18, RSP_R1);
static const CmdRsp_t CMD25_R1(CMD25, RSP_R1);
static const CmdRsp_t CMD32_R1(CMD32, RSP_R1);
static const CmdRsp_t CMD33_R1(CMD33, RSP_R1);
static const CmdRsp_t CMD38_R1(CMD38, RSP_R1);
static const CmdRsp_t CMD55_R1(CMD55, RSP_R1);
static const CmdRsp_t ACMD6_R1(ACMD6, RSP_R1);
static const CmdRsp_t ACMD13_R1(ACMD13, RSP_R1);
static const CmdRsp_t ACMD41_R3(ACMD41, RSP_R3);
static const CmdRsp_t ACMD51_R1(ACMD51, RSP_R1);
//==============================================================================
// Global variables.
static float g_clkDiv = 0;
static uint g_clkPin = PIN_SDIO_UNDEFINED;
static uint g_cmdPin = PIN_SDIO_UNDEFINED;
static uint g_dat0Pin = PIN_SDIO_UNDEFINED;
static uint g_cardRsp;
static uint g_errorCode;
static uint g_errorLine;
static bool g_highCapacity;
static bool g_initDone = false;
static uint g_ocr;
static bool g_version2;
static PIO g_pio = nullptr;
static int g_sm0 = -1;
static int g_sm1 = -1;
static int g_cmdRspOffset = -1;
static pio_sm_config g_cmdConfig;
static int g_rdDataOffset = -1;
static pio_sm_config g_rdDataConfig;
static int g_rdClkOffset = -1;
static pio_sm_config g_rdClkConfig;
static int g_wrDataOffset = -1;
static pio_sm_config g_wrDataConfig;
static int g_wrRespOffset = -1;
static pio_sm_config g_wrRespConfig;
static uint g_rca;
static cid_t g_cid;
static csd_t g_csd;
static scr_t g_scr;
static sds_t g_sds;
//==============================================================================
class Timeout {
public:
explicit Timeout(uint ms) : _usStart(0), _usTimeout(1000 * ms) {}
bool timedOut() {
if (_usStart) {
return (usSinceBoot() - _usStart) > _usTimeout;
}
_usStart = usSinceBoot();
return false;
}
uint32_t usSinceBoot() { return to_us_since_boot(get_absolute_time()); }
uint32_t _usStart;
uint32_t _usTimeout;
};
//==============================================================================
// Error function and macro.
#define PIO_ERROR_ADD_PROGRAM 99
#if USE_DEBUG_MODE
#define SDIO_FAIL() logmsgln(DEBUG_FILE, '.', __LINE__, F("SDIO_FAIL"))
#define sdError(code) setSdErrorCode(code, __LINE__, #code)
static void setSdErrorCode(uint8_t code, uint32_t line, const char* txt) {
g_errorCode = code;
g_errorLine = line;
logmsgln(F(DEBUG_FILE), '.', line, ' ', txt);
}
#else // USE_DEBUG_MODE
#define SDIO_FAIL()
#define sdError(code) setSdErrorCode(code, __LINE__)
static inline void setSdErrorCode(uint8_t code, uint32_t line) {
g_errorCode = code;
g_errorLine = line;
}
#endif // USE_DEBUG_MODE
//==============================================================================
// CRC functions.
//------------------------------------------------------------------------------
// See this library's extras folder.
static const uint8_t crc7_table[256] = {
0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, // 00 - 07
0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, // 08 - 0f
0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c, // 10 - 17
0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc, // 18 - 1f
0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a, // 20 - 27
0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a, // 28 - 2f
0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28, // 30 - 37
0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8, // 38 - 3f
0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6, // 40 - 47
0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26, // 48 - 4f
0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84, // 50 - 57
0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14, // 58 - 5f
0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2, // 60 - 67
0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42, // 68 - 6f
0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0, // 70 - 77
0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70, // 78 - 7f
0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc, // 80 - 87
0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c, // 88 - 8f
0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce, // 90 - 97
0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e, // 98 - 9f
0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98, // a0 - a7
0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08, // a8 - af
0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa, // b0 - b7
0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a, // b8 - bf
0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34, // c0 - c7
0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4, // c8 - cf
0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06, // d0 - d7
0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96, // d8 - df
0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50, // e0 - e7
0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0, // e8 - ef
0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62, // f0 - f7
0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2 // f8 - ff
};
//------------------------------------------------------------------------------
inline static uint8_t CRC7(const uint8_t* data, uint8_t n) {
uint8_t crc = 0;
for (uint8_t i = 0; i < n; i++) {
crc = crc7_table[crc ^ data[i]];
}
return crc | 1;
}
//------------------------------------------------------------------------------
// Modified from sdio_crc16_4bit_checksum() in
// https://github.com/ZuluSCSI/ZuluSCSI-firmware
//
static inline __attribute__((always_inline)) uint64_t crc16(uint64_t crc,
uint32_t data_in) {
// Shift out 8 bits for each line
uint32_t data_out = crc >> 32;
crc <<= 32;
// XOR outgoing data to itself with 4 bit delay
data_out ^= (data_out >> 16);
// XOR incoming data to outgoing data with 4 bit delay
data_out ^= (data_in >> 16);
// XOR outgoing and incoming data to accumulator at each tap
uint64_t xorred = data_out ^ data_in;
crc ^= xorred;
crc ^= xorred << (5 * 4);
crc ^= xorred << (12 * 4);
return crc;
}
//==============================================================================
static void pioConfig(float clkDiv) {
g_cmdConfig =
pio_cmd_rsp_program_config(g_cmdRspOffset, g_cmdPin, g_clkPin, clkDiv);
g_rdClkConfig =
pio_rd_clk_program_config(g_rdClkOffset, g_dat0Pin, g_clkPin, clkDiv);
g_rdDataConfig =
pio_rd_data_program_config(g_rdDataOffset, g_dat0Pin, clkDiv);
g_wrDataConfig =
pio_wr_data_program_config(g_wrDataOffset, g_dat0Pin, g_clkPin, clkDiv);
g_wrRespConfig =
pio_wr_resp_program_config(g_wrRespOffset, g_dat0Pin, g_clkPin, clkDiv);
}
//------------------------------------------------------------------------------
static void pioEnd() {
if (!g_pio) {
return;
}
if (g_sm0 >= 0) {
pio_sm_unclaim(g_pio, g_sm0);
g_sm0 = -1;
}
if (g_sm1 >= 0) {
pio_sm_unclaim(g_pio, g_sm1);
g_sm1 = -1;
}
if (g_cmdRspOffset >= 0) {
pio_remove_program(g_pio, &cmd_rsp_program, g_cmdRspOffset);
g_cmdRspOffset = -1;
}
if (g_rdClkOffset >= 0) {
pio_remove_program(g_pio, &rd_clk_program, g_rdClkOffset);
g_rdClkOffset = -1;
}
if (g_rdDataOffset >= 0) {
pio_remove_program(g_pio, &rd_data_program, g_rdDataOffset);
g_rdDataOffset = -1;
}
if (g_wrDataOffset >= 0) {
pio_remove_program(g_pio, &wr_data_program, g_wrDataOffset);
g_wrDataOffset = -1;
}
if (g_wrRespOffset >= 0) {
pio_remove_program(g_pio, &wr_resp_program, g_wrRespOffset);
g_wrRespOffset = -1;
}
}
//------------------------------------------------------------------------------
static bool pioInit() {
uint pin[] = {g_clkPin, g_cmdPin, g_dat0Pin,
g_dat0Pin + 1, g_dat0Pin + 2, g_dat0Pin + 3};
if (g_wrRespOffset < 0) {
uint16_t patched_inst[rd_data_program.length]; // NOLINT
struct pio_program tmp_program;
tmp_program.instructions = nullptr;
tmp_program.length = cmd_rsp_program.length + rd_data_program.length +
rd_clk_program.length + wr_data_program.length +
wr_resp_program.length;
tmp_program.origin = -1;
if (pio_can_add_program(pio0, &tmp_program)) {
g_pio = pio0;
} else if (pio_can_add_program(pio1, &tmp_program)) {
g_pio = pio1;
#if NUM_PIOS > 2
} else if (pio_can_add_program(pio2, &tmp_program)) {
g_pio = pio2;
#endif
} else {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_sm0 = pio_claim_unused_sm(g_pio, false);
if (g_sm0 < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_sm1 = pio_claim_unused_sm(g_pio, false);
if (g_sm0 < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_cmdRspOffset = pio_add_program(g_pio, &cmd_rsp_program);
if (g_cmdRspOffset < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
rd_data_patch_program(&tmp_program, patched_inst, g_clkPin);
g_rdDataOffset = pio_add_program(g_pio, &tmp_program);
if (g_rdDataOffset < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_rdClkOffset = pio_add_program(g_pio, &rd_clk_program);
if (g_rdClkOffset < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_wrDataOffset = pio_add_program(g_pio, &wr_data_program);
if (g_wrDataOffset < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
g_wrRespOffset = pio_add_program(g_pio, &wr_resp_program);
if (g_wrRespOffset < 0) {
sdError(PIO_ERROR_ADD_PROGRAM);
goto fail;
}
}
for (uint i = 0; i < 6U; i++) {
gpio_pull_up(pin[i]);
}
gpio_set_drive_strength(g_clkPin, GPIO_DRIVE_STRENGTH_8MA);
gpio_set_slew_rate(g_clkPin, GPIO_SLEW_RATE_FAST);
for (uint i = 0; i < 6U; i++) {
pio_gpio_init(g_pio, pin[i]);
}
g_pio->input_sync_bypass |=
(1 << g_clkPin) | (1 << g_cmdPin) | (0XF << g_dat0Pin);
pio_sm_set_consecutive_pindirs(g_pio, g_sm0, g_clkPin, 1, true);
pio_sm_set_consecutive_pindirs(g_pio, g_sm0, g_cmdPin, 1, true);
pio_sm_set_consecutive_pindirs(g_pio, g_sm0, g_dat0Pin, 4, false);
return true;
fail:
pioEnd();
return false;
}
//------------------------------------------------------------------------------
static bool cardCmd(CmdRsp_t cmd, uint32_t arg, void* rsp = nullptr) {
uint8_t buf[6];
uint nRsp = cmd.rsp == RSP_R0 ? 0 : cmd.rsp == RSP_R2 ? 17 : 6;
io_ro_8* rxFifo = reinterpret_cast<io_ro_8*>(&g_pio->rxf[g_sm0]);
io_wo_8* txFifo = reinterpret_cast<io_wo_8*>(&g_pio->txf[g_sm0]);
pio_sm_set_enabled(g_pio, g_sm1, false);
pio_sm_init(g_pio, g_sm0, g_cmdRspOffset, &g_cmdConfig);
pio_sm_exec(g_pio, g_sm0, pio_encode_set(pio_pindirs, 1));
*txFifo = 55;
pio_sm_exec(g_pio, g_sm0, pio_encode_out(pio_x, 8));
*txFifo = nRsp ? 8 * nRsp - 1 : 0;
pio_sm_exec(g_pio, g_sm0, pio_encode_out(pio_y, 8));
pio_sm_set_enabled(g_pio, g_sm0, true);
uint n = 0;
buf[n++] = (uint8_t)(cmd.idx | 0x40);
buf[n++] = (uint8_t)(arg >> 24U);
buf[n++] = (uint8_t)(arg >> 16U);
buf[n++] = (uint8_t)(arg >> 8U);
buf[n++] = (uint8_t)arg;
buf[n++] = CRC7(buf, 5);
*txFifo = 0XFF;
for (uint i = 0; i < n; i++) {
while (pio_sm_is_tx_fifo_full(g_pio, g_sm0)) {
}
*txFifo = buf[i];
}
Timeout timeout(SD_CMD_TIMEOUT);
if (!nRsp) {
uint32_t fdebug_tx_stall = 1u << (PIO_FDEBUG_TXSTALL_LSB + g_sm0);
g_pio->fdebug = fdebug_tx_stall;
while (!(g_pio->fdebug & fdebug_tx_stall)) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_CMD0);
goto fail;
}
}
goto done;
}
uint8_t rtn[20];
for (uint i = 0; i < nRsp; i++) {
while (pio_sm_is_rx_fifo_empty(g_pio, g_sm0)) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
rtn[i] = *rxFifo;
}
if (cmd.rsp == RSP_R3) {
if (rtn[0] != 0X3F || rtn[5] != 0XFF) {
sdError(SD_CARD_ERROR_ACMD41);
goto fail;
}
} else {
uint8_t crc;
if (cmd.rsp == RSP_R2) {
crc = CRC7(rtn + 1, nRsp - 2);
} else {
crc = CRC7(rtn, nRsp - 1);
}
if (rtn[nRsp - 1] != crc) {
#if USE_DEBUG_MODE
Serial.printf("CHK: %02X, CRC: %02X\n", rtn[nRsp - 1], crc);
for (uint i = 0; i < nRsp; i++) {
Serial.printf(" %02X", rtn[i]);
}
Serial.println();
#endif // USE_DEBUG_MODE
sdError(SD_CARD_ERROR_READ_CRC);
goto fail;
}
}
if (nRsp == 6) {
g_cardRsp = (rtn[1] << 24) | (rtn[2] << 16) | (rtn[3] << 8) | rtn[4];
if (rsp) {
*reinterpret_cast<uint32_t*>(rsp) = g_cardRsp;
}
} else if (rsp && nRsp == 17) {
memcpy(rsp, rtn + 1, 16);
}
done:
pio_sm_set_enabled(g_pio, g_sm0, false);
return true;
fail:
#if USE_DEBUG_MODE
Serial.printf("CMD%d failed\n", cmd.idx);
#endif // USE_DEBUG_MODE
pio_sm_set_enabled(g_pio, g_sm0, false);
return false;
}
//------------------------------------------------------------------------------
static bool cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg) {
return cardCmd(CMD55_R1, rca) && cardCmd(cmdRsp, arg);
}
//------------------------------------------------------------------------------
static bool __time_critical_func(readDat)(void* dst, uint n8) {
uint32_t buf[128];
uint n32 = n8 / 4;
uint nr = n32 + 2;
const uint mask = (1ul << g_sm0) | (1ul << g_sm1);
io_wo_8* txFifo = reinterpret_cast<io_wo_8*>(&g_pio->txf[g_sm1]);
pio_sm_init(g_pio, g_sm0, g_rdDataOffset, &g_rdDataConfig);
pio_sm_init(g_pio, g_sm1, g_rdClkOffset, &g_rdClkConfig);
pio_set_sm_mask_enabled(g_pio, mask, true);
uint nf = nr < DAT_FIFO_DEPTH ? nr : DAT_FIFO_DEPTH;
for (uint it = 0; it < nf; it++) {
*txFifo = 0XFF;
}
io_ro_32* rxFifo = reinterpret_cast<io_ro_32*>(&g_pio->rxf[g_sm0]);
uint32_t* dst32 = (uint)dst & 3 ? buf : reinterpret_cast<uint32_t*>(dst);
uint64_t crc = 0;
uint64_t chk = 0;
Timeout timeout(SD_READ_TIMEOUT);
uint ir = 0;
if (nf < nr) {
uint nb = nr - nf;
while (true) {
while (pio_sm_get_rx_fifo_level(g_pio, g_sm0) < 4) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
uint32_t tmp = *rxFifo;
*txFifo = 0XFF;
dst32[ir++] = __builtin_bswap32(tmp);
crc = crc16(crc, tmp);
tmp = *rxFifo;
*txFifo = 0XFF;
dst32[ir++] = __builtin_bswap32(tmp);
crc = crc16(crc, tmp);
if (ir == nb) {
break;
}
tmp = *rxFifo;
*txFifo = 0XFF;
dst32[ir++] = __builtin_bswap32(tmp);
crc = crc16(crc, tmp);
tmp = *rxFifo;
*txFifo = 0XFF;
dst32[ir++] = __builtin_bswap32(tmp);
crc = crc16(crc, tmp);
}
}
for (; ir < nr; ir++) {
while (pio_sm_is_rx_fifo_empty(g_pio, g_sm0)) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
uint32_t tmp = *rxFifo;
if (ir < n32) {
dst32[ir] = __builtin_bswap32(tmp);
crc = crc16(crc, tmp);
} else {
chk <<= 32;
chk |= tmp;
}
}
if (crc != chk) {
#if USE_DEBUG_MODE
Serial.printf("crc: %llX\r\nchk: %llX\r\n", crc, chk);
#endif // USE_DEBUG_MODE
sdError(SD_CARD_ERROR_READ_CRC);
goto fail;
}
pio_set_sm_mask_enabled(g_pio, mask, false);
if (dst32 == buf) {
memcpy(dst, buf, n8);
}
return true;
fail:
pio_set_sm_mask_enabled(g_pio, mask, false);
return false;
}
//------------------------------------------------------------------------------
static bool __time_critical_func(writeDat)(const uint8_t* src) {
const uint32_t* src32;
uint32_t buf[128];
if ((uint)src & 3) {
memcpy(buf, src, 512);
src32 = (const uint32_t*)buf;
} else {
src32 = (const uint32_t*)src;
}
uint32_t tmp;
io_wo_32* txFifo = reinterpret_cast<io_wo_32*>(&g_pio->txf[g_sm0]);
io_ro_32* rxFifo = reinterpret_cast<io_ro_32*>(&g_pio->rxf[g_sm1]);
uint8_t rsp;
uint mask = (1ul << g_sm0) | (1ul << g_sm1);
uint64_t crc = 0;
Timeout timeout(SD_WRITE_TIMEOUT);
while (!gpio_get(g_dat0Pin)) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
}
pio_sm_init(g_pio, g_sm0, g_wrDataOffset, &g_wrDataConfig);
pio_sm_init(g_pio, g_sm1, g_wrRespOffset, &g_wrRespConfig);
*txFifo = 1048; // 8 + 1024 + 16 + 1 - 1;
pio_sm_exec(g_pio, g_sm0, pio_encode_out(pio_x, 32));
pio_sm_exec(g_pio, g_sm0, pio_encode_set(pio_pindirs, 0XF));
*txFifo = 0xFFFFFFF0;
pio_set_sm_mask_enabled(g_pio, mask, true);
for (int i = 0; i < 128;) {
while (pio_sm_get_tx_fifo_level(g_pio, g_sm0) > 4) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_WRITE_FIFO);
goto fail;
}
}
tmp = __builtin_bswap32(src32[i++]);
crc = crc16(crc, tmp);
*txFifo = tmp;
tmp = __builtin_bswap32(src32[i++]);
crc = crc16(crc, tmp);
*txFifo = tmp;
tmp = __builtin_bswap32(src32[i++]);
crc = crc16(crc, tmp);
*txFifo = tmp;
tmp = __builtin_bswap32(src32[i++]);
crc = crc16(crc, tmp);
*txFifo = tmp;
}
while (pio_sm_get_tx_fifo_level(g_pio, g_sm0) > 5) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_WRITE_FIFO);
goto fail;
}
}
*txFifo = (uint32_t)(crc >> 32);
*txFifo = (uint32_t)crc;
*txFifo = 0xFFFFFFFF;
while (pio_sm_is_rx_fifo_empty(g_pio, g_sm1)) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_READ_FIFO);
goto fail;
}
}
rsp = *rxFifo;
if ((rsp & 0X1F) != 0b101) {
#if USE_DEBUG_MODE
Serial.printf("wr rsp: %02X\n", rsp);
#endif // USE_DEBUG_MODE
sdError(SD_CARD_ERROR_WRITE_DATA);
goto fail;
}
return true;
fail:
pio_set_sm_mask_enabled(g_pio, mask, false);
return false;
}
//==============================================================================
// add to SdioCard class int the future.
// SdioCard::SdioCard()
// SdioCard::~SdioCard()
//------------------------------------------------------------------------------
bool SdioCard::begin(SdioConfig sdioConfig) {
uint32_t arg;
m_curState = IDLE_STATE;
g_errorCode = SD_CARD_ERROR_NONE;
g_highCapacity = false;
g_initDone = false;
g_version2 = false;
g_clkDiv = PIO_CLK_DIV_INIT;
g_clkPin = sdioConfig.clkPin();
g_cmdPin = sdioConfig.cmdPin();
g_dat0Pin = sdioConfig.dat0Pin();
pioInit();
pioConfig(g_clkDiv);
#if USE_DEBUG_MODE == 2
Serial.println();
pioRegs(g_pio);
pioSmRegs(g_pio, g_sm0);
pioSmRegs(g_pio, g_sm1);
gpioStatus(g_clkPin);
gpioStatus(g_cmdPin);
while (Serial.read() >= 0) {
}
Serial.println("Logic Analyzer on");
while (!Serial.available()) {
}
#endif // USE_DEBUG_MODE
Timeout timeout(SD_INIT_TIMEOUT);
for (uint i = 0; i < CMD0_RETRIES; i++) {
if (!cardCmd(CMD0_R0, 0)) {
sdError(SD_CARD_ERROR_CMD0);
goto fail;
}
}
// Try several times for case of reset delay.
for (uint32_t i = 0; i < CMD8_RETRIES; i++) {
if (cardCmd(CMD8_R7, 0X1AA)) {
if (g_cardRsp != 0X1AA) {
sdError(SD_CARD_ERROR_CMD8);
goto fail;
}
g_version2 = true;
break;
}
g_errorCode = SD_CARD_ERROR_NONE;
}
arg = g_version2 ? 0X40300000 : 0x00300000;
while (true) {
if (!cardAcmd(0, ACMD41_R3, arg)) {
sdError(SD_CARD_ERROR_ACMD41);
goto fail;
}
if (g_cardRsp & 0x80000000) {
break;
}
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
g_ocr = g_cardRsp;
if (g_cardRsp & 0x40000000) {
// Is high capacity.
g_highCapacity = true;
}
if (!cardCmd(CMD2_R2, 0)) {
sdError(SD_CARD_ERROR_CMD2);
goto fail;
}
if (!cardCmd(CMD3_R6, 0)) {
sdError(SD_CARD_ERROR_CMD3);
goto fail;
}
g_rca = g_cardRsp & 0xFFFF0000;
if (!cardCmd(CMD9_R2, g_rca, &g_csd)) {
sdError(SD_CARD_ERROR_CMD9);
goto fail;
}
if (!cardCmd(CMD10_R2, g_rca, &g_cid)) {
sdError(SD_CARD_ERROR_CMD10);
goto fail;
}
if (!cardCmd(CMD7_R1, g_rca)) {
sdError(SD_CARD_ERROR_CMD7);
goto fail;
}
if (!cardAcmd(g_rca, ACMD6_R1, 2)) {
sdError(SD_CARD_ERROR_ACMD6);
goto fail;
}
if (!cardAcmd(g_rca, ACMD51_R1, 0) || !readDat(&g_scr, sizeof(g_scr))) {
sdError(SD_CARD_ERROR_ACMD51);
goto fail;
}
if (!cardAcmd(g_rca, ACMD13_R1, 0) || !readDat(&g_sds, sizeof(g_sds))) {
sdError(SD_CARD_ERROR_ACMD13);
goto fail;
}
#if HIGH_SPEED_MODE
// 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 (g_scr.sdSpec() > 0 && cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
// kHzSdClk = 50000;
Serial.println("High Speed Mode");
goto fail;
} else {
// kHzSdClk = 25000;
Serial.println("Default Speed Mode");
}
#endif // HIGH_SPEED_MODE
g_clkDiv = PIO_CLK_DIV_RUN;
pioConfig(g_clkDiv);
g_initDone = true;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::cardCMD6(uint32_t arg, uint8_t* status) {
if (!cardCmd(CMD6_R1, arg) || !readDat(status, 64)) {
sdError(SD_CARD_ERROR_CMD6);
goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
void SdioCard::end() { pioEnd(); }
//------------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
Timeout timeout(SD_ERASE_TIMEOUT);
if (!syncDevice()) {
SDIO_FAIL();
goto fail;
}
// check for single sector erase
if (!g_csd.eraseSingleBlock()) {
// erase size mask
uint8_t m = g_csd.eraseSize() - 1;
if ((firstSector & m) != 0 || ((lastSector + 1) & m) != 0) {
// error card can't erase specified area
sdError(SD_CARD_ERROR_ERASE_SINGLE_SECTOR);
goto fail;
}
}
if (!g_highCapacity) {
firstSector <<= 9;
lastSector <<= 9;
}
if (!cardCmd(CMD32_R1, firstSector)) {
sdError(SD_CARD_ERROR_CMD32);
goto fail;
}
if (!cardCmd(CMD33_R1, lastSector)) {
sdError(SD_CARD_ERROR_CMD33);
goto fail;
}
if (!cardCmd(CMD38_R1, 0)) {
sdError(SD_CARD_ERROR_CMD38);
goto fail;
}
while (isBusy()) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
uint8_t SdioCard::errorCode() const { return g_errorCode; }
//------------------------------------------------------------------------------
uint32_t SdioCard::errorData() const { return g_cardRsp; }
//------------------------------------------------------------------------------
uint32_t SdioCard::errorLine() const { return g_errorLine; }
//------------------------------------------------------------------------------
bool SdioCard::isBusy() {
return gpio_get(g_dat0Pin) ? false : !(status() & CARD_STATUS_READY_FOR_DATA);
}
//------------------------------------------------------------------------------
bool SdioCard::readSector(uint32_t sector, uint8_t* dst) {
if (m_curState != READ_STATE || sector != m_curSector) {
if (!syncDevice()) {
SDIO_FAIL();
goto fail;
}
if (!readStart(sector)) {
sdError(SD_CARD_ERROR_READ_START);
goto fail;
}
m_curSector = sector;
m_curState = READ_STATE;
}
if (!readData(dst)) {
SDIO_FAIL();
goto fail;
}
m_curSector++;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
for (size_t i = 0; i < ns; i++) {
if (!readSector(sector + i, dst + i * 512UL)) {
SDIO_FAIL();
goto fail;
}
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::readCID(cid_t* cid) {
memcpy(cid, &g_cid, sizeof(cid_t));
return true;
}
//------------------------------------------------------------------------------
bool SdioCard::readCSD(csd_t* csd) {
memcpy(csd, &g_csd, sizeof(csd_t));
return true;
}
//------------------------------------------------------------------------------
bool __time_critical_func(SdioCard::readData)(uint8_t* dst) {
return readDat(dst, 512);
}
//------------------------------------------------------------------------------
bool SdioCard::readOCR(uint32_t* ocr) {
*ocr = g_ocr;
return true;
}
//------------------------------------------------------------------------------
bool SdioCard::readSCR(scr_t* scr) {
memcpy(scr, &g_scr, sizeof(scr_t));
return true;
}
//------------------------------------------------------------------------------
bool SdioCard::readSDS(sds_t* sds) {
memcpy(sds, &g_sds, sizeof(sds_t));
return true;
}
//------------------------------------------------------------------------------
bool SdioCard::readStart(uint32_t sector) {
uint arg = g_highCapacity ? sector : 512 * sector;
if (!cardCmd(CMD18_R1, arg)) {
sdError(SD_CARD_ERROR_CMD18);
goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::readStop() { return syncDevice(); }
//------------------------------------------------------------------------------
uint32_t SdioCard::status() {
return cardCmd(CMD13_R1, g_rca) ? g_cardRsp : CARD_STATUS_ERROR;
}
//------------------------------------------------------------------------------
uint32_t SdioCard::sectorCount() {
csd_t csd;
return readCSD(&csd) ? csd.capacity() : 0;
}
//------------------------------------------------------------------------------
bool SdioCard::syncDevice() {
if (m_curState != IDLE_STATE) {
Timeout timeout(SD_INIT_TIMEOUT);
if (!cardCmd(CMD12_R1, 0)) {
sdError(SD_CARD_ERROR_CMD12);
goto fail;
}
while (isBusy()) {
if (timeout.timedOut()) {
sdError(SD_CARD_ERROR_CMD12);
goto fail;
}
}
m_curState = IDLE_STATE;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
uint8_t SdioCard::type() const {
return !g_initDone ? 0
: !g_version2 ? SD_CARD_TYPE_SD1
: !g_highCapacity ? SD_CARD_TYPE_SD2
: SD_CARD_TYPE_SDHC;
}
//------------------------------------------------------------------------------
bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
return writeSectors(sector, src, 1);
}
//------------------------------------------------------------------------------
bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
if (m_curState != WRITE_STATE || m_curSector != sector) {
if (!syncDevice()) {
sdError(SD_CARD_ERROR_CMD12);
goto fail;
}
if (!writeStart(sector)) {
sdError(SD_CARD_ERROR_WRITE_START);
goto fail;
}
m_curSector = sector;
m_curState = WRITE_STATE;
}
for (size_t i = 0; i < ns; i++, src += 512) {
if (!writeData(src)) {
sdError(SD_CARD_ERROR_WRITE_DATA);
goto fail;
}
}
m_curSector += ns;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::writeData(const uint8_t* src) { return writeDat(src); }
//------------------------------------------------------------------------------
bool SdioCard::writeStart(uint32_t sector) {
uint arg = g_highCapacity ? sector : 512 * sector;
if (!cardCmd(CMD25_R1, arg)) {
sdError(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdioCard::writeStop() { return syncDevice(); }
#endif // ARDUINO_ARCH_RP2040

View file

@ -0,0 +1,175 @@
; Copyright (c) 2011-2024 Bill Greiman
; This file is part of the SdFat library for SD memory cards.
;
; MIT License
;
; Permission is hereby granted, free of charge, to any person obtaining a
; copy of this software and associated documentation files (the "Software"),
; to deal in the Software without restriction, including without limitation
; the rights to use, copy, modify, merge, publish, distribute, sublicense,
; and/or sell copies of the Software, and to permit persons to whom the
; Software is furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included
; in all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
;
; Online assembler used to produce PioSdioCard.pio.h
; https://wokwi.com/tools/pioasm
.define public SDIO_IRQ 7
.program cmd_rsp
.side_set 1 opt
.wrap_target
cmd_begin:
send_cmd:
out pins, 1 side 0 [1]
jmp X-- send_cmd side 1 [1]
jmp !Y cmd_begin side 0 [1]
set pindirs, 0 side 1 [3]
wait_resp:
nop side 0 [3]
nop side 1 [2]
jmp PIN wait_resp
read_resp:
in pins, 1
push iffull block side 0 [2]
jmp Y-- read_resp side 1 [1]
.wrap
% c-sdk {
static inline pio_sm_config pio_cmd_rsp_program_config(uint offset, uint cmd_pin, uint clk_pin, float clk_div) {
pio_sm_config c = cmd_rsp_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_out_pins(&c, cmd_pin, 1);
sm_config_set_in_pins(&c, cmd_pin);
sm_config_set_set_pins(&c, cmd_pin, 1);
sm_config_set_jmp_pin(&c, cmd_pin);
sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
%}
.program rd_clk
.side_set 1 opt
wait_d0:
nop side 0 [3]
jmp PIN wait_d0 side 1 [3]
irq SDIO_IRQ
.wrap_target
out null, 1 side 0 [1] ; Clock stops when txFifo is empty
nop side 1 [1]
.wrap
% c-sdk {
static inline pio_sm_config pio_rd_clk_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) {
pio_sm_config c = rd_clk_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_in_pins(&c, d0_pin);
sm_config_set_jmp_pin(&c, d0_pin);
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
%}
.program rd_data
wait 1 irq SDIO_IRQ
.wrap_target
public wait0:
wait 0 gpio 0 ; See rd_data_patch_program for CLK pin
public wait1:
wait 1 gpio 0 ; See rd_data_patch_program for CLK pin
in pins, 4
.wrap
% c-sdk {
static inline void rd_data_patch_program(pio_program *prog, uint16_t* inst, uint clk_pin) {
*prog = rd_data_program;
prog->instructions = inst;
memcpy(inst, rd_data_program_instructions, sizeof(rd_data_program_instructions));
inst[rd_data_offset_wait0] = pio_encode_wait_gpio(0, clk_pin);
inst[rd_data_offset_wait1] = pio_encode_wait_gpio(1, clk_pin);
}
static inline pio_sm_config pio_rd_data_program_config(uint offset, uint data_pin, float clk_div) {
pio_sm_config c = rd_data_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
sm_config_set_in_pins(&c, data_pin);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
%}
; Data transmission program
;
; Before running this program, pindirs should be set as output
; and register X should be initialized with the number of nibbles
; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
;
; Words written to TX FIFO must be:
; - Word 0: start token 0xFFFFFFF0
; - Word 1-128: transmitted data (512 bytes)
; - Word 129-130: CRC checksum
; - Word 131: end token 0xFFFFFFFF
.program wr_data
.side_set 1 opt
; out X, 32
; set pindirs, 0XF
tx_loop:
out pins, 4 side 0 [1]
jmp X-- tx_loop side 1 [1]
irq SDIO_IRQ
.wrap_target
nop
.wrap
% c-sdk {
static inline pio_sm_config pio_wr_data_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) {
pio_sm_config c = wr_data_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_out_pins(&c, data_pin, 4);
sm_config_set_set_pins(&c, data_pin, 4);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
%}
.program wr_resp
.side_set 1 opt
wait 1 irq SDIO_IRQ
set pindirs, 0 [1]
.wrap_target
in pins, 1 side 1 [4]
push iffull noblock side 0 [4]
.wrap
% c-sdk {
static inline pio_sm_config pio_wr_resp_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) {
pio_sm_config c = wr_resp_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_in_pins(&c, data_pin);
sm_config_set_set_pins(&c, data_pin, 4);
sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
%}

View file

@ -0,0 +1,241 @@
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
#define SDIO_IRQ 7
// ------- //
// cmd_rsp //
// ------- //
#define cmd_rsp_wrap_target 0
#define cmd_rsp_wrap 9
static const uint16_t cmd_rsp_program_instructions[] = {
// .wrap_target
0x7101, // 0: out pins, 1 side 0 [1]
0x1940, // 1: jmp x--, 0 side 1 [1]
0x1160, // 2: jmp !y, 0 side 0 [1]
0xfb80, // 3: set pindirs, 0 side 1 [3]
0xb342, // 4: nop side 0 [3]
0xba42, // 5: nop side 1 [2]
0x00c4, // 6: jmp pin, 4
0x4001, // 7: in pins, 1
0x9260, // 8: push iffull block side 0 [2]
0x1987, // 9: jmp y--, 7 side 1 [1]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program cmd_rsp_program = {
.instructions = cmd_rsp_program_instructions,
.length = 10,
.origin = -1,
};
static inline pio_sm_config cmd_rsp_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + cmd_rsp_wrap_target, offset + cmd_rsp_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
static inline pio_sm_config pio_cmd_rsp_program_config(uint offset, uint cmd_pin, uint clk_pin, float clk_div) {
pio_sm_config c = cmd_rsp_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_out_pins(&c, cmd_pin, 1);
sm_config_set_in_pins(&c, cmd_pin);
sm_config_set_set_pins(&c, cmd_pin, 1);
sm_config_set_jmp_pin(&c, cmd_pin);
sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
#endif
// ------ //
// rd_clk //
// ------ //
#define rd_clk_wrap_target 3
#define rd_clk_wrap 4
static const uint16_t rd_clk_program_instructions[] = {
0xb342, // 0: nop side 0 [3]
0x1bc0, // 1: jmp pin, 0 side 1 [3]
0xc007, // 2: irq nowait 7
// .wrap_target
0x7161, // 3: out null, 1 side 0 [1]
0xb942, // 4: nop side 1 [1]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program rd_clk_program = {
.instructions = rd_clk_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config rd_clk_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + rd_clk_wrap_target, offset + rd_clk_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
static inline pio_sm_config pio_rd_clk_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) {
pio_sm_config c = rd_clk_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_in_pins(&c, d0_pin);
sm_config_set_jmp_pin(&c, d0_pin);
sm_config_set_out_shift(&c, false, true, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
#endif
// ------- //
// rd_data //
// ------- //
#define rd_data_wrap_target 1
#define rd_data_wrap 3
#define rd_data_offset_wait0 1u
#define rd_data_offset_wait1 2u
static const uint16_t rd_data_program_instructions[] = {
0x20c7, // 0: wait 1 irq, 7
// .wrap_target
0x2000, // 1: wait 0 gpio, 0
0x2080, // 2: wait 1 gpio, 0
0x4004, // 3: in pins, 4
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program rd_data_program = {
.instructions = rd_data_program_instructions,
.length = 4,
.origin = -1,
};
static inline pio_sm_config rd_data_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + rd_data_wrap_target, offset + rd_data_wrap);
return c;
}
static inline void rd_data_patch_program(pio_program *prog, uint16_t* inst, uint clk_pin) {
*prog = rd_data_program;
prog->instructions = inst;
memcpy(inst, rd_data_program_instructions, sizeof(rd_data_program_instructions));
inst[rd_data_offset_wait0] = pio_encode_wait_gpio(0, clk_pin);
inst[rd_data_offset_wait1] = pio_encode_wait_gpio(1, clk_pin);
}
static inline pio_sm_config pio_rd_data_program_config(uint offset, uint data_pin, float clk_div) {
pio_sm_config c = rd_data_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
sm_config_set_in_pins(&c, data_pin);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
#endif
// ------- //
// wr_data //
// ------- //
#define wr_data_wrap_target 3
#define wr_data_wrap 3
static const uint16_t wr_data_program_instructions[] = {
0x7104, // 0: out pins, 4 side 0 [1]
0x1940, // 1: jmp x--, 0 side 1 [1]
0xc007, // 2: irq nowait 7
// .wrap_target
0xa042, // 3: nop
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program wr_data_program = {
.instructions = wr_data_program_instructions,
.length = 4,
.origin = -1,
};
static inline pio_sm_config wr_data_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + wr_data_wrap_target, offset + wr_data_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
static inline pio_sm_config pio_wr_data_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) {
pio_sm_config c = wr_data_program_get_default_config(offset);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_out_pins(&c, data_pin, 4);
sm_config_set_set_pins(&c, data_pin, 4);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
#endif
// ------- //
// wr_resp //
// ------- //
#define wr_resp_wrap_target 2
#define wr_resp_wrap 3
static const uint16_t wr_resp_program_instructions[] = {
0x20c7, // 0: wait 1 irq, 7
0xe180, // 1: set pindirs, 0 [1]
// .wrap_target
0x5c01, // 2: in pins, 1 side 1 [4]
0x9440, // 3: push iffull noblock side 0 [4]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program wr_resp_program = {
.instructions = wr_resp_program_instructions,
.length = 4,
.origin = -1,
};
static inline pio_sm_config wr_resp_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + wr_resp_wrap_target, offset + wr_resp_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
static inline pio_sm_config pio_wr_resp_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) {
pio_sm_config c = wr_resp_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, clk_pin);
sm_config_set_in_pins(&c, data_pin);
sm_config_set_set_pins(&c, data_pin, 4);
sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_clkdiv(&c, clk_div);
return c;
}
#endif

View file

@ -0,0 +1,52 @@
/**
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
/**
* \class SdioConfig
* \brief SDIO card configuration.
*/
class SdioConfig {
public:
/**
* SdioConfig constructor.
* \param[in] clkPin gpio pin for SDIO CLK.
* \param[in] cmdPin gpio pin for SDIO CMD.
* \param[in] dat0Pin gpio start pin for SDIO DAT[4].
*/
SdioConfig(uint clkPin, uint cmdPin, uint dat0Pin)
: m_clkPin(clkPin), m_cmdPin(cmdPin), m_dat0Pin(dat0Pin) {}
/** \return gpio for SDIO CLK */
uint clkPin() { return m_clkPin; }
/** \return gpio for SDIO CMD */
uint cmdPin() { return m_cmdPin; }
/** \return gpio for SDIO DAT0 */
uint dat0Pin() { return m_dat0Pin; }
private:
SdioConfig() : m_clkPin(31u), m_cmdPin(31u), m_dat0Pin(31u) {}
const uint8_t m_clkPin;
const uint8_t m_cmdPin;
const uint8_t m_dat0Pin;
};

View file

@ -26,8 +26,7 @@
* \file
* \brief Top level include for SPI and SDIO cards.
*/
#ifndef SdCard_h
#define SdCard_h
#pragma once
#include "SdSpiCard.h"
#include "SdioCard.h"
#if HAS_SDIO_CLASS
@ -91,4 +90,3 @@ class SdCardFactory {
#endif // HAS_SDIO_CLASS
SdSpiCard m_spiCard;
};
#endif // SdCard_h

View file

@ -120,9 +120,9 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
#endif // CRC_CCITT
#endif // USE_SD_CRC
//==============================================================================
// SharedSpiCard member functions
// SdSpiCard member functions
//------------------------------------------------------------------------------
bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
bool SdSpiCard::begin(SdSpiConfig spiConfig) {
uint8_t cardType;
uint32_t arg;
Timeout timeout;
@ -213,6 +213,9 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
spiStop();
spiSetSckSpeed(spiConfig.maxSck);
m_type = cardType;
#if ENABLE_DEDICATED_SPI
m_dedicatedSpi = spiOptionDedicated(spiConfig.options);
#endif
return true;
fail:
@ -220,7 +223,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::cardCMD6(uint32_t arg, uint8_t* status) {
bool SdSpiCard::cardCMD6(uint32_t arg, uint8_t* status) {
if (cardCommand(CMD6, arg)) {
error(SD_CARD_ERROR_CMD6);
goto fail;
@ -237,7 +240,7 @@ fail:
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
if (!syncDevice()) {
return 0XFF;
}
@ -267,7 +270,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
spiSend(cmd | 0x40);
// send argument
uint8_t* pa = reinterpret_cast<uint8_t*>(&arg);
const uint8_t* pa = reinterpret_cast<uint8_t*>(&arg);
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}
@ -287,7 +290,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
return m_status;
}
//------------------------------------------------------------------------------
void SharedSpiCard::end() {
void SdSpiCard::end() {
if (m_beginCalled) {
syncDevice();
spiEnd();
@ -295,7 +298,7 @@ void SharedSpiCard::end() {
}
}
//------------------------------------------------------------------------------
bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
csd_t csd;
if (!readCSD(&csd)) {
goto fail;
@ -331,12 +334,12 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::eraseSingleSectorEnable() {
bool SdSpiCard::eraseSingleSectorEnable() {
csd_t csd;
return readCSD(&csd) ? csd.eraseSingleBlock() : false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::isBusy() {
bool SdSpiCard::isBusy() {
if (m_state == READ_STATE) {
return false;
}
@ -351,9 +354,9 @@ bool SharedSpiCard::isBusy() {
return rtn;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readData(uint8_t* dst) { return readData(dst, 512); }
bool SdSpiCard::readData(uint8_t* dst) { return readData(dst, 512); }
//------------------------------------------------------------------------------
bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
bool SdSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC
uint16_t crc;
#endif // USE_SD_CRC
@ -371,6 +374,8 @@ bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
goto fail;
}
// transfer data
// cppcheck wrong - Due can return non-zero.
// cppcheck-suppress knownConditionTrueFalse
if ((m_status = spiReceive(dst, count))) {
error(SD_CARD_ERROR_DMA);
goto fail;
@ -395,7 +400,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readOCR(uint32_t* ocr) {
bool SdSpiCard::readOCR(uint32_t* ocr) {
uint8_t* p = reinterpret_cast<uint8_t*>(ocr);
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
@ -417,7 +422,7 @@ fail:
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
bool SharedSpiCard::readRegister(uint8_t cmd, void* buf) {
bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
@ -434,7 +439,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSCR(scr_t* scr) {
bool SdSpiCard::readSCR(scr_t* scr) {
uint8_t* dst = reinterpret_cast<uint8_t*>(scr);
if (cardAcmd(ACMD51, 0)) {
error(SD_CARD_ERROR_ACMD51);
@ -451,7 +456,10 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
bool SdSpiCard::readSector(uint32_t sector, uint8_t* dst) {
#if ENABLE_DEDICATED_SPI
return readSectors(sector, dst, 1);
#else
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
@ -469,9 +477,25 @@ bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
fail:
spiStop();
return false;
#endif
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
bool SdSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
#if ENABLE_DEDICATED_SPI
if (sdState() != READ_STATE || sector != m_curSector) {
if (!readStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, dst += 512) {
if (!readData(dst)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : readStop();
#else
if (!readStart(sector)) {
goto fail;
}
@ -481,11 +505,12 @@ bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
}
}
return readStop();
#endif
fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readStart(uint32_t sector) {
bool SdSpiCard::readStart(uint32_t sector) {
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
}
@ -501,7 +526,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSDS(sds_t* sds) {
bool SdSpiCard::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()) {
@ -519,7 +544,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readStop() {
bool SdSpiCard::readStop() {
m_state = IDLE_STATE;
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
@ -533,12 +558,25 @@ fail:
return false;
}
//------------------------------------------------------------------------------
uint32_t SharedSpiCard::sectorCount() {
uint32_t SdSpiCard::sectorCount() {
csd_t csd;
return readCSD(&csd) ? csd.capacity() : 0;
}
//------------------------------------------------------------------------------
void SharedSpiCard::spiStart() {
bool SdSpiCard::setDedicatedSpi(bool value) {
#if ENABLE_DEDICATED_SPI
if (!syncDevice()) {
return false;
}
m_dedicatedSpi = value;
return true;
#else // ENABLE_DEDICATED_SPI
(void)value;
return false;
#endif // ENABLE_DEDICATED_SPI
}
//------------------------------------------------------------------------------
void SdSpiCard::spiStart() {
SPI_ASSERT_NOT_ACTIVE;
if (!m_spiActive) {
spiActivate();
@ -549,7 +587,7 @@ void SharedSpiCard::spiStart() {
}
}
//------------------------------------------------------------------------------
void SharedSpiCard::spiStop() {
void SdSpiCard::spiStop() {
SPI_ASSERT_ACTIVE;
if (m_spiActive) {
spiUnselect();
@ -560,7 +598,7 @@ void SharedSpiCard::spiStop() {
}
}
//------------------------------------------------------------------------------
bool SharedSpiCard::syncDevice() {
bool SdSpiCard::syncDevice() {
if (m_state == WRITE_STATE) {
return writeStop();
}
@ -570,7 +608,7 @@ bool SharedSpiCard::syncDevice() {
return true;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::waitReady(uint16_t ms) {
bool SdSpiCard::waitReady(uint16_t ms) {
Timeout timeout(ms);
while (spiReceive() != 0XFF) {
if (timeout.timedOut()) {
@ -580,7 +618,7 @@ bool SharedSpiCard::waitReady(uint16_t ms) {
return true;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeData(const uint8_t* src) {
bool SdSpiCard::writeData(const uint8_t* src) {
// wait for previous write to finish
if (!waitReady(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
@ -597,7 +635,7 @@ fail:
}
//------------------------------------------------------------------------------
// send one sector of data for write sector or write multiple sectors
bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
#if USE_SD_CRC
uint16_t crc = CRC_CCITT(src, 512);
#else // USE_SD_CRC
@ -620,7 +658,14 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
bool SdSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
#ifndef OLD_WAY_WRITE_SECTOR
#if ENABLE_DEDICATED_SPI
if (m_dedicatedSpi) {
return writeSectors(sector, src, 1);
}
#endif
#endif // OLD_WAY_WRITE_SECTOR
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
@ -654,8 +699,22 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
size_t ns) {
bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
#if ENABLE_DEDICATED_SPI
if (sdState() != WRITE_STATE || m_curSector != sector) {
if (!writeStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, src += 512) {
if (!writeData(src)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : writeStop();
#else
if (!writeStart(sector)) {
goto fail;
}
@ -665,13 +724,13 @@ bool SharedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
}
}
return writeStop();
#endif
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeStart(uint32_t sector) {
bool SdSpiCard::writeStart(uint32_t sector) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
@ -688,7 +747,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeStop() {
bool SdSpiCard::writeStop() {
if (!waitReady(SD_WRITE_TIMEOUT)) {
goto fail;
}
@ -702,69 +761,3 @@ fail:
spiStop();
return false;
}
//==============================================================================
bool DedicatedSpiCard::begin(SdSpiConfig spiConfig) {
if (!SharedSpiCard::begin(spiConfig)) {
return false;
}
m_dedicatedSpi = spiOptionDedicated(spiConfig.options);
return true;
}
//------------------------------------------------------------------------------
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) {
if (sdState() != READ_STATE || sector != m_curSector) {
if (!readStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, dst += 512) {
if (!readData(dst)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : readStop();
fail:
return false;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::setDedicatedSpi(bool value) {
if (!syncDevice()) {
return false;
}
m_dedicatedSpi = value;
return true;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
if (m_dedicatedSpi) {
return writeSectors(sector, src, 1);
}
return SharedSpiCard::writeSector(sector, src);
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
size_t ns) {
if (sdState() != WRITE_STATE || m_curSector != sector) {
if (!writeStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, src += 512) {
if (!writeData(src)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : writeStop();
fail:
return false;
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -26,8 +26,7 @@
* \file
* \brief Classes for SPI access to SD/SDHC cards.
*/
#ifndef SdSpiCard_h
#define SdSpiCard_h
#pragma once
#include <stddef.h>
#include "../SpiDriver/SdSpiDriver.h"
@ -43,8 +42,8 @@
if (!m_spiActive) { \
Serial.print(F("SPI_ASSERT_ACTIVE")); \
Serial.println(__LINE__); \
while (true) \
; \
while (true) { \
} \
} \
}
#define SPI_ASSERT_NOT_ACTIVE \
@ -52,8 +51,8 @@
if (m_spiActive) { \
Serial.print(F("SPI_ASSERT_NOT_ACTIVE")); \
Serial.println(__LINE__); \
while (true) \
; \
while (true) { \
} \
} \
}
#else // CHECK_SPI_ACTIVE
@ -64,15 +63,15 @@
#endif // CHECK_SPI_ACTIVE
//==============================================================================
/**
* \class SharedSpiCard
* \class SdSpiCard
* \brief Raw access to SD and SDHC flash memory cards via shared SPI port.
*/
#if HAS_SDIO_CLASS
class SharedSpiCard : public SdCardInterface {
class SdSpiCard : public SdCardInterface {
#elif USE_BLOCK_DEVICE_INTERFACE
class SharedSpiCard : public FsBlockDeviceInterface {
class SdSpiCard : public FsBlockDeviceInterface {
#else // HAS_SDIO_CLASS
class SharedSpiCard {
class SdSpiCard {
#endif // HAS_SDIO_CLASS
public:
/** SD is in idle state */
@ -81,8 +80,8 @@ class SharedSpiCard {
static const uint8_t READ_STATE = 1;
/** SD is in multi-sector write state. */
static const uint8_t WRITE_STATE = 2;
/** Construct an instance of SharedSpiCard. */
SharedSpiCard() { initSharedSpiCard(); }
/** Construct an instance of SdSpiCard. */
SdSpiCard() { initSharedSpiCard(); }
/** Initialize the SD card.
* \param[in] spiConfig SPI card configuration.
* \return true for success or false for failure.
@ -131,16 +130,24 @@ class SharedSpiCard {
uint8_t errorCode() const { return m_errorCode; }
/** \return error data for last error. */
uint32_t errorData() const { return m_status; }
/** \return false for shared class. */
/** \return false for shared class. */
#if ENABLE_DEDICATED_SPI
bool hasDedicatedSpi() { return true; }
#else
bool hasDedicatedSpi() { return false; }
#endif
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return false, can't be in dedicated state. */
/** \return true if in dedicated SPI state. */
#if ENABLE_DEDICATED_SPI
bool isDedicatedSpi() { return m_dedicatedSpi; }
#else // ENABLE_DEDICATED_SPI
bool isDedicatedSpi() { return false; }
#endif // ENABLE_DEDICATED_SPI
/** \return true if card is on SPI bus. */
bool isSpi() { return true; }
/**
@ -198,7 +205,6 @@ class SharedSpiCard {
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/** Start a read multiple sector sequence.
*
* \param[in] sector Address of first sector in sequence.
@ -228,19 +234,12 @@ class SharedSpiCard {
* or zero if an error occurs.
*/
uint32_t sectorCount();
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Use sectorCount(). cardSize() will be removed in the future.
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Set SPI sharing state
* \param[in] value desired state.
* \return false for shared card
* \return true for success.
*/
bool setDedicatedSpi(bool value) {
(void)value;
return false;
}
/** end a mult-sector transfer.
bool setDedicatedSpi(bool value);
/** end a multi-sector transfer.
*
* \return true for success or false for failure.
*/
@ -362,6 +361,10 @@ class SharedSpiCard {
m_status = 0;
m_type = 0;
}
#if ENABLE_DEDICATED_SPI
uint32_t m_curSector = 0;
bool m_dedicatedSpi = false;
#endif // ENABLE_DEDICATED_SPI
bool m_beginCalled;
SdCsPin_t m_csPin;
uint8_t m_errorCode;
@ -370,74 +373,3 @@ class SharedSpiCard {
uint8_t m_status;
uint8_t m_type;
};
//==============================================================================
/**
* \class DedicatedSpiCard
* \brief Raw access to SD and SDHC flash memory cards via dedicate SPI port.
*/
class DedicatedSpiCard : public SharedSpiCard {
public:
/** Construct an instance of DedicatedSpiCard. */
DedicatedSpiCard() = default;
/** Initialize the SD card.
* \param[in] spiConfig SPI card configuration.
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig);
/** \return true, can be in dedicaded state. */
bool hasDedicatedSpi() { return true; }
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi() { return m_dedicatedSpi; }
/**
* Read a 512 byte sector from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSector(uint32_t sector, uint8_t* dst);
/**
* Read multiple 512 byte sectors from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[in] ns Number of sectors to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value);
/**
* Write a 512 byte sector to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSector(uint32_t sector, const uint8_t* src);
/**
* Write multiple 512 byte sectors to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] ns Number of sectors to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
private:
uint32_t m_curSector = 0;
bool m_dedicatedSpi = false;
};
//==============================================================================
#if ENABLE_DEDICATED_SPI
/** typedef for dedicated SPI. */
typedef DedicatedSpiCard SdSpiCard;
#else
/** typedef for shared SPI. */
typedef SharedSpiCard SdSpiCard;
#endif
#endif // SdSpiCard_h

View file

@ -26,34 +26,18 @@
* \file
* \brief Classes for SDIO cards.
*/
#ifndef SdioCard_h
#define SdioCard_h
#pragma once
#include "../common/SysCall.h"
#include "SdCardInterface.h"
/** Use programmed I/O with FIFO. */
#define FIFO_SDIO 0
/** Use programmed I/O with DMA. */
#define DMA_SDIO 1
#ifdef SDIO_CONFIG_INCLUDE
#include SDIO_CONFIG_INCLUDE
#else // SDIO_CONFIG_INCLUDE
/**
* \class SdioConfig
* \brief SDIO card configuration.
* \brief Empty SDIO card configuration.
*/
class SdioConfig {
public:
SdioConfig() {}
/**
* SdioConfig constructor.
* \param[in] opt SDIO options.
*/
explicit SdioConfig(uint8_t opt) : m_options(opt) {}
/** \return SDIO card options. */
uint8_t options() { return m_options; }
/** \return true if DMA_SDIO. */
bool useDma() { return m_options & DMA_SDIO; }
private:
uint8_t m_options = FIFO_SDIO;
};
class SdioConfig {};
#endif // SDIO_CONFIG_INCLUDE
//------------------------------------------------------------------------------
/**
* \class SdioCard
@ -62,10 +46,10 @@ class SdioConfig {
class SdioCard : public SdCardInterface {
public:
/** Initialize the SD card.
* \param[in] sdioConfig SDIO card configuration.
* \param[in] config SDIO card configuration.
* \return true for success or false for failure.
*/
bool begin(SdioConfig sdioConfig);
bool begin(SdioConfig config);
/** CMD6 Switch mode: Check Function Set Function.
* \param[in] arg CMD6 argument.
* \param[out] status return status data.
@ -76,7 +60,7 @@ class SdioCard : public SdCardInterface {
/** Disable an SDIO card.
* not implemented.
*/
void end() {}
void end();
#ifndef DOXYGEN_SHOULD_SKIP_THIS
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
@ -253,7 +237,5 @@ class SdioCard : public SdCardInterface {
static const uint8_t READ_STATE = 1;
static const uint8_t WRITE_STATE = 2;
uint32_t m_curSector;
SdioConfig m_sdioConfig;
uint8_t m_curState = IDLE_STATE;
};
#endif // SdioCard_h

View file

@ -0,0 +1 @@
exclude_files=TeensySdioDefs.h

View file

@ -23,10 +23,9 @@
* DEALINGS IN THE SOFTWARE.
*/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
#include "SdioTeensy.h"
#include "SdCardInfo.h"
#include "SdioCard.h"
#include "../SdCardInfo.h"
#include "../SdioCard.h"
#include "TeensySdioDefs.h"
//==============================================================================
// limit of K66 due to errata KINETIS_K_0N65N.
const uint32_t MAX_BLKCNT = 0XFFFF;
@ -194,9 +193,10 @@ static bool waitTimeout(bool (*fcn)());
//------------------------------------------------------------------------------
static bool (*m_busyFcn)() = 0;
static bool m_initDone = false;
static bool m_version2;
static bool m_highCapacity;
static bool m_version2 = false;
static bool m_highCapacity = false;
static bool m_transferActive = false;
static bool m_useDma = false;
static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
static uint32_t m_errorLine = 0;
static uint32_t m_rca;
@ -689,7 +689,7 @@ static bool waitTransferComplete() {
bool SdioCard::begin(SdioConfig sdioConfig) {
uint32_t kHzSdClk;
uint32_t arg;
m_sdioConfig = sdioConfig;
m_useDma = sdioConfig.useDma();
m_curState = IDLE_STATE;
m_initDone = false;
m_errorCode = SD_CARD_ERROR_NONE;
@ -777,7 +777,7 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
}
if ((status[16] & 0XF) == 1) {
kHzSdClk = 50000;
} else {
} else {
return sdError(SD_CARD_ERROR_CMD6);
}
}
@ -812,6 +812,10 @@ bool SdioCard::cardCMD6(uint32_t arg, uint8_t* status) {
return true;
}
//------------------------------------------------------------------------------
void SdioCard::end() {
// to do
}
//------------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
if (m_curState != IDLE_STATE && !syncDevice()) {
return false;
@ -851,7 +855,7 @@ uint32_t SdioCard::errorData() const { return m_irqstat; }
uint32_t SdioCard::errorLine() const { return m_errorLine; }
//------------------------------------------------------------------------------
bool SdioCard::isBusy() {
if (m_sdioConfig.useDma()) {
if (m_useDma) {
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
} else {
if (m_transferActive) {
@ -932,7 +936,7 @@ bool SdioCard::readSDS(sds_t* sds) {
}
//------------------------------------------------------------------------------
bool SdioCard::readSector(uint32_t sector, uint8_t* dst) {
if (m_sdioConfig.useDma()) {
if (m_useDma) {
uint8_t aligned[512];
uint8_t* ptr = (uint32_t)dst & 3 ? aligned : dst;
@ -973,7 +977,7 @@ bool SdioCard::readSector(uint32_t sector, uint8_t* dst) {
}
//------------------------------------------------------------------------------
bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n) {
if (m_sdioConfig.useDma()) {
if (m_useDma) {
if ((uint32_t)dst & 3) {
for (size_t i = 0; i < n; i++, sector++, dst += 512) {
if (!readSector(sector, dst)) {
@ -1081,7 +1085,7 @@ bool SdioCard::writeData(const uint8_t* src) {
}
//------------------------------------------------------------------------------
bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
if (m_sdioConfig.useDma()) {
if (m_useDma) {
uint8_t* ptr;
uint8_t aligned[512];
if (3 & (uint32_t)src) {
@ -1124,7 +1128,7 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
}
//------------------------------------------------------------------------------
bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n) {
if (m_sdioConfig.useDma()) {
if (m_useDma) {
uint8_t* ptr = const_cast<uint8_t*>(src);
if (3 & (uint32_t)ptr) {
for (size_t i = 0; i < n; i++, sector++, ptr += 512) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,12 +22,28 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ExFatConfig_h
#define ExFatConfig_h
#include "SdFatConfig.h"
#pragma once
/** Use programmed I/O with FIFO. */
#define FIFO_SDIO 0
/** Use programmed I/O with DMA. */
#define DMA_SDIO 1
/**
* \class SdioConfig
* \brief SDIO card configuration.
*/
class SdioConfig {
public:
SdioConfig() {}
/**
* SdioConfig constructor.
* \param[in] opt SDIO options.
*/
explicit SdioConfig(uint8_t opt) : m_options(opt) {}
/** \return SDIO card options. */
uint8_t options() { return m_options; }
/** \return true if DMA_SDIO. */
bool useDma() { return m_options & DMA_SDIO; }
#ifndef EXFAT_READ_ONLY
#define EXFAT_READ_ONLY 0
#endif // EXFAT_READ_ONLY
#endif // ExFatConfig_h
private:
uint8_t m_options = FIFO_SDIO;
};

View file

@ -2,16 +2,14 @@
* \file
* \brief Definitions for Teensy HDHC.
*/
#ifndef SdioTeensy_h
#define SdioTeensy_h
#pragma once
// From Paul's SD.h driver.
#if defined(__IMXRT1062__)
#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_SET(x, m, s) (((uint32_t)(((uint32_t)(x) & m) << s)))
#define SDHC_BLKATTR_BLKSIZE_MASK \
MAKE_REG_MASK( \
@ -467,7 +465,8 @@
// 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_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)
@ -515,16 +514,15 @@
#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(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_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(n) (((n) & 0x7) << 3)
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7) << 3)
#endif // defined(__IMXRT1062__)
#endif // SdioTeensy_h

View file

@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdFat_h
#define SdFat_h
#pragma once
/**
* \file
* \brief main SdFs include file.
@ -38,9 +37,9 @@
#endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------
/** SdFat version for cpp use. */
#define SD_FAT_VERSION 20203
#define SD_FAT_VERSION 20300
/** SdFat version as string. */
#define SD_FAT_VERSION_STR "2.2.3"
#define SD_FAT_VERSION_STR "2.3.0"
//==============================================================================
/**
* \class SdBase
@ -463,7 +462,7 @@ typedef FsFile File;
#endif // HAS_INCLUDE_FS_H
/**
* \class SdFile
* \brief FAT16/FAT32 file with Print.
* \brief File with Print.
*/
class SdFile : public PrintFile<SdBaseFile> {
public:
@ -506,4 +505,3 @@ class SdFile : public PrintFile<SdBaseFile> {
/** Cancel the date/time callback function. */
static void dateTimeCallbackCancel() { FsDateTime::clearCallback(); }
};
#endif // SdFat_h

View file

@ -26,13 +26,13 @@
* \file
* \brief configuration definitions
*/
#ifndef SdFatConfig_h
#define SdFatConfig_h
#pragma once
#include <stdint.h>
#ifdef __AVR__
#include <avr/io.h>
#endif // __AVR__
//
// #include "SdFatDebugConfig.h"
// To try UTF-8 encoded filenames.
// #define USE_UTF8_LONG_NAMES 1
//
@ -87,13 +87,18 @@
#define DESTRUCTOR_CLOSES_FILE 0
#endif // DESTRUCTOR_CLOSES_FILE
//------------------------------------------------------------------------------
/** For Debug - must be one */
/** For Debug - must be one on Arduino */
#ifndef ENABLE_ARDUINO_FEATURES
#define ENABLE_ARDUINO_FEATURES 1
/** For Debug - must be one */
#endif //ENABLE_ARDUINO_FEATURES
/** For Debug - must be one on Arduino */
#ifndef ENABLE_ARDUINO_SERIAL
#define ENABLE_ARDUINO_SERIAL 1
/** For Debug - must be one */
#endif //ENABLE_ARDUINO_SERIAL
/** For Debug - must be one on Arduino */
#ifndef ENABLE_ARDUINO_STRING
#define ENABLE_ARDUINO_STRING 1
#endif //ENABLE_ARDUINO_STRING
//------------------------------------------------------------------------------
#if ENABLE_ARDUINO_FEATURES
#include "Arduino.h"
@ -183,7 +188,11 @@
* receive and transfer(buf, rxTmp, count) for send. Try this with STM32.
*/
#ifndef USE_SPI_ARRAY_TRANSFER
#if defined(ARDUINO_ARCH_RP2040)
#define USE_SPI_ARRAY_TRANSFER 2
#else // defined(ARDUINO_ARCH_RP2040)
#define USE_SPI_ARRAY_TRANSFER 0
#endif // defined(ARDUINO_ARCH_RP2040)
#endif // USE_SPI_ARRAY_TRANSFER
//------------------------------------------------------------------------------
/**
@ -435,6 +444,12 @@ typedef uint8_t SdCsPin_t;
#endif // RAMEND
//------------------------------------------------------------------------------
/** Enable SDIO driver if available. */
#if defined(ARDUINO_ARCH_RP2040)
#define HAS_RP2040_SDIO 1
#define HAS_SDIO_CLASS 1
#define SDIO_CONFIG_INCLUDE "Rp2040Sdio/Rp2040SdioConfig.h"
#endif // defined(ARDUINO_ARCH_RP2040)
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Pseudo pin select for SDIO.
#ifndef BUILTIN_SDCARD
@ -448,10 +463,11 @@ typedef uint8_t SdCsPin_t;
#define SDCARD_SCK_PIN 60
#define SDCARD_SS_PIN 62
#endif // SDCARD_SPI
#define HAS_SDIO_CLASS 1
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__IMXRT1062__)
#if defined(__IMXRT1062__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define HAS_SDIO_CLASS 1
#define HAS_TEENSY_SDIO 1
#define SDIO_CONFIG_INCLUDE "TeensySdio/TeensySdioConfig.h"
#endif // defined(__IMXRT1062__)
//------------------------------------------------------------------------------
/**
@ -460,9 +476,8 @@ typedef uint8_t SdCsPin_t;
#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(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID) || \
(defined(CORE_TEENSY) && defined(__arm__))
#define SD_HAS_CUSTOM_SPI 1
#else // SD_HAS_CUSTOM_SPI
@ -474,5 +489,3 @@ typedef uint8_t SdCsPin_t;
/** Default is no SDIO. */
#define HAS_SDIO_CLASS 0
#endif // HAS_SDIO_CLASS
#endif // SdFatConfig_h

15
src/SdFatDebugConfig.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
// File to be included in SdFatConfig.h for debug definitions.
#if defined(ARDUINO_ADAFRUIT_METRO_RP2040)
#define RP_CLK_GPIO 18
#define RP_CMD_GPIO 19
#define RP_DAT0_GPIO 20 // DAT1: GPIO21, DAT2: GPIO22, DAT3: GPIO23.
#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_2)
#define RP_CLK_GPIO 16
#define RP_CMD_GPIO 17
#define RP_DAT0_GPIO 18 // DAT1: GPIO19, DAT2: GPIO20, DAT3: GPIO21.
#elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2350_HSTX)
#define RP_CLK_GPIO 11
#define RP_CMD_GPIO 10
#define RP_DAT0_GPIO 22 // DAT1: GPIO23, DAT2: GPIO24, DAT3: GPIO25.
#endif // defined(ARDUINO_ADAFRUIT_METRO_RP2040))

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -28,13 +28,15 @@
//------------------------------------------------------------------------------
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 ? HIGH : LOW);
}
#elif SD_CHIP_SELECT_MODE == 1
//------------------------------------------------------------------------------
__attribute__((weak)) void sdCsInit(SdCsPin_t pin) { pinMode(pin, OUTPUT); }
//------------------------------------------------------------------------------
__attribute__((weak)) void sdCsWrite(SdCsPin_t pin, bool level) {
digitalWrite(pin, level);
digitalWrite(pin, level ? HIGH : LOW);
}
#endif // SD_CHIP_SELECT_MODE == 0
#endif // ENABLE_ARDUINO_FEATURES

View file

@ -1,86 +0,0 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiDriver.h"
#if defined(SD_USE_CUSTOM_SPI) && (defined(ESP8266) || defined(ESP32))
#define ESP_UNALIGN_OK 1
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::activate() { m_spi->beginTransaction(m_spiSettings); }
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
if (spiConfig.spiPort) {
m_spi = spiConfig.spiPort;
#if defined(SDCARD_SPI) && defined(SDCARD_SS_PIN)
} else if (spiConfig.csPin == SDCARD_SS_PIN) {
m_spi = &SDCARD_SPI;
#endif // defined(SDCARD_SPI) && defined(SDCARD_SS_PIN)
} else {
m_spi = &SPI;
}
m_spi->begin();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); }
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() { m_spi->end(); }
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); }
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
#if ESP_UNALIGN_OK
m_spi->transferBytes(nullptr, buf, count);
#else // ESP_UNALIGN_OK
// Adjust to 32-bit alignment.
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && count) {
*buf++ = m_spi->transfer(0xff);
count--;
}
// Do multiple of four byte transfers.
size_t n4 = 4 * (count / 4);
if (n4) {
m_spi->transferBytes(nullptr, buf, n4);
}
// Transfer up to three remaining bytes.
for (buf += n4, count -= n4; count; count--) {
*buf++ = m_spi->transfer(0xff);
}
#endif // ESP_UNALIGN_OK
return 0;
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::send(uint8_t data) { m_spi->transfer(data); }
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
#if !ESP_UNALIGN_OK
// Adjust to 32-bit alignment.
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && count) {
SPI.transfer(*buf++);
count--;
}
#endif // #if ESP_UNALIGN_OK
m_spi->transferBytes(const_cast<uint8_t*>(buf), nullptr, count);
}
#endif // defined(SD_USE_CUSTOM_SPI) && (defined(ESP8266) || defined(ESP32))

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ArduinoFiles_h
#define ArduinoFiles_h
#pragma once
#include "SysCall.h"
//------------------------------------------------------------------------------
/** Arduino SD.h style flag for open for read. */
@ -44,13 +43,29 @@ class PrintFile : public print_t, public BaseFile {
public:
using BaseFile::clearWriteError;
using BaseFile::getWriteError;
using BaseFile::read;
using BaseFile::write;
/** Ensure that any bytes written to the file are saved to the SD card. */
#if defined(ARDUINO_SAM_DUE) && !defined(ARDUINO_API_VERSION)
void flush() { BaseFile::sync(); }
#else
void flush() override { BaseFile::sync(); }
#endif
/** Write a single byte.
* \param[in] b byte to write.
* \return one for success.
*/
size_t write(uint8_t b) { return BaseFile::write(&b, 1); }
size_t write(uint8_t b) override { return BaseFile::write(&b, 1); }
/** Write data to an open file.
* \param[in] buffer pointer
* \param[in] size of the buffer
* \return number of bytes actually written
*/
size_t write(const uint8_t* buffer, size_t size) override {
return BaseFile::write(buffer, size);
}
};
//------------------------------------------------------------------------------
/**
@ -64,35 +79,39 @@ class StreamFile : public stream_t, public BaseFile {
using BaseFile::getWriteError;
using BaseFile::read;
using BaseFile::write;
StreamFile() {}
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
*/
int available() { return BaseFile::available(); }
int available() override { return BaseFile::available(); }
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() { BaseFile::sync(); }
void flush() override { BaseFile::sync(); }
/** This function reports if the current file is a directory or not.
* \return true if the file is a directory.
*/
bool isDirectory() { return BaseFile::isDir(); }
#ifndef DOXYGEN_SHOULD_SKIP_THIS
char* __attribute__((error("use getName(name, size)"))) name();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek() { return BaseFile::peek(); }
int peek() override { return BaseFile::peek(); }
/** \return the current file position. */
PosType position() { return BaseFile::curPosition(); }
/** Read the next byte from a file.
*
* \return For success return the next byte in the file as an int.
* If an error occurs or end of file is reached return -1.
*/
int read() { return BaseFile::read(); }
int read() override { return BaseFile::read(); }
/** Rewind a file if it is a directory */
void rewindDirectory() {
if (BaseFile::isDir()) {
@ -114,7 +133,7 @@ class StreamFile : public stream_t, public BaseFile {
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) { return BaseFile::write(b); }
size_t write(uint8_t b) override { return BaseFile::write(b); }
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
@ -127,8 +146,7 @@ class StreamFile : public stream_t, public BaseFile {
* \return For success write() returns the number of bytes written, always
* \a size.
*/
size_t write(const uint8_t* buffer, size_t size) {
size_t write(const uint8_t* buffer, size_t size) override {
return BaseFile::write(buffer, size);
}
};
#endif // ArduinoFiles_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef DebugMacros_h
#define DebugMacros_h
#pragma once
#include "SysCall.h"
// 0 - disable, 1 - fail, halt 2 - fail, halt, warn
@ -78,4 +77,3 @@ __attribute__((unused)) static void dbgWarn(uint16_t line) {
#define DBG_WARN_MACRO
#define DBG_WARN_IF(b)
#endif // USE_DBG_MACROS > 1
#endif // DebugMacros_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -174,7 +174,8 @@ char* fmtBase10(char* str, uint16_t n) {
// n = n + (n >> 16); // no code for 16-bit n
n = n >> 3;
uint8_t r = t - (((n << 2) + n) << 1);
if (r > 9) {
// cppcheck wrong.
if (r > 9) { // cppcheck-suppress knownConditionTrueFalse
n++;
r -= 10;
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsCache_h
#define FsCache_h
#pragma once
/**
* \file
* \brief Common cache code for exFAT and FAT.
@ -54,7 +53,7 @@ class FsCache {
CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
//----------------------------------------------------------------------------
/** Cobstructor. */
FsCache() { init(nullptr); }
FsCache() { init(nullptr); } // cppcheck-suppress uninitMemberVar
/** \return Cache buffer address. */
uint8_t* cacheBuffer() { return m_buffer; }
/**
@ -173,4 +172,3 @@ class FsCache {
uint32_t m_mirrorOffset;
uint8_t m_buffer[512];
};
#endif // FsCache_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsDateTime_h
#define FsDateTime_h
#pragma once
#include <stdint.h>
#include "CompileDateTime.h"
@ -188,4 +187,3 @@ size_t fsPrintDateTime(print_t* pr, uint32_t dateTime, uint8_t s100, int8_t tz);
size_t fsPrintTime(print_t* pr, uint16_t time);
size_t fsPrintTime(print_t* pr, uint16_t time, uint8_t sec100);
size_t fsPrintTimeZone(print_t* pr, int8_t tz);
#endif // FsDateTime_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FsUtf_h
#define FsUtf_h
#pragma once
/**
* \file
* \brief Unicode Transformation Format functions.
@ -98,4 +97,3 @@ const char* mbToCp(const char* str, const char* end, uint32_t* rtn);
const char* mbToU16(const char* str, const char* end, uint16_t* hs,
uint16_t* ls);
} // namespace FsUtf
#endif // FsUtf_h

91
src/common/PrintBasic.cpp Normal file
View file

@ -0,0 +1,91 @@
/**
* Copyright (c) 2011-2020 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "PrintBasic.h"
#if ENABLE_ARDUINO_FEATURES == 0
#include <math.h>
size_t PrintBasic::print(long n, uint8_t base) {
if (n < 0 && base == 10) {
return print('-') + printNum(-n, base);
}
return printNum(n, base);
}
size_t PrintBasic::printNum(unsigned long n, uint8_t base) {
const uint8_t DIM = 8 * sizeof(long);
char buf[DIM];
char *str = &buf[DIM];
if (base < 2) return 0;
do {
char c = n % base;
n /= base;
*--str = c + (c < 10 ? '0' : 'A' - 10);
} while (n);
return write(str, &buf[DIM] - str);
}
size_t PrintBasic::printDouble(double n, uint8_t prec) {
// Max printable 32-bit floating point number. AVR uses 32-bit double.
const double maxfp = static_cast<double>(0XFFFFFF00UL);
size_t rtn = 0;
if (isnan(n)) {
return write("NaN");
}
if (n < 0) {
n = -n;
rtn += print('-');
}
if (isinf(n)) {
return rtn + write("Inf");
}
if (n > maxfp) {
return rtn + write("Ovf");
}
double round = 0.5;
for (uint8_t i = 0; i < prec; ++i) {
round *= 0.1;
}
n += round;
uint32_t whole = (uint32_t)n;
rtn += print(whole);
if (prec) {
rtn += print('.');
double fraction = n - static_cast<double>(whole);
for (uint8_t i = 0; i < prec; i++) {
fraction *= 10.0;
uint8_t digit = fraction;
rtn += print(digit);
fraction -= digit;
}
}
return rtn;
}
#endif // ENABLE_ARDUINO_FEATURES == 0

148
src/common/PrintBasic.h Normal file
View file

@ -0,0 +1,148 @@
/**
* Copyright (c) 2011-2020 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef PrintBasic_h
#define PrintBasic_h
/**
* \file
* \brief Stream/Print like replacement for non-Arduino systems.
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "../SdFatConfig.h"
#ifndef F
#if defined(__AVR__)
#include <avr/pgmspace.h>
class __FlashStringHelper;
#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
#undef BIN
#endif // BIN
#define BIN 2
#define OCT 8
#define DEC 10
#define HEX 16
class PrintBasic {
public:
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); }
size_t print(const __FlashStringHelper *str) {
#ifdef __AVR__
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));
#endif // __AVR__
}
size_t println(const __FlashStringHelper *str) {
#ifdef __AVR__
return print(str) + println();
#else // __AVR__
return println(reinterpret_cast<const char *>(str));
#endif // __AVR__
}
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(unsigned int n, uint8_t base = 10) {
return print((unsigned long)n, base);
}
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 println(double n, uint8_t prec = 2) {
return print(n, prec) + println();
}
size_t println(signed char n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(unsigned char n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(int n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(unsigned int n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(long n, uint8_t base = 10) {
return print(n, base) + println();
}
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)); }
virtual size_t write(uint8_t b) = 0;
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;
}
return i;
}
size_t write(const char *buffer, size_t size) {
return write(reinterpret_cast<const uint8_t *>(buffer), size);
}
protected:
void setWriteError(int err = 1) { m_error = err; }
private:
size_t printDouble(double n, uint8_t prec);
size_t printNum(unsigned long n, uint8_t base);
int m_error;
};
//------------------------------------------------------------------------------
class StreamBasic : public PrintBasic {
public:
virtual int available() = 0;
virtual int peek() = 0;
virtual int read() = 0;
};
#endif // PrintBasic_h

15
src/fmt_src.bat Normal file
View file

@ -0,0 +1,15 @@
clang-format --style=Google -i *.cpp *.h
rem clang-format --style=Google -i DigitalIO/*.h
rem clang-format --style=Google -i DigitalIO/boards/*.h
clang-format --style=Google -i common/*.cpp common/*.h
clang-format --style=Google -i ExFatLib/*.cpp ExFatLib/*.h
clang-format --style=Google -i FatLib/*.cpp FatLib/*.h
clang-format --style=Google -i FsLib/*.cpp FsLib/*.h
clang-format --style=Google -i iostream/*.cpp iostream/*.h
clang-format --style=Google -i SdCard/*.cpp SdCard/*.h
rem clang-format --style=Google -i SdCard/Rp2040Sdio/DbgLogMsg.h SdCard/Rp2040Sdio/PioDbgInfo.h
rem clang-format --style=Google -i SdCard/Rp2040Sdio/PioSdioCard.h SdCard/Rp2040Sdio/Rp2040SdioConfig.h
clang-format --style=Google -i SdCard/Rp2040Sdio/*.cpp SdCard/Rp2040Sdio/*.h
clang-format --style=Google -i SdCard/TeensySdio/*.cpp SdCard/TeensySdio/*.h
clang-format --style=Google -i SpiDriver/*.cpp SpiDriver/*.h
pause

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -243,6 +243,8 @@ size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
return write(ptr, count * size) < 0 ? EOF : count;
}
//------------------------------------------------------------------------------
// allow shadow of rewind() in StreamBaseFile,
// cppcheck-suppress duplInheritedMember
int StdioStream::write(const void* buf, size_t count) {
const uint8_t* src = static_cast<const uint8_t*>(buf);
size_t todo = count;
@ -282,7 +284,7 @@ size_t StdioStream::print(const __FlashStringHelper* str) {
//------------------------------------------------------------------------------
int StdioStream::printDec(float value, uint8_t prec) {
char buf[24];
char* ptr = fmtDouble(buf + sizeof(buf), value, prec, false);
const char* ptr = fmtDouble(buf + sizeof(buf), value, prec, false);
return write(ptr, buf + sizeof(buf) - ptr);
}
//------------------------------------------------------------------------------
@ -314,7 +316,7 @@ int StdioStream::printDec(int16_t n) {
//------------------------------------------------------------------------------
int StdioStream::printDec(uint16_t n) {
char buf[5];
char* ptr = fmtBase10(buf + sizeof(buf), n);
const char* ptr = fmtBase10(buf + sizeof(buf), n);
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
}
@ -334,18 +336,20 @@ int StdioStream::printDec(int32_t n) {
//------------------------------------------------------------------------------
int StdioStream::printDec(uint32_t n) {
char buf[10];
char* ptr = fmtBase10(buf + sizeof(buf), n);
const char* ptr = fmtBase10(buf + sizeof(buf), n);
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
}
//------------------------------------------------------------------------------
int StdioStream::printHex(uint32_t n) {
char buf[8];
char* ptr = fmtHex(buf + sizeof(buf), n);
const char* ptr = fmtHex(buf + sizeof(buf), n);
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
}
//------------------------------------------------------------------------------
// allow shadow of rewind() in StreamBaseFile,
// cppcheck-suppress duplInheritedMember
bool StdioStream::rewind() {
if (m_status & S_SWR) {
if (!flushBuf()) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef StdioStream_h
#define StdioStream_h
#pragma once
/**
* \file
* \brief StdioStream class
@ -112,6 +111,7 @@ const uint8_t UNGETC_BUF_SIZE = 2;
*/
class StdioStream : private StreamBaseFile {
public:
using StreamBaseFile::printField;
/** Constructor
*
*/
@ -545,38 +545,6 @@ class StdioStream : private StreamBaseFile {
*/
int printDec(float value, uint8_t prec);
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(double value, char term, uint8_t prec = 2) {
return printField(static_cast<float>(value), term, prec) > 0;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(float value, char term, uint8_t prec = 2) {
int rtn = printDec(value, prec);
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \return The number of bytes written or -1 if an error occurs.
*/
template <typename T>
int printField(T value, char term) {
int rtn = printDec(value);
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
}
//----------------------------------------------------------------------------
/** Print HEX
* \param[in] n number to be printed as HEX.
*
@ -640,5 +608,3 @@ class StdioStream : private StreamBaseFile {
uint8_t m_r = 0;
uint8_t m_w = 0;
};
//------------------------------------------------------------------------------
#endif // StdioStream_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -150,9 +150,3 @@ bool StreamBaseClass::seekoff(off_type off, seekdir way) {
}
return seekpos(pos);
}
//------------------------------------------------------------------------------
int StreamBaseClass::write(const void* buf, size_t n) {
return StreamBaseFile::write(buf, n);
}
//------------------------------------------------------------------------------
void StreamBaseClass::write(char c) { StreamBaseFile::write(&c, 1); }

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -26,8 +26,7 @@
* \file
* \brief iostreams for files.
*/
#ifndef fstream_h
#define fstream_h
#pragma once
#include "iostream.h"
//------------------------------------------------------------------------------
/**
@ -36,12 +35,15 @@
*/
class StreamBaseClass : protected StreamBaseFile, virtual public ios {
protected:
void clearWriteError() { StreamBaseFile::clearWriteError(); }
using StreamBaseFile::clearWriteError;
using StreamBaseFile::getWriteError;
using StreamBaseFile::write;
/* Internal do not use
* \return mode
*/
int16_t getch();
bool getWriteError() { return StreamBaseFile::getWriteError(); }
void open(const char* path, ios::openmode mode);
/** Internal do not use
* \return mode
@ -58,8 +60,6 @@ class StreamBaseClass : protected StreamBaseFile, virtual public ios {
* \param[in] mode
*/
void setmode(ios::openmode mode) { m_mode = mode; }
int write(const void* buf, size_t n);
void write(char c);
private:
ios::openmode m_mode;
@ -72,6 +72,7 @@ class StreamBaseClass : protected StreamBaseFile, virtual public ios {
class fstream : public iostream, StreamBaseClass {
public:
using iostream::peek;
using StreamBaseClass::close;
fstream() {}
/** Constructor with open
* \param[in] path file to open
@ -86,14 +87,10 @@ class fstream : public iostream, StreamBaseClass {
/** Clear state and writeError
* \param[in] state new state for stream
*/
void clear(iostate state = goodbit) {
void clear(iostate state = goodbit) override {
ios::clear(state);
StreamBaseClass::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() { StreamBaseClass::close(); }
/** Open a fstream
* \param[in] path path to open
* \param[in] mode open mode
@ -127,29 +124,29 @@ class fstream : public iostream, StreamBaseClass {
/** Internal - do not use
* \return
*/
int16_t getch() { return StreamBaseClass::getch(); }
int16_t getch() override { return StreamBaseClass::getch(); }
/** Internal - do not use
* \param[out] pos
*/
void getpos(pos_t* pos) { StreamBaseFile::fgetpos(pos); }
void getpos(pos_t* pos) override { StreamBaseFile::fgetpos(pos); }
/** Internal - do not use
* \param[in] c
*/
void putch(char c) { StreamBaseClass::putch(c); }
void putch(char c) override { StreamBaseClass::putch(c); }
/** Internal - do not use
* \param[in] str
*/
void putstr(const char* str) { StreamBaseClass::putstr(str); }
void putstr(const char* str) override { StreamBaseClass::putstr(str); }
/** Internal - do not use
* \param[in] pos
*/
bool seekoff(off_type off, seekdir way) {
bool seekoff(off_type off, seekdir way) override {
return StreamBaseClass::seekoff(off, way);
}
bool seekpos(pos_type pos) { return StreamBaseClass::seekpos(pos); }
void setpos(pos_t* pos) { StreamBaseFile::fsetpos(pos); }
bool sync() { return StreamBaseClass::sync(); }
pos_type tellpos() { return StreamBaseFile::curPosition(); }
bool seekpos(pos_type pos) override { return StreamBaseClass::seekpos(pos); }
void setpos(const pos_t* pos) { StreamBaseFile::fsetpos(pos); }
bool sync() override { return StreamBaseClass::sync(); }
pos_type tellpos() override { return StreamBaseFile::curPosition(); }
/// @endcond
};
//==============================================================================
@ -160,6 +157,7 @@ class fstream : public iostream, StreamBaseClass {
class ifstream : public istream, StreamBaseClass {
public:
using istream::peek;
using StreamBaseClass::close;
ifstream() {}
/** Constructor with open
* \param[in] path file to open
@ -169,10 +167,6 @@ class ifstream : public istream, StreamBaseClass {
#if DESTRUCTOR_CLOSES_FILE
~ifstream() {}
#endif // DESTRUCTOR_CLOSES_FILE
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() { StreamBaseClass::close(); }
/** \return True if stream is open else false. */
bool is_open() { return StreamBaseFile::isOpen(); }
/** Open an ifstream
@ -213,6 +207,7 @@ class ifstream : public istream, StreamBaseClass {
*/
class ofstream : public ostream, StreamBaseClass {
public:
using StreamBaseClass::close;
ofstream() {}
/** Constructor with open
* \param[in] path file to open
@ -225,14 +220,10 @@ class ofstream : public ostream, StreamBaseClass {
/** Clear state and writeError
* \param[in] state new state for stream
*/
void clear(iostate state = goodbit) {
void clear(iostate state = goodbit) override {
ios::clear(state);
StreamBaseClass::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() { StreamBaseClass::close(); }
/** Open an ofstream
* \param[in] path file to open
* \param[in] mode open mode
@ -265,4 +256,3 @@ class ofstream : public ostream, StreamBaseClass {
pos_type tellpos() override { return StreamBaseFile::curPosition(); }
/// @endcond
};
#endif // fstream_h

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -22,8 +22,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ios_h
#define ios_h
#pragma once
#include "../FsLib/FsLib.h"
/**
* \file
@ -412,7 +411,7 @@ class ios : public ios_base {
*
* \param[in] state The flags you want to set after clearing all flags.
**/
void clear(iostate state = goodbit) { m_iostate = state; }
virtual void clear(iostate state = goodbit) { m_iostate = state; }
/** Set iostate bits.
*
* \param[in] state Bitts to set.
@ -422,4 +421,3 @@ class ios : public ios_base {
private:
iostate m_iostate = 0;
};
#endif // ios_h