Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2020-06-15 21:28:31 +0300
committerDavid Crocker <dcrocker@eschertech.com>2020-06-15 21:28:31 +0300
commitcec9ec68435afecbd88acf068bcffc40d4e051bc (patch)
treea8b13cd300af0071b8de1bb7c01612b3ebad8be1 /src/Libraries
parent9210008cafead2e5b9c12802861994d0826fa384 (diff)
Moved sd_mmc library here from CoreNG
Diffstat (limited to 'src/Libraries')
-rw-r--r--src/Libraries/Fatfs/diskio.cpp4
-rw-r--r--src/Libraries/sd_mmc/conf_sd_mmc.h105
-rw-r--r--src/Libraries/sd_mmc/ctrl_access.c98
-rw-r--r--src/Libraries/sd_mmc/ctrl_access.h171
-rw-r--r--src/Libraries/sd_mmc/sd_mmc.c2131
-rw-r--r--src/Libraries/sd_mmc/sd_mmc.h317
-rw-r--r--src/Libraries/sd_mmc/sd_mmc_mem.c138
-rw-r--r--src/Libraries/sd_mmc/sd_mmc_mem.h127
-rw-r--r--src/Libraries/sd_mmc/sd_mmc_protocol.h1012
-rw-r--r--src/Libraries/sd_mmc/sd_mmc_spi.c629
-rw-r--r--src/Libraries/sd_mmc/sd_mmc_spi.h249
11 files changed, 4979 insertions, 2 deletions
diff --git a/src/Libraries/Fatfs/diskio.cpp b/src/Libraries/Fatfs/diskio.cpp
index f3d19c40..4ab7860a 100644
--- a/src/Libraries/Fatfs/diskio.cpp
+++ b/src/Libraries/Fatfs/diskio.cpp
@@ -44,8 +44,8 @@
#include "compiler.h"
#include "diskio.h"
-#include "ctrl_access.h"
-#include "conf_sd_mmc.h"
+#include <Libraries/sd_mmc/ctrl_access.h>
+#include <Libraries/sd_mmc/conf_sd_mmc.h>
#include "RepRapFirmware.h"
#include "RepRap.h"
diff --git a/src/Libraries/sd_mmc/conf_sd_mmc.h b/src/Libraries/sd_mmc/conf_sd_mmc.h
new file mode 100644
index 00000000..86bfd6a8
--- /dev/null
+++ b/src/Libraries/sd_mmc/conf_sd_mmc.h
@@ -0,0 +1,105 @@
+/**
+ * \file
+ *
+ * \brief SD/MMC stack configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef CONF_SD_MMC_H_INCLUDED
+#define CONF_SD_MMC_H_INCLUDED
+
+// Define this to enable the SPI mode instead of Multimedia Card interface mode
+//#define SD_MMC_SPI_MODE
+
+// Define this to enable the SDIO support
+//#define SDIO_SUPPORT_ENABLE
+
+// Define this to enable the debug trace to the current standard output (stdio)
+//#define SD_MMC_DEBUG
+
+/*! \name board MCI SD/MMC slot template definition
+ *
+ * The GPIO and MCI/HSMCI connections of the SD/MMC Connector must be added
+ * in board.h file.
+ */
+
+// SD card configuration for Duet and Duet WiFi
+#define SD_MMC_ENABLE
+
+#if defined(__RADDS__)
+
+#define SD_MMC_HSMCI_MEM_CNT 0 // Number of HSMCI card slots supported
+#define SD_MMC_SPI_MEM_CNT 2 // Number of SPI card slots supported
+
+#define SD_MMC_SPI_MAX_CLOCK (4000000) // Max 4MHz clock for SPI cards, to allow a reasonable cable length
+
+#define SD_MMC_WP_DETECT_VALUE false
+
+#elif defined(__ALLIGATOR__)
+
+#define SD_MMC_HSMCI_MEM_CNT 0 // Number of HSMCI card slots supported
+#define SD_MMC_SPI_MEM_CNT 1 // Number of SPI card slots supported
+
+#define SD_MMC_SPI_MAX_CLOCK (20000000) // Max 20MHz clock for onboard SPI cards
+
+#define SD_MMC_WP_DETECT_VALUE false
+
+
+#else
+
+#define CONF_BOARD_SD_MMC_HSMCI 1 // Enable HSMCI
+#define SD_MMC_HSMCI_MEM_CNT 1 // Number of HSMCI card slots supported
+#define SD_MMC_HSMCI_SLOT_0_SIZE 4 // HSMCI bus width
+#define SD_MMC_SPI_MEM_CNT 1 // Number of SPI card slots supported
+
+#define SD_MMC_SPI_MAX_CLOCK (4000000) // Max 4MHz clock for SPI cards, to allow a reasonable cable length
+
+#define SD_MMC_WP_DETECT_VALUE false
+
+#endif
+
+#define SD_MMC_MEM_CNT (SD_MMC_HSMCI_MEM_CNT + SD_MMC_SPI_MEM_CNT)
+
+#define ACCESS_MEM_TO_RAM_ENABLED
+
+#endif /* CONF_SD_MMC_H_INCLUDED */
+
diff --git a/src/Libraries/sd_mmc/ctrl_access.c b/src/Libraries/sd_mmc/ctrl_access.c
new file mode 100644
index 00000000..e6940388
--- /dev/null
+++ b/src/Libraries/sd_mmc/ctrl_access.c
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ *
+ * \file
+ *
+ * \brief Abstraction layer for memory interfaces.
+ *
+ * This module contains the interfaces:
+ * - MEM <-> USB;
+ * - MEM <-> RAM;
+ * - MEM <-> MEM.
+ *
+ * This module may be configured and expanded to support the following features:
+ * - write-protected globals;
+ * - password-protected data;
+ * - specific features;
+ * - etc.
+ *
+ * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ ******************************************************************************/
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+
+//_____ I N C L U D E S ____________________________________________________
+
+#include "compiler.h"
+#include "ctrl_access.h"
+#include "sd_mmc_mem.h"
+
+
+Ctrl_status mem_test_unit_ready(uint8_t lun)
+{
+ return (lun < MAX_LUN) ? sd_mmc_test_unit_ready(lun) : CTRL_FAIL;
+}
+
+Ctrl_status mem_read_capacity(uint8_t lun, uint32_t *u32_nb_sector)
+{
+ return (lun < MAX_LUN) ? sd_mmc_read_capacity(lun, u32_nb_sector) : CTRL_FAIL;
+}
+
+uint8_t mem_sector_size(uint8_t lun)
+{
+ return 1;
+}
+
+bool mem_wr_protect(uint8_t lun)
+{
+ return (lun < MAX_LUN) ? sd_mmc_wr_protect(lun) : true;
+}
+
+Ctrl_status memory_2_ram(uint8_t lun, uint32_t addr, void *ram, uint32_t numBlocks)
+{
+ return (lun < MAX_LUN) ? sd_mmc_mem_2_ram(lun, addr, ram, numBlocks) : CTRL_FAIL;
+}
+
+Ctrl_status ram_2_memory(uint8_t lun, uint32_t addr, const void *ram, uint32_t numBlocks)
+{
+ return (lun < MAX_LUN) ? sd_mmc_ram_2_mem(lun, addr, ram, numBlocks) : CTRL_FAIL;
+}
+
+
+//! @}
diff --git a/src/Libraries/sd_mmc/ctrl_access.h b/src/Libraries/sd_mmc/ctrl_access.h
new file mode 100644
index 00000000..ac49bb97
--- /dev/null
+++ b/src/Libraries/sd_mmc/ctrl_access.h
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ *
+ * \file
+ *
+ * \brief Abstraction layer for memory interfaces.
+ *
+ * This module contains the interfaces:
+ * - MEM <-> USB;
+ * - MEM <-> RAM;
+ * - MEM <-> MEM.
+ *
+ * This module may be configured and expanded to support the following features:
+ * - write-protected globals;
+ * - password-protected data;
+ * - specific features;
+ * - etc.
+ *
+ * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ ******************************************************************************/
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+
+#ifndef _CTRL_ACCESS_H_
+#define _CTRL_ACCESS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup group_common_services_storage_ctrl_access Memory Control Access
+ *
+ * Common abstraction layer for memory interfaces. It provides interfaces between:
+ * Memory and USB, Memory and RAM, Memory and Memory. Common API for XMEGA and UC3.
+ *
+ * \{
+ */
+
+#include "compiler.h"
+
+#ifndef SECTOR_SIZE
+# define SECTOR_SIZE 512
+#endif
+
+//! Status returned by CTRL_ACCESS interfaces.
+typedef enum
+{
+ CTRL_GOOD = 0, //!< Success, memory ready.
+ CTRL_FAIL = 1, //!< An error occurred.
+ CTRL_NO_PRESENT = 2, //!< Memory unplugged.
+ CTRL_BUSY = 3 //!< Memory not initialized or changed.
+} Ctrl_status;
+
+#define MAX_LUN 2
+
+/*! \name Control Interface
+ */
+//! @{
+
+/*! \brief Tests the memory state and initializes the memory if required.
+ *
+ * The TEST UNIT READY SCSI primary command allows an application client to poll
+ * a LUN until it is ready without having to allocate memory for returned data.
+ *
+ * This command may be used to check the media status of LUNs with removable
+ * media.
+ *
+ * \param lun Logical Unit Number.
+ *
+ * \return Status.
+ */
+extern Ctrl_status mem_test_unit_ready(uint8_t lun) noexcept;
+
+/*! \brief Returns the address of the last valid sector (512 bytes) in the
+ * memory.
+ *
+ * \param lun Logical Unit Number.
+ * \param u32_nb_sector Pointer to the address of the last valid sector.
+ *
+ * \return Status.
+ */
+extern Ctrl_status mem_read_capacity(uint8_t lun, uint32_t *u32_nb_sector) noexcept;
+
+/*! \brief Returns the size of the physical sector.
+ *
+ * \param lun Logical Unit Number.
+ *
+ * \return Sector size (unit: 512 bytes).
+ */
+extern uint8_t mem_sector_size(uint8_t lun) noexcept;
+
+/*! \brief Returns the write-protection state of the memory.
+ *
+ * \param lun Logical Unit Number.
+ *
+ * \return \c true if the memory is write-protected, else \c false.
+ *
+ * \note Only used by removable memories with hardware-specific write
+ * protection.
+ */
+extern bool mem_wr_protect(uint8_t lun) noexcept;
+
+/*! \brief Copies 1 data sector from the memory to RAM.
+ *
+ * \param lun Logical Unit Number.
+ * \param addr Address of first memory sector to read.
+ * \param ram Pointer to RAM buffer to write.
+ *
+ * \return Status.
+ */
+extern Ctrl_status memory_2_ram(uint8_t lun, uint32_t addr, void *ram, uint32_t numBlocks) noexcept;
+
+/*! \brief Copies 1 data sector from RAM to the memory.
+ *
+ * \param lun Logical Unit Number.
+ * \param addr Address of first memory sector to write.
+ * \param ram Pointer to RAM buffer to read.
+ *
+ * \return Status.
+ */
+extern Ctrl_status ram_2_memory(uint8_t lun, uint32_t addr, const void *ram, uint32_t numBlocks) noexcept;
+
+//! @}
+
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _CTRL_ACCESS_H_
diff --git a/src/Libraries/sd_mmc/sd_mmc.c b/src/Libraries/sd_mmc/sd_mmc.c
new file mode 100644
index 00000000..c3db16ef
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc.c
@@ -0,0 +1,2131 @@
+/**
+ * \file
+ *
+ * \brief Common SD/MMC stack
+ *
+ * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "Core.h"
+#include <string.h>
+#include "sd_mmc_protocol.h"
+#include "sd_mmc.h"
+#include "conf_sd_mmc.h"
+
+#include "Core.h" // for digitalRead() and pinMode()
+
+#ifdef FREERTOS_USED
+#include "FreeRTOS.h"
+#include "task.h"
+#include "portmacro.h"
+#include "projdefs.h"
+#endif
+
+/**
+ * \ingroup sd_mmc_stack
+ * \defgroup sd_mmc_stack_internal Implementation of SD/MMC/SDIO Stack
+ * @{
+ */
+
+// Enable debug information for SD/MMC module
+#ifdef SD_MMC_DEBUG
+extern void debugPrintf(const char* fmt, ...);
+# define sd_mmc_debug(...) debugPrintf(__VA_ARGS__)
+#else
+# define sd_mmc_debug(...)
+#endif
+
+#ifndef SD_MMC_HSMCI_MEM_CNT
+# error SD_MMC_HSMCI_MEM_CNT not defined
+#endif
+#ifndef SD_MMC_SPI_MEM_CNT
+# error SD_MMC_SPI_MEM_CNT not defined
+#endif
+
+typedef void (*driverIdleFunc_t)(uint32_t, uint32_t);
+
+struct DriverInterface
+{
+ void (*select_device)(uint8_t slot, uint32_t clock, uint8_t bus_width, bool high_speed);
+ void (*deselect_device)(uint8_t slot);
+ uint8_t (*get_bus_width)(uint8_t slot);
+ bool (*is_high_speed_capable)(void);
+ void (*send_clock)(void);
+ bool (*send_cmd)(sdmmc_cmd_def_t cmd, uint32_t arg);
+ uint32_t (*get_response)(void);
+ void (*get_response_128)(uint8_t* response);
+ bool (*adtc_start)(sdmmc_cmd_def_t cmd, uint32_t arg, uint16_t block_size, uint16_t nb_block, bool access_block);
+ bool (*adtc_stop)(sdmmc_cmd_def_t cmd, uint32_t arg);
+ bool (*read_word)(uint32_t* value);
+ bool (*write_word)(uint32_t value);
+ bool (*start_read_blocks)(void *dest, uint16_t nb_block);
+ bool (*wait_end_of_read_blocks)(void);
+ bool (*start_write_blocks)(const void *src, uint16_t nb_block);
+ bool (*wait_end_of_write_blocks)(void);
+#if 1 //dc42
+ uint32_t (*getInterfaceSpeed)(void);
+#endif
+ driverIdleFunc_t (*set_idle_func)(driverIdleFunc_t);
+ bool is_spi; // true if the interface is SPI, false if it is HSMCI
+};
+
+#if (SD_MMC_HSMCI_MEM_CNT != 0)
+
+# ifdef __SAME54P20A__
+
+# include <hal_mci_sync.h>
+
+static const struct DriverInterface hsmciInterface = {
+ .select_device = mci_sync_select_device,
+ .deselect_device = mci_sync_deselect_device,
+ .get_bus_width = mci_sync_get_bus_width,
+ .is_high_speed_capable = mci_sync_is_high_speed_capable,
+ .send_clock = mci_sync_send_clock,
+ .send_cmd = mci_sync_send_cmd,
+ .get_response = mci_sync_get_response,
+ .get_response_128 = mci_sync_get_response_128,
+ .adtc_start = mci_sync_adtc_start,
+ .adtc_stop = mci_sync_send_cmd, // adtc_stop aliased to send_cmd as in the ASF original
+ .read_word = mci_sync_read_word,
+ .write_word = mci_sync_write_word,
+ .start_read_blocks = mci_sync_start_read_blocks,
+ .wait_end_of_read_blocks = mci_sync_wait_end_of_read_blocks,
+ .start_write_blocks = mci_sync_start_write_blocks,
+ .wait_end_of_write_blocks = mci_sync_wait_end_of_write_blocks,
+#if 1 //dc42
+ .getInterfaceSpeed = mci_sync_get_speed,
+#endif
+ .set_idle_func = mci_sync_set_idle_func,
+ .is_spi = false
+};
+
+# else
+
+# include <hsmci/hsmci.h>
+
+static const struct DriverInterface hsmciInterface = {
+ .select_device = hsmci_select_device,
+ .deselect_device = hsmci_deselect_device,
+ .get_bus_width = hsmci_get_bus_width,
+ .is_high_speed_capable = hsmci_is_high_speed_capable,
+ .send_clock = hsmci_send_clock,
+ .send_cmd = hsmci_send_cmd,
+ .get_response = hsmci_get_response,
+ .get_response_128 = hsmci_get_response_128,
+ .adtc_start = hsmci_adtc_start,
+ .adtc_stop = hsmci_send_cmd, // adtc_stop aliased to send_cmd as in the ASF original
+ .read_word = hsmci_read_word,
+ .write_word = hsmci_write_word,
+ .start_read_blocks = hsmci_start_read_blocks,
+ .wait_end_of_read_blocks = hsmci_wait_end_of_read_blocks,
+ .start_write_blocks = hsmci_start_write_blocks,
+ .wait_end_of_write_blocks = hsmci_wait_end_of_write_blocks,
+#if 1 //dc42
+ .getInterfaceSpeed = hsmci_get_speed,
+#endif
+ .set_idle_func = hsmci_set_idle_func,
+ .is_spi = false
+};
+
+# endif
+
+#endif
+
+#if (SD_MMC_SPI_MEM_CNT != 0)
+# include "sd_mmc_spi.h"
+
+static const struct DriverInterface spiInterface = {
+ .select_device = sd_mmc_spi_select_device,
+ .deselect_device = sd_mmc_spi_deselect_device,
+ .get_bus_width = sd_mmc_spi_get_bus_width,
+ .is_high_speed_capable = sd_mmc_spi_is_high_speed_capable,
+ .send_clock = sd_mmc_spi_send_clock,
+ .send_cmd = sd_mmc_spi_send_cmd,
+ .get_response = sd_mmc_spi_get_response,
+ .get_response_128 = sd_mmc_spi_get_response_128,
+ .adtc_start = sd_mmc_spi_adtc_start,
+ .adtc_stop = sd_mmc_spi_send_cmd, // adtc_stop aliased to send_cmd as in the ASF original
+ .read_word = sd_mmc_spi_read_word,
+ .write_word = sd_mmc_spi_write_word,
+ .start_read_blocks = sd_mmc_spi_start_read_blocks,
+ .wait_end_of_read_blocks = sd_mmc_spi_wait_end_of_read_blocks,
+ .start_write_blocks = sd_mmc_spi_start_write_blocks,
+ .wait_end_of_write_blocks = sd_mmc_spi_wait_end_of_write_blocks,
+#if 1 //dc42
+ .getInterfaceSpeed = spi_mmc_get_speed,
+#endif
+ .set_idle_func = sd_mmc_spi_set_idle_func,
+ .is_spi = true
+};
+#endif
+
+#ifdef SDIO_SUPPORT_ENABLE
+# define IS_SDIO() (sd_mmc_card->type & CARD_TYPE_SDIO)
+#else
+# define IS_SDIO() false
+#endif
+
+//! This SD MMC stack supports only the high voltage
+#define SD_MMC_VOLTAGE_SUPPORT \
+ (OCR_VDD_27_28 | OCR_VDD_28_29 | \
+ OCR_VDD_29_30 | OCR_VDD_30_31 | \
+ OCR_VDD_31_32 | OCR_VDD_32_33)
+
+//! SD/MMC card states
+enum card_state {
+ SD_MMC_CARD_STATE_READY = 0, //!< Ready to use
+ SD_MMC_CARD_STATE_DEBOUNCE = 1, //!< Debounce ongoing
+ SD_MMC_CARD_STATE_INIT = 2, //!< Initialization ongoing
+ SD_MMC_CARD_STATE_UNUSABLE = 3, //!< Unusable card
+ SD_MMC_CARD_STATE_NO_CARD = 4, //!< No SD/MMC card inserted
+};
+
+//! SD/MMC card information structure
+struct sd_mmc_card {
+ const struct DriverInterface *iface; // Pointer to driver interface functions
+ uint32_t clock; //!< Card access clock
+ uint32_t capacity; //!< Card capacity in KBytes
+#if 0 // dc42
+ Pin cd_gpio; //!< Card detect pin number, or -1 if none present
+#endif
+ Pin wp_gpio; //!< Card write protection pin number, or -1 if none present
+ uint16_t rca; //!< Relative card address
+ enum card_state state; //!< Card state
+ card_type_t type; //!< Card type
+ card_version_t version; //!< Card version
+ uint8_t slot; // Slot number within the driver
+ uint8_t bus_width; //!< Number of DATA lines on bus (MCI only)
+ uint8_t csd[CSD_REG_BSIZE]; //!< CSD register
+ uint8_t high_speed; //!< High speed card (1)
+};
+
+//! SD/MMC card list
+static struct sd_mmc_card sd_mmc_cards[SD_MMC_MEM_CNT];
+
+//! Index of current slot selected
+static uint8_t sd_mmc_slot_sel;
+//! Pointer on current slot selected
+static struct sd_mmc_card *sd_mmc_card;
+//! Number of block to read or write on the current transfer
+static uint16_t sd_mmc_nb_block_to_tranfer = 0;
+//! Number of block remaining to read or write on the current transfer
+static uint16_t sd_mmc_nb_block_remaining = 0;
+
+//! SD/MMC transfer rate unit codes (10K) list
+const uint32_t sd_mmc_trans_units[7] = {
+ 10, 100, 1000, 10000, 0, 0, 0
+};
+//! SD transfer multiplier factor codes (1/10) list
+const uint32_t sd_trans_multipliers[16] = {
+ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+//! MMC transfer multiplier factor codes (1/10) list
+const uint32_t mmc_trans_multipliers[16] = {
+ 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
+};
+
+//! \name MMC, SD and SDIO commands process
+//! @{
+static bool mmc_spi_op_cond(void);
+static bool mmc_mci_op_cond(void);
+static bool sd_spi_op_cond(uint8_t v2);
+static bool sd_mci_op_cond(uint8_t v2);
+static bool sdio_op_cond(void);
+static bool sdio_get_max_speed(void);
+static bool sdio_cmd52_set_bus_width(void);
+static bool sdio_cmd52_set_high_speed(void);
+static bool sd_cm6_set_high_speed(void);
+static bool mmc_cmd6_set_bus_width(uint8_t bus_width);
+static bool mmc_cmd6_set_high_speed(void);
+static bool sd_cmd8(uint8_t * v2);
+static bool mmc_cmd8(uint8_t *b_authorize_high_speed);
+static bool sd_mmc_cmd9_spi(void);
+static bool sd_mmc_cmd9_mci(void);
+static void mmc_decode_csd(void);
+static void sd_decode_csd(void);
+static bool sd_mmc_cmd13(void);
+#ifdef SDIO_SUPPORT_ENABLE
+static bool sdio_cmd52(uint8_t rw_flag, uint8_t func_nb,
+ uint32_t reg_addr, uint8_t rd_after_wr, uint8_t *io_data);
+static bool sdio_cmd53(uint8_t rw_flag, uint8_t func_nb, uint32_t reg_addr,
+ uint8_t inc_addr, uint32_t size, bool access_block);
+#endif // SDIO_SUPPORT_ENABLE
+static bool sd_acmd6(void);
+static bool sd_acmd51(void);
+//! @}
+
+//! \name Internal function to process the initialization and install
+//! @{
+static sd_mmc_err_t sd_mmc_select_slot(uint8_t slot);
+static void sd_mmc_configure_slot(void);
+static void sd_mmc_deselect_slot(void);
+static bool sd_mmc_spi_card_init(void);
+static bool sd_mmc_mci_card_init(void);
+static bool sd_mmc_spi_install_mmc(void);
+static bool sd_mmc_mci_install_mmc(void);
+//! @}
+
+
+//! \name Internal functions to manage a large timeout after a card insertion
+//! @{
+#define SD_MMC_DEBOUNCE_TIMEOUT 1000 // Unit ms
+
+
+/**
+ * \brief Sends operation condition command and read OCR (SPI only)
+ * - CMD1 sends operation condition command
+ * - CMD58 reads OCR
+ *
+ * \return true if success, otherwise false
+ */
+static bool mmc_spi_op_cond(void)
+{
+ uint32_t retry, resp;
+
+ /*
+ * Timeout 1s = 400KHz / ((6+1)*8) cylces = 7150 retry
+ * 6 = cmd byte size
+ * 1 = response byte size
+ */
+ retry = 7150;
+ do {
+ if (!sd_mmc_card->iface->send_cmd(MMC_SPI_CMD1_SEND_OP_COND, 0)) {
+ sd_mmc_debug("%s: CMD1 SPI Fail - Busy retry %d\n\r",
+ __func__, (int)(7150 - retry));
+ return false;
+ }
+ // Check busy flag
+ resp = sd_mmc_card->iface->get_response();
+ if (!(resp & R1_SPI_IDLE)) {
+ break;
+ }
+ if (retry-- == 0) {
+ sd_mmc_debug("%s: CMD1 Timeout on busy\n\r", __func__);
+ return false;
+ }
+ } while (1);
+
+ // Read OCR for SPI mode
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD58_READ_OCR, 0)) {
+ sd_mmc_debug("%s: CMD58 Fail\n\r", __func__);
+ return false;
+ }
+ // Check OCR value
+ if ((sd_mmc_card->iface->get_response() & OCR_ACCESS_MODE_MASK)
+ == OCR_ACCESS_MODE_SECTOR) {
+ sd_mmc_card->type |= CARD_TYPE_HC;
+ }
+ return true;
+}
+
+/**
+ * \brief Sends operation condition command and read OCR (MCI only)
+ * - CMD1 sends operation condition command
+ * - CMD1 reads OCR
+ *
+ * \return true if success, otherwise false
+ */
+static bool mmc_mci_op_cond(void)
+{
+ uint32_t retry, resp;
+
+ /*
+ * Timeout 1s = 400KHz / ((6+6)*8) cylces = 4200 retry
+ * 6 = cmd byte size
+ * 6 = response byte size
+ */
+ retry = 4200;
+ do {
+ if (!sd_mmc_card->iface->send_cmd(MMC_MCI_CMD1_SEND_OP_COND,
+ SD_MMC_VOLTAGE_SUPPORT | OCR_ACCESS_MODE_SECTOR)) {
+ sd_mmc_debug("%s: CMD1 MCI Fail - Busy retry %d\n\r",
+ __func__, (int)(4200 - retry));
+ return false;
+ }
+ // Check busy flag
+ resp = sd_mmc_card->iface->get_response();
+ if (resp & OCR_POWER_UP_BUSY) {
+ // Check OCR value
+ if ((resp & OCR_ACCESS_MODE_MASK)
+ == OCR_ACCESS_MODE_SECTOR) {
+ sd_mmc_card->type |= CARD_TYPE_HC;
+ }
+ break;
+ }
+ if (retry-- == 0) {
+ sd_mmc_debug("%s: CMD1 Timeout on busy\n\r", __func__);
+ return false;
+ }
+ } while (1);
+ return true;
+}
+
+/**
+ * \brief Ask to all cards to send their operations conditions (SPI only).
+ * - ACMD41 sends operation condition command.
+ * - CMD58 reads OCR
+ *
+ * \param v2 Shall be 1 if it is a SD card V2
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_spi_op_cond(uint8_t v2)
+{
+ uint32_t arg, retry, resp;
+
+ /*
+ * Timeout 1s = 400KHz / ((6+1)*8) cylces = 7150 retry
+ * 6 = cmd byte size
+ * 1 = response byte size
+ */
+ retry = 7150;
+ do {
+ // CMD55 - Indicate to the card that the next command is an
+ // application specific command rather than a standard command.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD55_APP_CMD, 0)) {
+ sd_mmc_debug("%s: CMD55 Fail\n\r", __func__);
+ return false;
+ }
+
+ // (ACMD41) Sends host OCR register
+ arg = 0;
+ if (v2) {
+ arg |= SD_ACMD41_HCS;
+ }
+ // Check response
+ if (!sd_mmc_card->iface->send_cmd(SD_SPI_ACMD41_SD_SEND_OP_COND, arg)) {
+ sd_mmc_debug("%s: ACMD41 Fail\n\r", __func__);
+ return false;
+ }
+ resp = sd_mmc_card->iface->get_response();
+ if (!(resp & R1_SPI_IDLE)) {
+ // Card is ready
+ break;
+ }
+ if (retry-- == 0) {
+ sd_mmc_debug("%s: ACMD41 Timeout on busy, resp32 0x%08x \n\r",
+ __func__, resp);
+ return false;
+ }
+ } while (1);
+
+ // Read OCR for SPI mode
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD58_READ_OCR, 0)) {
+ sd_mmc_debug("%s: CMD58 Fail\n\r", __func__);
+ return false;
+ }
+ if ((sd_mmc_card->iface->get_response() & OCR_CCS) != 0) {
+ sd_mmc_card->type |= CARD_TYPE_HC;
+ }
+ return true;
+}
+
+/**
+ * \brief Ask to all cards to send their operations conditions (MCI only).
+ * - ACMD41 sends operation condition command.
+ * - ACMD41 reads OCR
+ *
+ * \param v2 Shall be 1 if it is a SD card V2
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mci_op_cond(uint8_t v2)
+{
+ uint32_t arg, retry, resp;
+
+ /*
+ * Timeout 1s = 400KHz / ((6+6+6+6)*8) cylces = 2100 retry
+ * 6 = cmd byte size
+ * 6 = response byte size
+ * 6 = cmd byte size
+ * 6 = response byte size
+ */
+ retry = 2100;
+ do {
+ // CMD55 - Indicate to the card that the next command is an
+ // application specific command rather than a standard command.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD55_APP_CMD, 0)) {
+ sd_mmc_debug("%s: CMD55 Fail\n\r", __func__);
+ return false;
+ }
+
+ // (ACMD41) Sends host OCR register
+ arg = SD_MMC_VOLTAGE_SUPPORT;
+ if (v2) {
+ arg |= SD_ACMD41_HCS;
+ }
+ // Check response
+ if (!sd_mmc_card->iface->send_cmd(SD_MCI_ACMD41_SD_SEND_OP_COND, arg)) {
+ sd_mmc_debug("%s: ACMD41 Fail\n\r", __func__);
+ return false;
+ }
+ resp = sd_mmc_card->iface->get_response();
+ if (resp & OCR_POWER_UP_BUSY) {
+ // Card is ready
+ if ((resp & OCR_CCS) != 0) {
+ sd_mmc_card->type |= CARD_TYPE_HC;
+ }
+ break;
+ }
+ if (retry-- == 0) {
+ sd_mmc_debug("%s: ACMD41 Timeout on busy, resp32 0x%08x \n\r",
+ __func__, resp);
+ return false;
+ }
+ } while (1);
+ return true;
+}
+
+#ifdef SDIO_SUPPORT_ENABLE
+/**
+ * \brief Try to get the SDIO card's operating condition
+ * - CMD5 to read OCR NF field
+ * - CMD5 to wait OCR power up busy
+ * - CMD5 to read OCR MP field
+ * sd_mmc_card->type is updated
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_op_cond(void)
+{
+ uint32_t resp;
+
+ // CMD5 - SDIO send operation condition (OCR) command.
+ if (!sd_mmc_card->iface->send_cmd(SDIO_CMD5_SEND_OP_COND, 0)) {
+ sd_mmc_debug("%s: CMD5 Fail\n\r", __func__);
+ return true; // No error but card type not updated
+ }
+ resp = sd_mmc_card->iface->get_response();
+ if ((resp & OCR_SDIO_NF) == 0) {
+ return true; // No error but card type not updated
+ }
+
+ /*
+ * Wait card ready
+ * Timeout 1s = 400KHz / ((6+4)*8) cylces = 5000 retry
+ * 6 = cmd byte size
+ * 4(SPI) 6(MCI) = response byte size
+ */
+ uint32_t cmd5_retry = 5000;
+ while (1) {
+ // CMD5 - SDIO send operation condition (OCR) command.
+ if (!sd_mmc_card->iface->send_cmd(SDIO_CMD5_SEND_OP_COND,
+ resp & SD_MMC_VOLTAGE_SUPPORT)) {
+ sd_mmc_debug("%s: CMD5 Fail\n\r", __func__);
+ return false;
+ }
+ resp = sd_mmc_card->iface->get_response();
+ if ((resp & OCR_POWER_UP_BUSY) == OCR_POWER_UP_BUSY) {
+ break;
+ }
+ if (cmd5_retry-- == 0) {
+ sd_mmc_debug("%s: CMD5 Timeout on busy\n\r", __func__);
+ return false;
+ }
+ }
+ // Update card type at the end of busy
+ if ((resp & OCR_SDIO_MP) > 0) {
+ sd_mmc_card->type = CARD_TYPE_SD_COMBO;
+ } else {
+ sd_mmc_card->type = CARD_TYPE_SDIO;
+ }
+ return true; // No error and card type updated with SDIO type
+}
+
+/**
+ * \brief Get SDIO max transfer speed in Hz.
+ * - CMD53 reads CIS area address in CCCR area.
+ * - Nx CMD53 search Fun0 tuple in CIS area
+ * - CMD53 reads TPLFE_MAX_TRAN_SPEED in Fun0 tuple
+ * - Compute maximum speed of SDIO
+ * and update sd_mmc_card->clock
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_get_max_speed(void)
+{
+ uint32_t addr_new, addr_old;
+ uint8_t buf[6];
+ uint32_t unit;
+ uint32_t mul;
+ uint8_t tplfe_max_tran_speed, i;
+ uint8_t addr_cis[4];
+
+ /* Read CIS area address in CCCR area */
+ addr_old = SDIO_CCCR_CIS_PTR;
+ for(i = 0; i < 4; i++) {
+ sdio_cmd52(SDIO_CMD52_READ_FLAG, SDIO_CIA, addr_old, 0, &addr_cis[i]);
+ addr_old++;
+ }
+ addr_old = addr_cis[0] + (addr_cis[1] << 8) + \
+ (addr_cis[2] << 16) + (addr_cis[3] << 24);
+ addr_new = addr_old;
+
+ while (1) {
+ // Read a sample of CIA area
+ for(i=0; i<3; i++) {
+ sdio_cmd52(SDIO_CMD52_READ_FLAG, SDIO_CIA, addr_new, 0, &buf[i]);
+ addr_new++;
+ }
+ if (buf[0] == SDIO_CISTPL_END) {
+ sd_mmc_debug("%s: CMD52 Tuple error\n\r", __func__);
+ return false; // Tuple error
+ }
+ if (buf[0] == SDIO_CISTPL_FUNCE && buf[2] == 0x00) {
+ break; // Fun0 tuple found
+ }
+ if (buf[1] == 0) {
+ sd_mmc_debug("%s: CMD52 Tuple error\n\r", __func__);
+ return false; // Tuple error
+ }
+
+ // Next address
+ addr += (buf[1] + 2);
+ if (addr > (addr_cis + 256)) {
+ sd_mmc_debug("%s: CMD52 Outoff CIS area\n\r", __func__);
+ return false; // Outoff CIS area
+ }
+ }
+
+ // Read all Fun0 tuple fields: fn0_blk_siz & max_tran_speed
+ addr_new -= 3;
+ for(i = 0; i < 6; i++) {
+ sdio_cmd52(SDIO_CMD52_READ_FLAG, SDIO_CIA, addr_new, 0, &buf[i]);
+ addr_new++;
+ }
+
+ tplfe_max_tran_speed = buf[5];
+ if (tplfe_max_tran_speed > 0x32) {
+ /* Error on SDIO register, the high speed is not activated
+ * and the clock can not be more than 25MHz.
+ * This error is present on specific SDIO card
+ * (H&D wireless card - HDG104 WiFi SIP).
+ */
+ tplfe_max_tran_speed = 0x32; // 25Mhz
+ }
+
+ // Decode transfer speed in Hz.
+ unit = sd_mmc_trans_units[tplfe_max_tran_speed & 0x7];
+ mul = sd_trans_multipliers[(tplfe_max_tran_speed >> 3) & 0xF];
+ sd_mmc_card->clock = unit * mul * 1000;
+ /**
+ * Note: A combo card shall be a Full-Speed SDIO card
+ * which supports upto 25MHz.
+ * A SDIO card alone can be:
+ * - a Low-Speed SDIO card which supports 400Khz minimum
+ * - a Full-Speed SDIO card which supports upto 25MHz
+ */
+ return true;
+}
+
+/**
+ * \brief CMD52 for SDIO - Switches the bus width mode to 4
+ *
+ * \note sd_mmc_card->bus_width is updated.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_cmd52_set_bus_width(void)
+{
+ /**
+ * A SD memory card always supports bus 4bit
+ * A SD COMBO card always supports bus 4bit
+ * A SDIO Full-Speed alone always supports 4bit
+ * A SDIO Low-Speed alone can supports 4bit (Optional)
+ */
+ uint8_t u8_value;
+
+ // Check 4bit support in 4BLS of "Card Capability" register
+ if (!sdio_cmd52(SDIO_CMD52_READ_FLAG, SDIO_CIA, SDIO_CCCR_CAP,
+ 0, &u8_value)) {
+ return false;
+ }
+ if ((u8_value & SDIO_CAP_4BLS) != SDIO_CAP_4BLS) {
+ // No supported, it is not a protocol error
+ return true;
+ }
+ // HS mode possible, then enable
+ u8_value = SDIO_BUSWIDTH_4B;
+ if (!sdio_cmd52(SDIO_CMD52_WRITE_FLAG, SDIO_CIA, SDIO_CCCR_BUS_CTRL,
+ 1, &u8_value)) {
+ return false;
+ }
+ sd_mmc_card->bus_width = 4;
+ sd_mmc_debug("%d-bit bus width enabled.\n\r", (int)sd_mmc_card->bus_width);
+ return true;
+}
+
+/**
+ * \brief CMD52 for SDIO - Enable the high speed mode
+ *
+ * \note sd_mmc_card->high_speed is updated.
+ * \note sd_mmc_card->clock is updated.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_cmd52_set_high_speed(void)
+{
+ uint8_t u8_value;
+
+ // Check CIA.HS
+ if (!sdio_cmd52(SDIO_CMD52_READ_FLAG, SDIO_CIA, SDIO_CCCR_HS, 0, &u8_value)) {
+ return false;
+ }
+ if ((u8_value & SDIO_SHS) != SDIO_SHS) {
+ // No supported, it is not a protocol error
+ return true;
+ }
+ // HS mode possible, then enable
+ u8_value = SDIO_EHS;
+ if (!sdio_cmd52(SDIO_CMD52_WRITE_FLAG, SDIO_CIA, SDIO_CCCR_HS,
+ 1, &u8_value)) {
+ return false;
+ }
+ sd_mmc_card->high_speed = 1;
+ sd_mmc_card->clock *= 2;
+ return true;
+}
+
+#else
+static bool sdio_op_cond(void)
+{
+ return true; // No error but card type not updated
+}
+static bool sdio_get_max_speed(void)
+{
+ return false;
+}
+static bool sdio_cmd52_set_bus_width(void)
+{
+ return false;
+}
+static bool sdio_cmd52_set_high_speed(void)
+{
+ return false;
+}
+#endif // SDIO_SUPPORT_ENABLE
+
+/**
+ * \brief CMD6 for SD - Switch card in high speed mode
+ *
+ * \note CMD6 for SD is valid under the "trans" state.
+ * \note sd_mmc_card->high_speed is updated.
+ * \note sd_mmc_card->clock is updated.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_cm6_set_high_speed(void)
+{
+ uint8_t switch_status[SD_SW_STATUS_BSIZE];
+
+ if (!sd_mmc_card->iface->adtc_start(SD_CMD6_SWITCH_FUNC,
+ SD_CMD6_MODE_SWITCH
+ | SD_CMD6_GRP6_NO_INFLUENCE
+ | SD_CMD6_GRP5_NO_INFLUENCE
+ | SD_CMD6_GRP4_NO_INFLUENCE
+ | SD_CMD6_GRP3_NO_INFLUENCE
+ | SD_CMD6_GRP2_DEFAULT
+ | SD_CMD6_GRP1_HIGH_SPEED,
+ SD_SW_STATUS_BSIZE, 1, true)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->start_read_blocks(switch_status, 1)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->wait_end_of_read_blocks()) {
+ return false;
+ }
+
+ if (sd_mmc_card->iface->get_response() & CARD_STATUS_SWITCH_ERROR) {
+ sd_mmc_debug("%s: CMD6 CARD_STATUS_SWITCH_ERROR\n\r", __func__);
+ return false;
+ }
+ if (SD_SW_STATUS_FUN_GRP1_RC(switch_status)
+ == SD_SW_STATUS_FUN_GRP_RC_ERROR) {
+ // No supported, it is not a protocol error
+ return true;
+ }
+ if (SD_SW_STATUS_FUN_GRP1_BUSY(switch_status)) {
+ sd_mmc_debug("%s: CMD6 SD_SW_STATUS_FUN_GRP1_BUSY\n\r", __func__);
+ return false;
+ }
+ // CMD6 function switching period is within 8 clocks
+ // after the end bit of status data.
+ sd_mmc_card->iface->send_clock();
+ sd_mmc_card->high_speed = 1;
+ sd_mmc_card->clock *= 2;
+ return true;
+}
+
+/**
+ * \brief CMD6 for MMC - Switches the bus width mode
+ *
+ * \note CMD6 is valid under the "trans" state.
+ * \note sd_mmc_card->bus_width is updated.
+ *
+ * \param bus_width Bus width to set
+ *
+ * \return true if success, otherwise false
+ */
+static bool mmc_cmd6_set_bus_width(uint8_t bus_width)
+{
+ uint32_t arg;
+
+ switch (bus_width) {
+ case 8:
+ arg = MMC_CMD6_ACCESS_SET_BITS
+ | MMC_CMD6_INDEX_BUS_WIDTH
+ | MMC_CMD6_VALUE_BUS_WIDTH_8BIT;
+ break;
+ case 4:
+ arg = MMC_CMD6_ACCESS_SET_BITS
+ | MMC_CMD6_INDEX_BUS_WIDTH
+ | MMC_CMD6_VALUE_BUS_WIDTH_4BIT;
+ break;
+ default:
+ arg = MMC_CMD6_ACCESS_SET_BITS
+ | MMC_CMD6_INDEX_BUS_WIDTH
+ | MMC_CMD6_VALUE_BUS_WIDTH_1BIT;
+ break;
+ }
+ if (!sd_mmc_card->iface->send_cmd(MMC_CMD6_SWITCH, arg)) {
+ return false;
+ }
+ if (sd_mmc_card->iface->get_response() & CARD_STATUS_SWITCH_ERROR) {
+ // No supported, it is not a protocol error
+ sd_mmc_debug("%s: CMD6 CARD_STATUS_SWITCH_ERROR\n\r", __func__);
+ return false;
+ }
+ sd_mmc_card->bus_width = bus_width;
+ sd_mmc_debug("%d-bit bus width enabled.\n\r", (int)sd_mmc_card->bus_width);
+ return true;
+}
+
+/**
+ * \brief CMD6 for MMC - Switches in high speed mode
+ *
+ * \note CMD6 is valid under the "trans" state.
+ * \note sd_mmc_card->high_speed is updated.
+ * \note sd_mmc_card->clock is updated.
+ *
+ * \return true if success, otherwise false
+ */
+static bool mmc_cmd6_set_high_speed(void)
+{
+ if (!sd_mmc_card->iface->send_cmd(MMC_CMD6_SWITCH,
+ MMC_CMD6_ACCESS_WRITE_BYTE
+ | MMC_CMD6_INDEX_HS_TIMING
+ | MMC_CMD6_VALUE_HS_TIMING_ENABLE)) {
+ return false;
+ }
+ if (sd_mmc_card->iface->get_response() & CARD_STATUS_SWITCH_ERROR) {
+ // No supported, it is not a protocol error
+ sd_mmc_debug("%s: CMD6 CARD_STATUS_SWITCH_ERROR\n\r", __func__);
+ return false;
+ }
+ sd_mmc_card->high_speed = 1;
+ sd_mmc_card->clock = 52000000lu;
+ return true;
+}
+
+/**
+ * \brief CMD8 for SD card - Send Interface Condition Command.
+ *
+ * \note
+ * Send SD Memory Card interface condition, which includes host supply
+ * voltage information and asks the card whether card supports voltage.
+ * Should be performed at initialization time to detect the card type.
+ *
+ * \param v2 Pointer to v2 flag to update
+ *
+ * \return true if success, otherwise false
+ * with a update of \ref sd_mmc_err.
+ */
+static bool sd_cmd8(uint8_t * v2)
+{
+ uint32_t resp;
+
+ *v2 = 0;
+ // Test for SD version 2
+ if (!sd_mmc_card->iface->send_cmd(SD_CMD8_SEND_IF_COND,
+ SD_CMD8_PATTERN | SD_CMD8_HIGH_VOLTAGE)) {
+ return true; // It is not a V2
+ }
+ // Check R7 response
+ resp = sd_mmc_card->iface->get_response();
+ if (resp == 0xFFFFFFFF) {
+ // No compliance R7 value
+ return true; // It is not a V2
+ }
+ if ((resp & (SD_CMD8_MASK_PATTERN | SD_CMD8_MASK_VOLTAGE))
+ != (SD_CMD8_PATTERN | SD_CMD8_HIGH_VOLTAGE)) {
+ sd_mmc_debug("%s: CMD8 resp32 0x%08x UNUSABLE CARD\n\r",
+ __func__, resp);
+ return false;
+ }
+ sd_mmc_debug("SD card V2\n\r");
+ *v2 = 1;
+ return true;
+}
+
+/**
+ * \brief CMD8 - The card sends its EXT_CSD register as a block of data.
+ *
+ * \param b_authorize_high_speed Pointer to update with the high speed
+ * support information
+ *
+ * \return true if success, otherwise false
+ */
+static bool mmc_cmd8(uint8_t *b_authorize_high_speed)
+{
+ uint16_t i;
+ uint32_t ext_csd;
+ uint32_t sec_count;
+
+ if (!sd_mmc_card->iface->adtc_start(MMC_CMD8_SEND_EXT_CSD, 0,
+ EXT_CSD_BSIZE, 1, false)) {
+ return false;
+ }
+ //** Read and decode Extended Extended CSD
+ // Note: The read access is done in byte to avoid a buffer
+ // of EXT_CSD_BSIZE Byte in stack.
+
+ // Read card type
+ for (i = 0; i < (EXT_CSD_CARD_TYPE_INDEX + 4) / 4; i++) {
+ if (!sd_mmc_card->iface->read_word(&ext_csd)) {
+ return false;
+ }
+ }
+ *b_authorize_high_speed = (ext_csd >> ((EXT_CSD_CARD_TYPE_INDEX % 4) * 8))
+ & MMC_CTYPE_52MHZ;
+
+ if (MMC_CSD_C_SIZE(sd_mmc_card->csd) == 0xFFF) {
+ // For high capacity SD/MMC card,
+ // memory capacity = SEC_COUNT * 512 byte
+ for (; i <(EXT_CSD_SEC_COUNT_INDEX + 4) / 4; i++) {
+ if (!sd_mmc_card->iface->read_word(&sec_count)) {
+ return false;
+ }
+ }
+ sd_mmc_card->capacity = sec_count / 2;
+ }
+ for (; i < EXT_CSD_BSIZE / 4; i++) {
+ if (!sd_mmc_card->iface->read_word(&sec_count)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * \brief CMD9: Addressed card sends its card-specific
+ * data (CSD) on the CMD line spi.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_cmd9_spi(void)
+{
+ if (!sd_mmc_card->iface->adtc_start(SDMMC_SPI_CMD9_SEND_CSD, (uint32_t)sd_mmc_card->rca << 16,
+ CSD_REG_BSIZE, 1, true)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->start_read_blocks(sd_mmc_card->csd, 1)) {
+ return false;
+ }
+ return sd_mmc_card->iface->wait_end_of_read_blocks();
+}
+
+/**
+ * \brief CMD9: Addressed card sends its card-specific
+ * data (CSD) on the CMD line mci.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_cmd9_mci(void)
+{
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_MCI_CMD9_SEND_CSD, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ sd_mmc_card->iface->get_response_128(sd_mmc_card->csd);
+ return true;
+}
+
+/**
+ * \brief Decodes MMC CSD register
+ */
+static void mmc_decode_csd(void)
+{
+ uint32_t unit;
+ uint32_t mul;
+ uint32_t tran_speed;
+
+ // Get MMC System Specification version supported by the card
+ switch (MMC_CSD_SPEC_VERS(sd_mmc_card->csd)) {
+ default:
+ case 0:
+ sd_mmc_card->version = CARD_VER_MMC_1_2;
+ break;
+
+ case 1:
+ sd_mmc_card->version = CARD_VER_MMC_1_4;
+ break;
+
+ case 2:
+ sd_mmc_card->version = CARD_VER_MMC_2_2;
+ break;
+
+ case 3:
+ sd_mmc_card->version = CARD_VER_MMC_3;
+ break;
+
+ case 4:
+ sd_mmc_card->version = CARD_VER_MMC_4;
+ break;
+ }
+
+ // Get MMC memory max transfer speed in Hz.
+ tran_speed = CSD_TRAN_SPEED(sd_mmc_card->csd);
+ unit = sd_mmc_trans_units[tran_speed & 0x7];
+ mul = mmc_trans_multipliers[(tran_speed >> 3) & 0xF];
+ sd_mmc_card->clock = unit * mul * 1000;
+
+ /*
+ * Get card capacity.
+ * ----------------------------------------------------
+ * For normal SD/MMC card:
+ * memory capacity = BLOCKNR * BLOCK_LEN
+ * Where
+ * BLOCKNR = (C_SIZE+1) * MULT
+ * MULT = 2 ^ (C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+ * BLOCK_LEN = 2 ^ READ_BL_LEN (READ_BL_LEN < 12)
+ * ----------------------------------------------------
+ * For high capacity SD/MMC card:
+ * memory capacity = SEC_COUNT * 512 byte
+ */
+ if (MMC_CSD_C_SIZE(sd_mmc_card->csd) != 0xFFF) {
+ uint32_t blocknr = ((MMC_CSD_C_SIZE(sd_mmc_card->csd) + 1) *
+ (1 << (MMC_CSD_C_SIZE_MULT(sd_mmc_card->csd) + 2)));
+ sd_mmc_card->capacity = blocknr *
+ (1 << MMC_CSD_READ_BL_LEN(sd_mmc_card->csd)) / 1024;
+ }
+}
+
+/**
+ * \brief Decodes SD CSD register
+ */
+static void sd_decode_csd(void)
+{
+ uint32_t unit;
+ uint32_t mul;
+ uint32_t tran_speed;
+
+ // Get SD memory maximum transfer speed in Hz.
+ tran_speed = CSD_TRAN_SPEED(sd_mmc_card->csd);
+ unit = sd_mmc_trans_units[tran_speed & 0x7];
+ mul = sd_trans_multipliers[(tran_speed >> 3) & 0xF];
+ sd_mmc_card->clock = unit * mul * 1000;
+
+ /*
+ * Get card capacity.
+ * ----------------------------------------------------
+ * For normal SD/MMC card:
+ * memory capacity = BLOCKNR * BLOCK_LEN
+ * Where
+ * BLOCKNR = (C_SIZE+1) * MULT
+ * MULT = 2 ^ (C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+ * BLOCK_LEN = 2 ^ READ_BL_LEN (READ_BL_LEN < 12)
+ * ----------------------------------------------------
+ * For high capacity SD card:
+ * memory capacity = (C_SIZE+1) * 512K byte
+ */
+ if (CSD_STRUCTURE_VERSION(sd_mmc_card->csd) >= SD_CSD_VER_2_0) {
+ sd_mmc_card->capacity =
+ (SD_CSD_2_0_C_SIZE(sd_mmc_card->csd) + 1)
+ * 512;
+ } else {
+ uint32_t blocknr = ((SD_CSD_1_0_C_SIZE(sd_mmc_card->csd) + 1) *
+ (1 << (SD_CSD_1_0_C_SIZE_MULT(sd_mmc_card->csd) + 2)));
+ sd_mmc_card->capacity = blocknr *
+ (1 << SD_CSD_1_0_READ_BL_LEN(sd_mmc_card->csd))
+ / 1024;
+ }
+}
+
+/**
+ * \brief CMD13 - Addressed card sends its status register.
+ * This function waits the clear of the busy flag
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_cmd13(void)
+{
+ uint32_t nec_timeout;
+
+ /* Wait for data ready status.
+ * Nec timing: 0 to unlimited
+ * However a timeout is used.
+ * 200 000 * 8 cycles
+ */
+ nec_timeout = 200000;
+ do {
+ if (sd_mmc_card->iface->is_spi) {
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD13_SEND_STATUS, 0)) {
+ return false;
+ }
+ // Check busy flag
+ if (!(sd_mmc_card->iface->get_response() & 0xFF)) {
+ break;
+ }
+ } else {
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_MCI_CMD13_SEND_STATUS, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ // Check busy flag
+ if (sd_mmc_card->iface->get_response() & CARD_STATUS_READY_FOR_DATA) {
+ break;
+ }
+ }
+ if (nec_timeout-- == 0) {
+ sd_mmc_debug("%s: CMD13 Busy timeout\n\r", __func__);
+ return false;
+ }
+ } while (1);
+
+ return true;
+}
+
+#ifdef SDIO_SUPPORT_ENABLE
+/**
+ * \brief CMD52 - SDIO IO_RW_DIRECT command
+ *
+ * \param rw_flag Direction, 1:write, 0:read.
+ * \param func_nb Number of the function.
+ * \param rd_after_wr Read after Write flag.
+ * \param reg_addr register address.
+ * \param io_data Pointer to input argument and response buffer.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_cmd52(uint8_t rw_flag, uint8_t func_nb,
+ uint32_t reg_addr, uint8_t rd_after_wr, uint8_t *io_data)
+{
+ Assert(io_data != NULL);
+ if (!sd_mmc_card->iface->send_cmd(SDIO_CMD52_IO_RW_DIRECT,
+ ((uint32_t)*io_data << SDIO_CMD52_WR_DATA)
+ | ((uint32_t)rw_flag << SDIO_CMD52_RW_FLAG)
+ | ((uint32_t)func_nb << SDIO_CMD52_FUNCTION_NUM)
+ | ((uint32_t)rd_after_wr << SDIO_CMD52_RAW_FLAG)
+ | ((uint32_t)reg_addr << SDIO_CMD52_REG_ADRR))) {
+ return false;
+ }
+ *io_data = sd_mmc_card->iface->get_response() & 0xFF;
+ return true;
+}
+
+/**
+ * \brief CMD53 - SDIO IO_RW_EXTENDED command
+ * This implementation support only the SDIO multi-byte transfer mode which is
+ * similar to the single block transfer on memory.
+ * Note: The SDIO block transfer mode is optional for SDIO card.
+ *
+ * \param rw_flag Direction, 1:write, 0:read.
+ * \param func_nb Number of the function.
+ * \param reg_addr Register address.
+ * \param inc_addr 1:Incrementing address, 0: fixed.
+ * \param size Transfer data size.
+ * \param access_block true, if the block access (DMA) is used
+ *
+ * \return true if success, otherwise false
+ */
+static bool sdio_cmd53(uint8_t rw_flag, uint8_t func_nb, uint32_t reg_addr,
+ uint8_t inc_addr, uint32_t size, bool access_block)
+{
+ Assert(size != 0);
+ Assert(size <= 512);
+
+ return sd_mmc_card->iface->adtc_start((rw_flag == SDIO_CMD53_READ_FLAG)?
+ SDIO_CMD53_IO_R_BYTE_EXTENDED :
+ SDIO_CMD53_IO_W_BYTE_EXTENDED,
+ ((size % 512) << SDIO_CMD53_COUNT)
+ | ((uint32_t)reg_addr << SDIO_CMD53_REG_ADDR)
+ | ((uint32_t)inc_addr << SDIO_CMD53_OP_CODE)
+ | ((uint32_t)0 << SDIO_CMD53_BLOCK_MODE)
+ | ((uint32_t)func_nb << SDIO_CMD53_FUNCTION_NUM)
+ | ((uint32_t)rw_flag << SDIO_CMD53_RW_FLAG),
+ size, 1, access_block);
+}
+#endif // SDIO_SUPPORT_ENABLE
+
+/**
+ * \brief ACMD6 - Define the data bus width to 4 bits bus
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_acmd6(void)
+{
+ // CMD55 - Indicate to the card that the next command is an
+ // application specific command rather than a standard command.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD55_APP_CMD, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ // 10b = 4 bits bus
+ if (!sd_mmc_card->iface->send_cmd(SD_ACMD6_SET_BUS_WIDTH, 0x2)) {
+ return false;
+ }
+ sd_mmc_card->bus_width = 4;
+ sd_mmc_debug("%d-bit bus width enabled.\n\r", (int)sd_mmc_card->bus_width);
+ return true;
+}
+
+/**
+ * \brief ACMD51 - Read the SD Configuration Register.
+ *
+ * \note
+ * SD Card Configuration Register (SCR) provides information on the SD Memory
+ * Card's special features that were configured into the given card. The size
+ * of SCR register is 64 bits.
+ *
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_acmd51(void)
+{
+ uint8_t scr[SD_SCR_REG_BSIZE];
+
+ // CMD55 - Indicate to the card that the next command is an
+ // application specific command rather than a standard command.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD55_APP_CMD, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->adtc_start(SD_ACMD51_SEND_SCR, 0,
+ SD_SCR_REG_BSIZE, 1, true)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->start_read_blocks(scr, 1)) {
+ return false;
+ }
+ if (!sd_mmc_card->iface->wait_end_of_read_blocks()) {
+ return false;
+ }
+
+ // Get SD Memory Card - Spec. Version
+ switch (SD_SCR_SD_SPEC(scr)) {
+ case SD_SCR_SD_SPEC_1_0_01:
+ sd_mmc_card->version = CARD_VER_SD_1_0;
+ break;
+
+ case SD_SCR_SD_SPEC_1_10:
+ sd_mmc_card->version = CARD_VER_SD_1_10;
+ break;
+
+ case SD_SCR_SD_SPEC_2_00:
+ if (SD_SCR_SD_SPEC3(scr) == SD_SCR_SD_SPEC_3_00) {
+ sd_mmc_card->version = CARD_VER_SD_3_0;
+ } else {
+ sd_mmc_card->version = CARD_VER_SD_2_0;
+ }
+ break;
+
+ default:
+ sd_mmc_card->version = CARD_VER_SD_1_0;
+ break;
+ }
+ return true;
+}
+
+/**
+ * \brief Select a card slot and initialize the associated driver
+ *
+ * \param slot Card slot number
+ *
+ * \retval SD_MMC_ERR_SLOT Wrong slot number
+ * \retval SD_MMC_ERR_NO_CARD No card present on slot
+ * \retval SD_MMC_ERR_UNUSABLE Unusable card
+ * \retval SD_MMC_INIT_ONGOING Card initialization requested
+ * \retval SD_MMC_OK Card present
+ * \retval SD_MMC_CD_DEBOUNCING Giving the card time to be ready
+ */
+static sd_mmc_err_t sd_mmc_select_slot(uint8_t slot)
+{
+ if (slot >= SD_MMC_MEM_CNT) {
+ return SD_MMC_ERR_SLOT;
+ }
+ Assert(sd_mmc_nb_block_remaining == 0);
+
+#if 1 // dc42
+ // RepRapFirmware now handles the card detect pin and debouncing, so ignore the card detect pin here
+#else
+ if (sd_mmc_cards[slot].cd_gpio != NoPin) {
+ //! Card Detect pins
+ if (digitalRead(sd_mmc_cards[slot].cd_gpio) != SD_MMC_CD_DETECT_VALUE) {
+ if (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_DEBOUNCE) {
+ SD_MMC_STOP_TIMEOUT();
+ }
+ sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_NO_CARD;
+ return SD_MMC_ERR_NO_CARD;
+ }
+ if (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_NO_CARD) {
+ // A card plug on going, but this is not initialized
+ sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_DEBOUNCE;
+ // Debounce + Power On Setup
+ SD_MMC_START_TIMEOUT();
+ return SD_MMC_CD_DEBOUNCING;
+ }
+ if (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_DEBOUNCE) {
+ if (!SD_MMC_IS_TIMEOUT()) {
+ // Debounce on going
+ return SD_MMC_CD_DEBOUNCING;
+ }
+ // Card is not initialized
+ sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_INIT;
+ // Set 1-bit bus width and low clock for initialization
+ sd_mmc_cards[slot].clock = SDMMC_CLOCK_INIT;
+ sd_mmc_cards[slot].bus_width = 1;
+ sd_mmc_cards[slot].high_speed = 0;
+ }
+ if (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_UNUSABLE) {
+ return SD_MMC_ERR_UNUSABLE;
+ }
+ }
+ else
+#endif
+ {
+ // No pin card detection, then always try to install it
+ if ((sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_NO_CARD)
+ || (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_UNUSABLE)) {
+ // Card is not initialized
+ sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_INIT;
+ // Set 1-bit bus width and low clock for initialization
+ sd_mmc_cards[slot].clock = SDMMC_CLOCK_INIT;
+ sd_mmc_cards[slot].bus_width = 1;
+ sd_mmc_cards[slot].high_speed = 0;
+ }
+ }
+
+ // Initialize interface
+ sd_mmc_slot_sel = slot;
+ sd_mmc_card = &sd_mmc_cards[slot];
+ sd_mmc_configure_slot();
+ return (sd_mmc_cards[slot].state == SD_MMC_CARD_STATE_INIT) ?
+ SD_MMC_INIT_ONGOING : SD_MMC_OK;
+}
+
+/**
+ * \brief Configures the driver with the selected card configuration
+ */
+static void sd_mmc_configure_slot(void)
+{
+ sd_mmc_card->iface->select_device(sd_mmc_card->slot, sd_mmc_card->clock, sd_mmc_card->bus_width, sd_mmc_card->high_speed);
+}
+
+/**
+ * \brief Deselect the current card slot
+ */
+static void sd_mmc_deselect_slot(void)
+{
+ if (sd_mmc_slot_sel < SD_MMC_MEM_CNT) {
+ sd_mmc_card->iface->deselect_device(sd_mmc_card->slot);
+ sd_mmc_slot_sel = 0xFF; // No slot selected
+ }
+}
+
+/**
+ * \brief Initialize the SD card in SPI mode.
+ *
+ * \note
+ * This function runs the initialization procedure and the identification
+ * process, then it sets the SD/MMC card in transfer state.
+ * At last, it will automatically enable maximum bus width and transfer speed.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_spi_card_init(void)
+{
+ uint8_t v2 = 0;
+
+ // In first, try to install SD/SDIO card
+ sd_mmc_card->type = CARD_TYPE_SD;
+ sd_mmc_card->version = CARD_VER_UNKNOWN;
+ sd_mmc_card->rca = 0;
+ sd_mmc_debug("Start SD card install\n\r");
+
+ // Card need of 74 cycles clock minimum to start
+ sd_mmc_card->iface->send_clock();
+
+ // CMD0 - Reset all cards to idle state.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD0_GO_IDLE_STATE, 0)) {
+ return false;
+ }
+ if (!sd_cmd8(&v2)) {
+ return false;
+ }
+ // Try to get the SDIO card's operating condition
+ if (!sdio_op_cond()) {
+ return false;
+ }
+
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ // Try to get the SD card's operating condition
+ if (!sd_spi_op_cond(v2)) {
+ // It is not a SD card
+ sd_mmc_debug("Start MMC Install\n\r");
+ sd_mmc_card->type = CARD_TYPE_MMC;
+ return sd_mmc_spi_install_mmc();
+ }
+
+ /* The CRC on card is disabled by default.
+ * However, to be sure, the CRC OFF command is send.
+ * Unfortunately, specific SDIO card does not support it
+ * (H&D wireless card - HDG104 WiFi SIP)
+ * and the command is send only on SD card.
+ */
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD59_CRC_ON_OFF, 0)) {
+ return false;
+ }
+ }
+ // SD MEMORY
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ // Get the Card-Specific Data
+ if (!sd_mmc_cmd9_spi()) {
+ return false;
+ }
+ sd_decode_csd();
+ // Read the SCR to get card version
+ if (!sd_acmd51()) {
+ return false;
+ }
+ }
+ if (IS_SDIO()) {
+ if (!sdio_get_max_speed()) {
+ return false;
+ }
+ }
+ // SD MEMORY not HC, Set default block size
+ if ((sd_mmc_card->type & CARD_TYPE_SD) &&
+ (0 == (sd_mmc_card->type & CARD_TYPE_HC))) {
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE)) {
+ return false;
+ }
+ }
+ // Check communication
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (!sd_mmc_cmd13()) {
+ return false;
+ }
+ }
+ // Re-initialize the slot with the new speed
+ sd_mmc_configure_slot();
+ return true;
+}
+
+/**
+ * \brief Initialize the SD card in MCI mode.
+ *
+ * \note
+ * This function runs the initialization procedure and the identification
+ * process, then it sets the SD/MMC card in transfer state.
+ * At last, it will automatically enable maximum bus width and transfer speed.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_mci_card_init(void)
+{
+ uint8_t v2 = 0;
+
+ // In first, try to install SD/SDIO card
+ sd_mmc_card->type = CARD_TYPE_SD;
+ sd_mmc_card->version = CARD_VER_UNKNOWN;
+ sd_mmc_card->rca = 0;
+ sd_mmc_debug("Start SD card install\n\r");
+
+ // Card need of 74 cycles clock minimum to start
+ sd_mmc_card->iface->send_clock();
+
+ // CMD0 - Reset all cards to idle state.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_MCI_CMD0_GO_IDLE_STATE, 0)) {
+ return false;
+ }
+ if (!sd_cmd8(&v2)) {
+ return false;
+ }
+ // Try to get the SDIO card's operating condition
+ if (!sdio_op_cond()) {
+ return false;
+ }
+
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ // Try to get the SD card's operating condition
+ if (!sd_mci_op_cond(v2)) {
+ // It is not a SD card
+ sd_mmc_debug("Start MMC Install\n\r");
+ sd_mmc_card->type = CARD_TYPE_MMC;
+ return sd_mmc_mci_install_mmc();
+ }
+ }
+
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ // SD MEMORY, Put the Card in Identify Mode
+ // Note: The CID is not used in this stack
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD2_ALL_SEND_CID, 0)) {
+ return false;
+ }
+ }
+ // Ask the card to publish a new relative address (RCA).
+ if (!sd_mmc_card->iface->send_cmd(SD_CMD3_SEND_RELATIVE_ADDR, 0)) {
+ return false;
+ }
+ sd_mmc_card->rca = (sd_mmc_card->iface->get_response() >> 16) & 0xFFFF;
+
+ // SD MEMORY, Get the Card-Specific Data
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (!sd_mmc_cmd9_mci()) {
+ return false;
+ }
+ sd_decode_csd();
+ }
+ // Select the and put it into Transfer Mode
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD7_SELECT_CARD_CMD,
+ (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ // SD MEMORY, Read the SCR to get card version
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (!sd_acmd51()) {
+ return false;
+ }
+ }
+ if (IS_SDIO()) {
+ if (!sdio_get_max_speed()) {
+ return false;
+ }
+ }
+ if ((4 <= sd_mmc_card->iface->get_bus_width(sd_mmc_card->slot))) {
+ // TRY to enable 4-bit mode
+ if (IS_SDIO()) {
+ if (!sdio_cmd52_set_bus_width()) {
+ return false;
+ }
+ }
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (!sd_acmd6()) {
+ return false;
+ }
+ }
+ // Switch to selected bus mode
+ sd_mmc_configure_slot();
+ }
+ if (sd_mmc_card->iface->is_high_speed_capable()) {
+ // TRY to enable High-Speed Mode
+ if (IS_SDIO()) {
+ if (!sdio_cmd52_set_high_speed()) {
+ return false;
+ }
+ }
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (sd_mmc_card->version > CARD_VER_SD_1_0) {
+ if (!sd_cm6_set_high_speed()) {
+ return false;
+ }
+ }
+ }
+ // Valid new configuration
+ sd_mmc_configure_slot();
+ }
+ // SD MEMORY, Set default block size
+ if (sd_mmc_card->type & CARD_TYPE_SD) {
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * \brief Initialize the MMC card in SPI mode.
+ *
+ * \note
+ * This function runs the initialization procedure and the identification
+ * process, then it sets the SD/MMC card in transfer state.
+ * At last, it will automatically enable maximum bus width and transfer speed.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_spi_install_mmc(void)
+{
+ uint8_t b_authorize_high_speed;
+
+ // CMD0 - Reset all cards to idle state.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD0_GO_IDLE_STATE, 0)) {
+ return false;
+ }
+
+ if (!mmc_spi_op_cond()) {
+ return false;
+ }
+
+ // Disable CRC check for SPI mode
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_SPI_CMD59_CRC_ON_OFF, 0)) {
+ return false;
+ }
+ // Get the Card-Specific Data
+ if (!sd_mmc_cmd9_spi()) {
+ return false;
+ }
+ mmc_decode_csd();
+ // For MMC 4.0 Higher version
+ if (sd_mmc_card->version >= CARD_VER_MMC_4) {
+ // Get EXT_CSD
+ if (!mmc_cmd8(&b_authorize_high_speed)) {
+ return false;
+ }
+ }
+ // Set default block size
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE)) {
+ return false;
+ }
+ // Check communication
+ if (!sd_mmc_cmd13()) {
+ return false;
+ }
+ // Re-initialize the slot with the new speed
+ sd_mmc_configure_slot();
+ return true;
+}
+
+
+/**
+ * \brief Initialize the MMC card in MCI mode.
+ *
+ * \note
+ * This function runs the initialization procedure and the identification
+ * process, then it sets the SD/MMC card in transfer state.
+ * At last, it will automatically enable maximum bus width and transfer speed.
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_mci_install_mmc(void)
+{
+ uint8_t b_authorize_high_speed;
+
+ // CMD0 - Reset all cards to idle state.
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_MCI_CMD0_GO_IDLE_STATE, 0)) {
+ return false;
+ }
+
+ if (!mmc_mci_op_cond()) {
+ return false;
+ }
+
+ // Put the Card in Identify Mode
+ // Note: The CID is not used in this stack
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD2_ALL_SEND_CID, 0)) {
+ return false;
+ }
+ // Assign relative address to the card.
+ sd_mmc_card->rca = 1;
+ if (!sd_mmc_card->iface->send_cmd(MMC_CMD3_SET_RELATIVE_ADDR, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ // Get the Card-Specific Data
+ if (!sd_mmc_cmd9_mci()) {
+ return false;
+ }
+ mmc_decode_csd();
+ // Select the and put it into Transfer Mode
+ if (!sd_mmc_card->iface->send_cmd(SDMMC_CMD7_SELECT_CARD_CMD, (uint32_t)sd_mmc_card->rca << 16)) {
+ return false;
+ }
+ if (sd_mmc_card->version >= CARD_VER_MMC_4) {
+ // For MMC 4.0 Higher version
+ // Get EXT_CSD
+ if (!mmc_cmd8(&b_authorize_high_speed)) {
+ return false;
+ }
+ if (4 <= sd_mmc_card->iface->get_bus_width(sd_mmc_card->slot)) {
+ // Enable more bus width
+ if (!mmc_cmd6_set_bus_width(sd_mmc_card->iface->get_bus_width(sd_mmc_card->slot))) {
+ return false;
+ }
+ // Re-initialize the slot with the bus width
+ sd_mmc_configure_slot();
+ }
+ if (sd_mmc_card->iface->is_high_speed_capable() && b_authorize_high_speed) {
+ // Enable HS
+ if (!mmc_cmd6_set_high_speed()) {
+ return false;
+ }
+ // Re-initialize the slot with the new speed
+ sd_mmc_configure_slot();
+ }
+ } else {
+ // Re-initialize the slot with the new speed
+ sd_mmc_configure_slot();
+ }
+
+ uint8_t retry = 10;
+ while (retry--) {
+ // Retry is a WORKAROUND for no compliance card (Atmel Internal ref. MMC19):
+ // These cards seem not ready immediatly
+ // after the end of busy of mmc_cmd6_set_high_speed()
+
+ // Set default block size
+ if (sd_mmc_card->iface->send_cmd(SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//-------------------------------------------------------------------
+//--------------------- PUBLIC FUNCTIONS ----------------------------
+
+void sd_mmc_init(const Pin wpPins[], const Pin spiCsPins[])
+{
+ for (size_t slot = 0; slot < SD_MMC_MEM_CNT; slot++)
+ {
+ struct sd_mmc_card *card = &sd_mmc_cards[slot];
+ card->state = SD_MMC_CARD_STATE_NO_CARD;
+ card->wp_gpio = wpPins[slot];
+ if (card->wp_gpio != NoPin)
+ {
+ pinMode(card->wp_gpio, INPUT_PULLUP);
+ }
+#if SD_MMC_HSMCI_MEM_CNT != 0
+ if (slot < SD_MMC_HSMCI_MEM_CNT)
+ {
+ card->iface = &hsmciInterface;
+ card->slot = slot;
+ }
+ else
+#endif
+ {
+#if (SD_MMC_SPI_MEM_CNT != 0)
+ card->iface = &spiInterface;
+ card->slot = slot - SD_MMC_HSMCI_MEM_CNT;
+#endif
+ }
+ }
+ sd_mmc_slot_sel = 0xFF; // No slot selected
+
+#if SD_MMC_HSMCI_MEM_CNT != 0
+ hsmci_init();
+#endif
+
+#if SD_MMC_SPI_MEM_CNT != 0
+ sd_mmc_spi_init(spiCsPins);
+#endif
+}
+
+uint8_t sd_mmc_nb_slot(void)
+{
+ return SD_MMC_MEM_CNT;
+}
+
+sd_mmc_err_t sd_mmc_check(uint8_t slot)
+{
+#if 1 //dc42
+ sd_mmc_err_t sd_mmc_err;
+ do
+ {
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ } while (sd_mmc_err == SD_MMC_CD_DEBOUNCING);
+#else
+ sd_mmc_err_t sd_mmc_err = sd_mmc_select_slot(slot);
+#endif
+ if (sd_mmc_err != SD_MMC_INIT_ONGOING)
+ {
+ sd_mmc_deselect_slot();
+ return sd_mmc_err;
+ }
+
+ // Initialization of the card requested
+ if (sd_mmc_card->iface->is_spi ? sd_mmc_spi_card_init() : sd_mmc_mci_card_init()) {
+ sd_mmc_debug("SD/MMC card ready\n\r");
+ sd_mmc_card->state = SD_MMC_CARD_STATE_READY;
+ sd_mmc_deselect_slot();
+#if 1
+ // If we return SD_MMC_INIT_ONGOING here then I can't see how we can ever access the card
+ return SD_MMC_OK;
+#else
+ // To notify that the card has been just initialized
+ // It is necessary for USB Device MSC
+ return SD_MMC_INIT_ONGOING;
+#endif
+ }
+ sd_mmc_debug("SD/MMC card initialization failed\n\r");
+ sd_mmc_card->state = SD_MMC_CARD_STATE_UNUSABLE;
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_UNUSABLE;
+}
+
+card_type_t sd_mmc_get_type(uint8_t slot)
+{
+ if (SD_MMC_OK != sd_mmc_select_slot(slot)) {
+ return CARD_TYPE_UNKNOWN;
+ }
+ sd_mmc_deselect_slot();
+ return sd_mmc_card->type;
+}
+
+card_version_t sd_mmc_get_version(uint8_t slot)
+{
+ if (SD_MMC_OK != sd_mmc_select_slot(slot)) {
+ return CARD_VER_UNKNOWN;
+ }
+ sd_mmc_deselect_slot();
+ return sd_mmc_card->version;
+}
+
+uint32_t sd_mmc_get_capacity(uint8_t slot)
+{
+ if (SD_MMC_OK != sd_mmc_select_slot(slot)) {
+ return 0;
+ }
+ sd_mmc_deselect_slot();
+ return sd_mmc_card->capacity;
+}
+
+bool sd_mmc_is_write_protected(uint8_t slot)
+{
+ return sd_mmc_cards[slot].wp_gpio != NoPin && digitalRead(sd_mmc_cards[slot].wp_gpio) == SD_MMC_WP_DETECT_VALUE;
+}
+
+#if 1 // dc42
+
+// Unmount the card. Must call this to force it to be re-initialised when changing card.
+void sd_mmc_unmount(uint8_t slot)
+{
+ sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_NO_CARD;
+}
+
+// Get the interface speed in bytes/sec
+uint32_t sd_mmc_get_interface_speed(uint8_t slot)
+{
+ return sd_mmc_cards[slot].iface->getInterfaceSpeed();
+}
+
+#endif
+
+sd_mmc_err_t sd_mmc_init_read_blocks(uint8_t slot, uint32_t start, uint16_t nb_block)
+{
+ sd_mmc_err_t sd_mmc_err;
+ uint32_t cmd, arg, resp;
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+
+ // Wait for data ready status
+ if (!sd_mmc_cmd13()) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+
+ if (nb_block > 1) {
+ cmd = SDMMC_CMD18_READ_MULTIPLE_BLOCK;
+ } else {
+ cmd = SDMMC_CMD17_READ_SINGLE_BLOCK;
+ }
+ /*
+ * SDSC Card (CCS=0) uses byte unit address,
+ * SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit).
+ */
+ if (sd_mmc_card->type & CARD_TYPE_HC) {
+ arg = start;
+ } else {
+ arg = (start * SD_MMC_BLOCK_SIZE);
+ }
+
+ if (!sd_mmc_card->iface->adtc_start(cmd, arg, SD_MMC_BLOCK_SIZE, nb_block, true)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ // Check response
+ if (!sd_mmc_card->iface->is_spi) {
+ resp = sd_mmc_card->iface->get_response();
+ if (resp & CARD_STATUS_ERR_RD_WR) {
+ sd_mmc_debug("%s: Read blocks %02d resp32 0x%08x CARD_STATUS_ERR_RD_WR\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), resp);
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ }
+ sd_mmc_nb_block_remaining = nb_block;
+ sd_mmc_nb_block_to_tranfer = nb_block;
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sd_mmc_start_read_blocks(void *dest, uint16_t nb_block)
+{
+ Assert(sd_mmc_nb_block_remaining >= nb_block);
+
+ if (!sd_mmc_card->iface->start_read_blocks(dest, nb_block)) {
+ sd_mmc_nb_block_remaining = 0;
+ return SD_MMC_ERR_COMM;
+ }
+ sd_mmc_nb_block_remaining -= nb_block;
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sd_mmc_wait_end_of_read_blocks(bool abort)
+{
+ if (!sd_mmc_card->iface->wait_end_of_read_blocks()) {
+ return SD_MMC_ERR_COMM;
+ }
+ if (abort) {
+ sd_mmc_nb_block_remaining = 0;
+ } else if (sd_mmc_nb_block_remaining) {
+ return SD_MMC_OK;
+ }
+
+ // All blocks are transfered then stop read operation
+ if (sd_mmc_nb_block_to_tranfer == 1) {
+ // Single block transfer, then nothing to do
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+ }
+ // WORKAROUND for no compliance card (Atmel Internal ref. !MMC7 !SD19):
+ // The errors on this command must be ignored
+ // and one retry can be necessary in SPI mode for no compliance card.
+ if (!sd_mmc_card->iface->adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0)) {
+ sd_mmc_card->iface->adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0);
+ }
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sd_mmc_init_write_blocks(uint8_t slot, uint32_t start, uint16_t nb_block)
+{
+ sd_mmc_err_t sd_mmc_err;
+ uint32_t cmd, arg, resp;
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+ if (sd_mmc_is_write_protected(slot)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_WP;
+ }
+
+ if (nb_block > 1) {
+ cmd = SDMMC_CMD25_WRITE_MULTIPLE_BLOCK;
+ } else {
+ cmd = SDMMC_CMD24_WRITE_BLOCK;
+ }
+ /*
+ * SDSC Card (CCS=0) uses byte unit address,
+ * SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit).
+ */
+ if (sd_mmc_card->type & CARD_TYPE_HC) {
+ arg = start;
+ } else {
+ arg = (start * SD_MMC_BLOCK_SIZE);
+ }
+ if (!sd_mmc_card->iface->adtc_start(cmd, arg, SD_MMC_BLOCK_SIZE, nb_block, true)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ // Check response
+ if (!sd_mmc_card->iface->is_spi) {
+ resp = sd_mmc_card->iface->get_response();
+ if (resp & CARD_STATUS_ERR_RD_WR) {
+ sd_mmc_debug("%s: Write blocks %02d r1 0x%08x CARD_STATUS_ERR_RD_WR\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), resp);
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ }
+ sd_mmc_nb_block_remaining = nb_block;
+ sd_mmc_nb_block_to_tranfer = nb_block;
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sd_mmc_start_write_blocks(const void *src, uint16_t nb_block)
+{
+ Assert(sd_mmc_nb_block_remaining >= nb_block);
+ if (!sd_mmc_card->iface->start_write_blocks(src, nb_block)) {
+ sd_mmc_nb_block_remaining = 0;
+ return SD_MMC_ERR_COMM;
+ }
+ sd_mmc_nb_block_remaining -= nb_block;
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sd_mmc_wait_end_of_write_blocks(bool abort)
+{
+ if (!sd_mmc_card->iface->wait_end_of_write_blocks()) {
+ return SD_MMC_ERR_COMM;
+ }
+ if (abort) {
+ sd_mmc_nb_block_remaining = 0;
+ } else if (sd_mmc_nb_block_remaining) {
+ return SD_MMC_OK;
+ }
+
+ // All blocks are transfered then stop write operation
+ if (sd_mmc_nb_block_to_tranfer == 1) {
+ // Single block transfer, then nothing to do
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+ }
+
+ if (!sd_mmc_card->iface->is_spi) {
+ // Note: SPI multi block writes terminate using a special
+ // token, not a STOP_TRANSMISSION request.
+ if (!sd_mmc_card->iface->adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ }
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+
+#ifdef SDIO_SUPPORT_ENABLE
+sd_mmc_err_t sdio_read_direct(uint8_t slot, uint8_t func_num, uint32_t addr,
+ uint8_t *dest)
+{
+ sd_mmc_err_t sd_mmc_err;
+
+ if (dest == NULL) {
+ return SD_MMC_ERR_PARAM;
+ }
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+
+ if (!sdio_cmd52(SDIO_CMD52_READ_FLAG, func_num, addr, 0, dest)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sdio_write_direct(uint8_t slot, uint8_t func_num, uint32_t addr,
+ uint8_t data)
+{
+ sd_mmc_err_t sd_mmc_err;
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+
+ if (!sdio_cmd52(SDIO_CMD52_WRITE_FLAG, func_num, addr, 0, &data)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sdio_read_extended(uint8_t slot, uint8_t func_num, uint32_t addr,
+ uint8_t inc_addr, uint8_t *dest, uint16_t size)
+{
+ sd_mmc_err_t sd_mmc_err;
+
+ if ((size == 0) || (size > 512)) {
+ return SD_MMC_ERR_PARAM;
+ }
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+
+ if (!sdio_cmd53(SDIO_CMD53_READ_FLAG, func_num, addr, inc_addr,
+ size, true)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ if (!sd_mmc_card->iface->start_read_blocks(dest, 1)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ if (!sd_mmc_card->iface->wait_end_of_read_blocks()) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+
+sd_mmc_err_t sdio_write_extended(uint8_t slot, uint8_t func_num, uint32_t addr,
+ uint8_t inc_addr, uint8_t *src, uint16_t size)
+{
+ sd_mmc_err_t sd_mmc_err;
+
+ if ((size == 0) || (size > 512)) {
+ return SD_MMC_ERR_PARAM;
+ }
+
+ sd_mmc_err = sd_mmc_select_slot(slot);
+ if (sd_mmc_err != SD_MMC_OK) {
+ return sd_mmc_err;
+ }
+
+ if (!sdio_cmd53(SDIO_CMD53_WRITE_FLAG, func_num, addr, inc_addr,
+ size, true)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ if (!sd_mmc_card->iface->start_write_blocks(src, 1)) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+ if (!sd_mmc_card->iface->wait_end_of_write_blocks()) {
+ sd_mmc_deselect_slot();
+ return SD_MMC_ERR_COMM;
+ }
+
+ sd_mmc_deselect_slot();
+ return SD_MMC_OK;
+}
+#endif // SDIO_SUPPORT_ENABLE
+
+//! @}
diff --git a/src/Libraries/sd_mmc/sd_mmc.h b/src/Libraries/sd_mmc/sd_mmc.h
new file mode 100644
index 00000000..33e773bf
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc.h
@@ -0,0 +1,317 @@
+/**
+ * \file
+ *
+ * \brief Common SD/MMC stack header file
+ *
+ * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SD_MMC_H_INCLUDED
+#define SD_MMC_H_INCLUDED
+
+#include "compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \ingroup common_memory
+ * \defgroup sd_mmc_stack_group SD/MMC/SDIO common stack
+ *
+ * SD/MMC/SDIO basic APIs used by SD/MMC/SDIO memory
+ * APIs (\ref sd_mmc_stack_mem_group).
+ * Also, it can be used by application which use the SDIO card
+ * or specific application which does not need of File System.
+ *
+ * For usual application which use the SD/MMC card in
+ * memory mode with a file system, please refer to
+ * \ref sd_mmc_stack_mem_group.
+ * @{
+ */
+
+typedef uint8_t sd_mmc_err_t; //!< Type of return error code
+
+//! \name Return error codes
+//! @{
+#define SD_MMC_OK 0 //! No error
+#define SD_MMC_INIT_ONGOING 1 //! Card not initialized
+#define SD_MMC_ERR_NO_CARD 2 //! No SD/MMC card inserted
+#define SD_MMC_ERR_UNUSABLE 3 //! Unusable card
+#define SD_MMC_ERR_SLOT 4 //! Slot unknown
+#define SD_MMC_ERR_COMM 5 //! General communication error
+#define SD_MMC_ERR_PARAM 6 //! Illegal input parameter
+#define SD_MMC_ERR_WP 7 //! Card write protected
+#define SD_MMC_CD_DEBOUNCING 8 //! Waiting for card to settle after CD
+//! @}
+
+typedef uint8_t card_type_t; //!< Type of card type
+
+//! \name Card Types
+//! @{
+#define CARD_TYPE_UNKNOWN (0) //!< Unknown type card
+#define CARD_TYPE_SD (1 << 0) //!< SD card
+#define CARD_TYPE_MMC (1 << 1) //!< MMC card
+#define CARD_TYPE_SDIO (1 << 2) //!< SDIO card
+#define CARD_TYPE_HC (1 << 3) //!< High capacity card
+//! SD combo card (io + memory)
+#define CARD_TYPE_SD_COMBO (CARD_TYPE_SD | CARD_TYPE_SDIO)
+//! @}
+
+typedef uint8_t card_version_t; //!< Type of card version
+
+//! \name Card Versions
+//! @{
+#define CARD_VER_UNKNOWN (0) //! Unknown card version
+#define CARD_VER_SD_1_0 (0x10) //! SD version 1.0 and 1.01
+#define CARD_VER_SD_1_10 (0x1A) //! SD version 1.10
+#define CARD_VER_SD_2_0 (0X20) //! SD version 2.00
+#define CARD_VER_SD_3_0 (0X30) //! SD version 3.0X
+#define CARD_VER_MMC_1_2 (0x12) //! MMC version 1.2
+#define CARD_VER_MMC_1_4 (0x14) //! MMC version 1.4
+#define CARD_VER_MMC_2_2 (0x22) //! MMC version 2.2
+#define CARD_VER_MMC_3 (0x30) //! MMC version 3
+#define CARD_VER_MMC_4 (0x40) //! MMC version 4
+//! @}
+
+//! This SD MMC stack uses the maximum block size authorized (512 bytes)
+#define SD_MMC_BLOCK_SIZE 512
+
+/**
+ * \brief Initialize the SD/MMC stack and low level driver required
+ */
+void sd_mmc_init(const Pin wpPins[], const Pin spiCsPins[]) noexcept;
+
+/** \brief Return the number of slot available
+ *
+ * \return Number of card slot available
+ */
+uint8_t sd_mmc_nb_slot(void) noexcept;
+
+/** \brief Performs a card checks
+ *
+ * \param slot Card slot to use
+ *
+ * \retval SD_MMC_OK Card ready
+ * \retval SD_MMC_INIT_ONGOING Initialization on going
+ * \retval SD_MMC_ERR_NO_CARD Card not present in slot
+ * \retval Other value for error cases, see \ref sd_mmc_err_t
+ */
+sd_mmc_err_t sd_mmc_check(uint8_t slot) noexcept;
+
+/** \brief Get the card type
+ *
+ * \param slot Card slot
+ *
+ * \return Card type (\ref card_type_t)
+ */
+card_type_t sd_mmc_get_type(uint8_t slot) noexcept;
+
+/** \brief Get the card version
+ *
+ * \param slot Card slot
+ *
+ * \return Card version (\ref card_version_t)
+ */
+card_version_t sd_mmc_get_version(uint8_t slot) noexcept;
+
+/** \brief Get the memory capacity
+ *
+ * \param slot Card slot
+ *
+ * \return Capacity (unit KB)
+ */
+uint32_t sd_mmc_get_capacity(uint8_t slot) noexcept;
+
+/** \brief Get the card write protection status
+ *
+ * \param slot Card slot
+ *
+ * \return true, if write protected
+ */
+bool sd_mmc_is_write_protected(uint8_t slot) noexcept;
+
+#if 1 // dc42
+
+// Unmount the card. Must call this to force it to be re-initialised when changing card.
+void sd_mmc_unmount(uint8_t slot) noexcept;
+
+// Get the interface speed in bytes/sec
+uint32_t sd_mmc_get_interface_speed(uint8_t slot) noexcept;
+
+#endif
+
+/**
+ * \brief Initialize the read blocks of data from the card.
+ *
+ * \param slot Card slot to use
+ * \param start Start block number to to read.
+ * \param nb_block Total number of blocks to be read.
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_init_read_blocks(uint8_t slot, uint32_t start, uint16_t nb_block) noexcept;
+
+/**
+ * \brief Start the read blocks of data from the card.
+ *
+ * \param dest Pointer to read buffer.
+ * \param nb_block Number of blocks to be read.
+ *
+ * \return return SD_MMC_OK if started,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_start_read_blocks(void *dest, uint16_t nb_block) noexcept;
+
+/**
+ * \brief Wait the end of read blocks of data from the card.
+ *
+ * \param abort Abort reading process initialized by
+ * \ref sd_mmc_init_read_blocks() after the reading issued by
+ * \ref sd_mmc_start_read_blocks() is done
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_wait_end_of_read_blocks(bool abort) noexcept;
+
+/**
+ * \brief Initialize the write blocks of data
+ *
+ * \param slot Card slot to use
+ * \param start Start block number to be written.
+ * \param nb_block Total number of blocks to be written.
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_init_write_blocks(uint8_t slot, uint32_t start, uint16_t nb_block) noexcept;
+
+/**
+ * \brief Start the write blocks of data
+ *
+ * \param src Pointer to write buffer.
+ * \param nb_block Number of blocks to be written.
+ *
+ * \return return SD_MMC_OK if started,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_start_write_blocks(const void *src, uint16_t nb_block) noexcept;
+
+/**
+ * \brief Wait the end of write blocks of data
+ *
+ * \param abort Abort writing process initialized by
+ * \ref sd_mmc_init_write_blocks() after the writing issued by
+ * \ref sd_mmc_start_write_blocks() is done
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sd_mmc_wait_end_of_write_blocks(bool abort) noexcept;
+
+#ifdef SDIO_SUPPORT_ENABLE
+/**
+ * \brief Read one byte from SDIO using RW_DIRECT command.
+ *
+ * \param slot Card slot to use
+ * \param func_num Function number.
+ * \param addr Register address to read from.
+ * \param dest Pointer to read buffer.
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sdio_read_direct(uint8_t slot, uint8_t func_num, uint32_t addr, uint8_t *dest) noexcept;
+/**
+ * \brief Write one byte to SDIO using RW_DIRECT command.
+ *
+ * \param slot Card slot to use
+ * \param func_num Function number.
+ * \param addr Register address to read from.
+ * \param data Data to be written.
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sdio_write_direct(uint8_t slot, uint8_t func_num, uint32_t addr, uint8_t data) noexcept;
+
+/**
+ * \brief Read bytes from SDIO using RW_EXTENDED command.
+ *
+ * \param slot Card slot to use
+ * \param func_num Function number.
+ * \param addr First register address to read from.
+ * \param inc_addr 0 - The data address is fixed.
+ * 1 - The data address increase automatically.
+ * \param dest Pointer to read buffer.
+ * \param size Number of bytes to read (1 ~ 512).
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sdio_read_extended(uint8_t slot, uint8_t func_num, uint32_t addr, uint8_t inc_addr, uint8_t *dest, uint16_t size) noexcept;
+
+/**
+ * \brief Write bytes to SDIO using RW_EXTENDED command.
+ *
+ * \param slot Card slot to use
+ * \param func_num Function number.
+ * \param addr First register address to write to.
+ * \param inc_addr 0 - The data address is fixed.
+ * 1 - The data address increase automatically.
+ * \param src Pointer to write buffer.
+ * \param size Number of bytes to read (1 ~ 512).
+ *
+ * \return return SD_MMC_OK if success,
+ * otherwise return an error code (\ref sd_mmc_err_t).
+ */
+sd_mmc_err_t sdio_write_extended(uint8_t slot, uint8_t func_num, uint32_t addr, uint8_t inc_addr, uint8_t *src, uint16_t size) noexcept;
+#endif // SDIO_SUPPORT_ENABLE
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SD_MMC_H_INCLUDED */
diff --git a/src/Libraries/sd_mmc/sd_mmc_mem.c b/src/Libraries/sd_mmc/sd_mmc_mem.c
new file mode 100644
index 00000000..24912d7c
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc_mem.c
@@ -0,0 +1,138 @@
+/**
+ * \file
+ *
+ * \brief CTRL_ACCESS interface for common SD/MMC stack
+ *
+ * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "Core.h"
+#include "sd_mmc.h"
+#include "sd_mmc_mem.h"
+
+/**
+ * \ingroup sd_mmc_stack_mem
+ * \defgroup sd_mmc_stack_mem_internal Implementation of SD/MMC Memory
+ * @{
+ */
+
+/**
+ * \name Control Interface
+ * @{
+ */
+
+Ctrl_status sd_mmc_test_unit_ready(uint8_t slot)
+{
+ switch (sd_mmc_check(slot))
+ {
+ case SD_MMC_OK:
+ if (sd_mmc_get_type(slot) & (CARD_TYPE_SD | CARD_TYPE_MMC)) {
+ return CTRL_GOOD;
+ }
+ // It is not a memory card
+ return CTRL_NO_PRESENT;
+
+ case SD_MMC_INIT_ONGOING:
+ return CTRL_BUSY;
+
+ case SD_MMC_ERR_NO_CARD:
+ return CTRL_NO_PRESENT;
+
+ default:
+ return CTRL_FAIL;
+ }
+}
+
+Ctrl_status sd_mmc_read_capacity(uint8_t slot, uint32_t *nb_sector)
+{
+ // Return last sector address (-1)
+ *nb_sector = (sd_mmc_get_capacity(slot) * 2) - 1;
+ return sd_mmc_test_unit_ready(slot);
+}
+
+bool sd_mmc_wr_protect(uint8_t slot)
+{
+ return sd_mmc_is_write_protected(slot);
+}
+
+/**
+ * \name MEM <-> RAM Interface
+ * @{
+ */
+Ctrl_status sd_mmc_mem_2_ram(uint8_t slot, uint32_t addr, void *ram, uint32_t numBlocks)
+{
+ switch (sd_mmc_init_read_blocks(slot, addr, numBlocks)) {
+ case SD_MMC_OK:
+ break;
+ case SD_MMC_ERR_NO_CARD:
+ return CTRL_NO_PRESENT;
+ default:
+ return CTRL_FAIL;
+ }
+ if (SD_MMC_OK != sd_mmc_start_read_blocks(ram, numBlocks)) {
+ return CTRL_FAIL;
+ }
+ if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) {
+ return CTRL_FAIL;
+ }
+ return CTRL_GOOD;
+}
+
+Ctrl_status sd_mmc_ram_2_mem(uint8_t slot, uint32_t addr, const void *ram, uint32_t numBlocks)
+{
+ switch (sd_mmc_init_write_blocks(slot, addr, numBlocks)) {
+ case SD_MMC_OK:
+ break;
+ case SD_MMC_ERR_NO_CARD:
+ return CTRL_NO_PRESENT;
+ default:
+ return CTRL_FAIL;
+ }
+ if (SD_MMC_OK != sd_mmc_start_write_blocks(ram, numBlocks)) {
+ return CTRL_FAIL;
+ }
+ if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks(false)) {
+ return CTRL_FAIL;
+ }
+ return CTRL_GOOD;
+}
+
+// End
diff --git a/src/Libraries/sd_mmc/sd_mmc_mem.h b/src/Libraries/sd_mmc/sd_mmc_mem.h
new file mode 100644
index 00000000..2554ae5d
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc_mem.h
@@ -0,0 +1,127 @@
+/**
+ * \file
+ *
+ * \brief CTRL_ACCESS interface for common SD/MMC stack
+ *
+ * Copyright (c) 2012 - 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _SD_MMC_MEM_H_
+#define _SD_MMC_MEM_H_
+
+/**
+ * \ingroup sd_mmc_stack_group
+ * \defgroup sd_mmc_stack_mem SD/MMC Memory
+ *
+ * SD/MMC memory APIs required by CTRL_ACCESS module
+ * (\ref group_common_services_storage_ctrl_access).
+ *
+ * For usual application which use the SD/MMC card in
+ * memory mode through a file system or a USB device MSC,
+ * only a call of \ref sd_mmc_init() function is required in the startup.
+ *
+ * @{
+ */
+
+#include "ctrl_access.h"
+
+/*! \name Control Interface
+ */
+//! @{
+
+/*! \brief Tests the memory state and initializes the memory if required.
+ *
+ * The TEST UNIT READY SCSI primary command allows an application client to poll
+ * a LUN until it is ready without having to allocate memory for returned data.
+ *
+ * This command may be used to check the media status of LUNs with removable
+ * media.
+ *
+ * \param slot SD/MMC Slot Card Selected.
+ *
+ * \return Status.
+ */
+extern Ctrl_status sd_mmc_test_unit_ready(uint8_t slot) noexcept;
+
+/*! \brief Returns the address of the last valid sector in the memory.
+ *
+ * \param slot SD/MMC Slot Card Selected.
+ * \param u32_nb_sector Pointer to the address of the last valid sector.
+ *
+ * \return Status.
+ */
+extern Ctrl_status sd_mmc_read_capacity(uint8_t slot,uint32_t *u32_nb_sector) noexcept;
+
+/*! \brief Returns the write-protection state of the memory.
+ *
+* \param slot SD/MMC Slot Card Selected.
+ * \return \c true if the memory is write-protected, else \c false.
+ *
+ * \note Only used by removable memories with hardware-specific write
+ * protection.
+ */
+extern bool sd_mmc_wr_protect(uint8_t slot) noexcept;
+
+
+/*! \name MEM <-> RAM Interface
+ */
+//! @{
+
+/*! \brief Copies 1 data sector from the memory to RAM.
+ *
+ * \param slot SD/MMC Slot Card Selected.
+ * \param addr Address of first memory sector to read.
+ * \param ram Pointer to RAM buffer to write.
+ *
+ * \return Status.
+ */
+extern Ctrl_status sd_mmc_mem_2_ram(uint8_t slot, uint32_t addr, void *ram, uint32_t numBlocks) noexcept;
+
+/*! \brief Copies 1 data sector from RAM to the memory.
+ *
+ * \param slot SD/MMC Slot Card Selected.
+ * \param addr Address of first memory sector to write.
+ * \param ram Pointer to RAM buffer to read.
+ *
+ * \return Status.
+ */
+extern Ctrl_status sd_mmc_ram_2_mem(uint8_t slot, uint32_t addr, const void *ram, uint32_t numBlocks) noexcept;
+
+//! @}
+
+#endif // _SD_MMC_MEM_H_
diff --git a/src/Libraries/sd_mmc/sd_mmc_protocol.h b/src/Libraries/sd_mmc/sd_mmc_protocol.h
new file mode 100644
index 00000000..c6f6b7df
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc_protocol.h
@@ -0,0 +1,1012 @@
+/**
+ * \file
+ *
+ * \brief SD/MMC protocol definitions.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SD_MMC_PROTOCOL_H_INCLUDED
+#define SD_MMC_PROTOCOL_H_INCLUDED
+
+#include "compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup sd_mmc_protocol SD/MMC Protocol Definition
+ * \ingroup sd_mmc_stack_group
+ * @{
+ */
+
+// SD/MMC/SDIO default clock frequency for initialization (400KHz)
+#define SDMMC_CLOCK_INIT 400000
+
+
+/**
+ * \name Macros for command definition
+ *
+ * Commands types:
+ * - broadcast commands (bc), no response
+ * - broadcast commands with response (bcr) (Note: No open drain on SD card)
+ * - addressed (point-to-point) commands (ac), no data transfer on DAT lines
+ * - addressed (point-to-point) data transfer commands (adtc), data transfer
+ * on DAT lines
+ *
+ * Specific MMC norms:
+ * CMD1, CMD2 & CMD3 are processed in the open-drain mode.
+ * The CMD line is driven with push-pull drivers.
+ *
+ * Specific SD norms:
+ * There is no open drain mode in SD memory card.
+ *
+ ***************************************
+ * Responses types:
+ *
+ * R1, R3, R4 & R5 use a 48 bits response protected by a 7bit CRC checksum
+ * - R1 receiv data not specified
+ * - R3 receiv OCR
+ * - R4, R5 RCA management (MMC only)
+ * - R6, R7 RCA management (SD only)
+ *
+ * R1b assert the BUSY signal and respond with R1.
+ * If the busy signal is asserted, it is done two clock cycles (Nsr time)
+ * after the end bit of the command. The DAT0 line is driven low.
+ * DAT1-DAT7 lines are driven by the card though their values are not relevant.
+ *
+ * R2 use a 136 bits response protected by a 7bit CRC checksum
+ * The content is CID or CSD
+ *
+ * Specific MMC norms:
+ * - R4 (Fast I/O) return RCA
+ * - R5 (interrupt request) return RCA null
+ *
+ * Specific SD norms:
+ * - R6 (Published RCA) return RCA
+ * - R7 (Card interface condition) return RCA null
+ *
+ * @{
+ */
+
+/****************************************** WARNING **********************************************
+ * There is a copy of this file in project CoreNG because it is #included by the HSMCI driver
+ * So beware of changing this file, they must be kept in step!
+ *************************************************************************************************/
+
+//! Value to define a SD/MMC/SDIO command
+typedef uint32_t sdmmc_cmd_def_t;
+
+//! \name Flags used to define a SD/MMC/SDIO command
+//! @{
+#define SDMMC_CMD_GET_INDEX(cmd) (cmd & 0x3F)
+//! Have response (MCI only)
+#define SDMMC_RESP_PRESENT (1lu << 8)
+//! 8 bit response (SPI only)
+#define SDMMC_RESP_8 (1lu << 9)
+//! 32 bit response (SPI only)
+#define SDMMC_RESP_32 (1lu << 10)
+//! 136 bit response (MCI only)
+#define SDMMC_RESP_136 (1lu << 11)
+//! Expect valid crc (MCI only)
+#define SDMMC_RESP_CRC (1lu << 12)
+//! Card may send busy
+#define SDMMC_RESP_BUSY (1lu << 13)
+// Open drain for a braodcast command (bc)
+// or to enter in inactive state (MCI only)
+#define SDMMC_CMD_OPENDRAIN (1lu << 14)
+//! To signal a data write operation
+#define SDMMC_CMD_WRITE (1lu << 15)
+//! To signal a SDIO tranfer in multi byte mode
+#define SDMMC_CMD_SDIO_BYTE (1lu << 16)
+//! To signal a SDIO tranfer in block mode
+#define SDMMC_CMD_SDIO_BLOCK (1lu << 17)
+//! To signal a data transfer in stream mode
+#define SDMMC_CMD_STREAM (1lu << 18)
+//! To signal a data transfer in single block mode
+#define SDMMC_CMD_SINGLE_BLOCK (1lu << 19)
+//! To signal a data transfer in multi block mode
+#define SDMMC_CMD_MULTI_BLOCK (1lu << 20)
+//! @}
+
+//! \name Set of flags to define a reponse type
+//! @{
+#define SDMMC_CMD_NO_RESP (0)
+#define SDMMC_CMD_R1 (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC)
+#define SDMMC_CMD_R1B (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC | SDMMC_RESP_BUSY)
+#define SDMMC_CMD_R2 (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_136 | SDMMC_RESP_CRC)
+#define SDMMC_CMD_R3 (SDMMC_RESP_PRESENT | SDMMC_RESP_32)
+#define SDMMC_CMD_R4 (SDMMC_RESP_PRESENT | SDMMC_RESP_32)
+#define SDMMC_CMD_R5 (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_CRC)
+#define SDMMC_CMD_R6 (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC)
+#define SDMMC_CMD_R7 (SDMMC_RESP_PRESENT | SDMMC_RESP_32 | SDMMC_RESP_CRC)
+//! @}
+
+//! \name SD/MMC/SDIO command definitions
+//! SDMMC_CMDx are include in SD and MMC norms
+//! MMC_CMDx are include in MMC norms only
+//! SD_CMDx are include in SD norms only
+//! SDIO_CMDx are include in SDIO norms only
+//! @{
+
+/*
+ * --- Basic commands and read-stream command (class 0 and class 1) ---
+ */
+
+/** Cmd0(bc): Reset all cards to idle state */
+#define SDMMC_SPI_CMD0_GO_IDLE_STATE (0 | SDMMC_CMD_R1)
+#define SDMMC_MCI_CMD0_GO_IDLE_STATE (0 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN)
+/** MMC Cmd1(bcr, R3): Ask the card to send its Operating Conditions */
+#define MMC_SPI_CMD1_SEND_OP_COND (1 | SDMMC_CMD_R1)
+#define MMC_MCI_CMD1_SEND_OP_COND (1 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN)
+/** Cmd2(bcr, R2): Ask the card to send its CID number (stuff but arg 0 used) */
+#define SDMMC_CMD2_ALL_SEND_CID (2 | SDMMC_CMD_R2 | SDMMC_CMD_OPENDRAIN)
+/** SD Cmd3(bcr, R6): Ask the card to publish a new relative address (RCA) */
+#define SD_CMD3_SEND_RELATIVE_ADDR (3 | SDMMC_CMD_R6 | SDMMC_CMD_OPENDRAIN)
+/** MMC Cmd3(ac, R1): Assigns relative address to the card */
+#define MMC_CMD3_SET_RELATIVE_ADDR (3 | SDMMC_CMD_R1)
+/** Cmd4(bc): Program the DSR of all cards (MCI only) */
+#define SDMMC_CMD4_SET_DSR (4 | SDMMC_CMD_NO_RESP)
+/** MMC Cmd5(ac, R1b): Toggle the card between Sleep state and Standby state. */
+#define MMC_CMD5_SLEEP_AWAKE (5 | SDMMC_CMD_R1B)
+/** Cmd7(ac, R1/R1b): Select/Deselect card
+ * For SD: R1b only from the selected card.
+ * For MMC: R1 while selecting from Stand-By State to Transfer State;
+ * R1b while selecting from Disconnected State to Programming State.
+ */
+#define SDMMC_CMD7_SELECT_CARD_CMD (7 | SDMMC_CMD_R1B)
+#define SDMMC_CMD7_DESELECT_CARD_CMD (7 | SDMMC_CMD_R1)
+/** MMC Cmd8(adtc, R1): Send EXT_CSD register as a block of data */
+#define MMC_CMD8_SEND_EXT_CSD (8 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
+/** SD Cmd8(bcr, R7) : Send SD Memory Card interface condition */
+#define SD_CMD8_SEND_IF_COND (8 | SDMMC_CMD_R7 | SDMMC_CMD_OPENDRAIN)
+/** Cmd9 SPI (R1): Addressed card sends its card-specific data (CSD) */
+#define SDMMC_SPI_CMD9_SEND_CSD (9 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
+/** Cmd9 MCI (ac, R2): Addressed card sends its card-specific data (CSD) */
+#define SDMMC_MCI_CMD9_SEND_CSD (9 | SDMMC_CMD_R2)
+/** Cmd10(ac, R2): Addressed card sends its card identification (CID) */
+#define SDMMC_CMD10_SEND_CID (10 | SDMMC_CMD_R2)
+/**
+ * MMC Cmd11(adtc, R1): Read data stream from the card, starting at the given
+ * address, until a STOP_TRANSMISSION follows.
+ */
+#define MMC_CMD11_READ_DAT_UNTIL_STOP (11 | SDMMC_CMD_R1)
+/* SD Cmd11 MCI (ac, R1): Voltage switching */
+#define SD_CMD11_READ_DAT_UNTIL_STOP (11 | SDMMC_CMD_R1)
+/** Cmd12(ac, R1b): Force the card to stop transmission */
+#define SDMMC_CMD12_STOP_TRANSMISSION (12 | SDMMC_CMD_R1B)
+/** Cmd13(R2): Addressed card sends its status register. */
+#define SDMMC_SPI_CMD13_SEND_STATUS (13 | SDMMC_CMD_R2)
+/** Cmd13(ac, R1): Addressed card sends its status register. */
+#define SDMMC_MCI_CMD13_SEND_STATUS (13 | SDMMC_CMD_R1)
+/** MMC Cmd14(adtc, R1): Read the reversed bus testing data pattern from a card. */
+#define MMC_CMD14_BUSTEST_R (14 | SDMMC_CMD_R1)
+/** Cmd15(ac): Send an addressed card into the Inactive State. */
+// Note: It is a ac cmd, but it must be send like bc cmd to open drain
+#define SDMMC_CMD15_GO_INACTIVE_STATE (15 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN)
+/** MMC Cmd19(adtc, R1): Send the bus test data pattern */
+#define MMC_CMD19_BUSTEST_W (19 | SDMMC_CMD_R1)
+/** Cmd58(R3): Reads the OCR register of a card */
+#define SDMMC_SPI_CMD58_READ_OCR (58 | SDMMC_CMD_R3)
+/** Cmd59(R1): Turns the CRC option on or off */
+#define SDMMC_SPI_CMD59_CRC_ON_OFF (59 | SDMMC_CMD_R1)
+
+/*
+ * --- Block-oriented read commands (class 2) ---
+ */
+/** Cmd16(ac, R1): Set the block length (in bytes) */
+#define SDMMC_CMD16_SET_BLOCKLEN (16 | SDMMC_CMD_R1)
+/** Cmd17(adtc, R1): Read single block */
+#define SDMMC_CMD17_READ_SINGLE_BLOCK (17 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
+/** Cmd18(adtc, R1): Read multiple block */
+#define SDMMC_CMD18_READ_MULTIPLE_BLOCK (18 | SDMMC_CMD_R1 | SDMMC_CMD_MULTI_BLOCK)
+
+/*
+ * --- Sequential write commands (class 3) ---
+ */
+
+/**
+ * MMC Cmd20(adtc, R1): Write a data stream from the host, starting at the
+ * given address, until a STOP_TRANSMISSION follows.
+ */
+#define MMC_CMD20_WRITE_DAT_UNTIL_STOP (20 | SDMMC_CMD_R1)
+
+/*
+ * --- Block-oriented write commands (class 4) ---
+ */
+/** MMC Cmd23(ac, R1): Set block count */
+#define MMC_CMD23_SET_BLOCK_COUNT (23 | SDMMC_CMD_R1)
+/** Cmd24(adtc, R1): Write block */
+#define SDMMC_CMD24_WRITE_BLOCK (24 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_SINGLE_BLOCK)
+/** Cmd25(adtc, R1): Write multiple block */
+#define SDMMC_CMD25_WRITE_MULTIPLE_BLOCK (25 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_MULTI_BLOCK)
+/** MMC Cmd26(adtc, R1): Programming of the card identification register. */
+#define MMC_CMD26_PROGRAM_CID (26 | SDMMC_CMD_R1)
+/** Cmd27(adtc, R1): Programming of the programmable bits of the CSD. */
+#define SDMMC_CMD27_PROGRAM_CSD (27 | SDMMC_CMD_R1)
+
+/*
+ * --- Erase commands (class 5) ---
+ */
+/** SD Cmd32(ac, R1): */
+#define SD_CMD32_ERASE_WR_BLK_START (32 | SDMMC_CMD_R1)
+/** SD Cmd33(ac, R1): */
+#define SD_CMD33_ERASE_WR_BLK_END (33 | SDMMC_CMD_R1)
+/** MMC Cmd35(ac, R1): */
+#define MMC_CMD35_ERASE_GROUP_START (35 | SDMMC_CMD_R1)
+/** MMC Cmd36(ac, R1): */
+#define MMC_CMD36_ERASE_GROUP_END (36 | SDMMC_CMD_R1)
+/** Cmd38(ac, R1B): */
+#define SDMMC_CMD38_ERASE (38 | SDMMC_CMD_R1B)
+
+/*
+ * --- Block Oriented Write Protection Commands (class 6) ---
+ */
+/** Cmd28(ac, R1b): Set write protection */
+#define SDMMC_CMD28_SET_WRITE_PROT (28 | SDMMC_CMD_R1B)
+/** Cmd29(ac, R1b): Clr write protection */
+#define SDMMC_CMD29_CLR_WRITE_PROT (29 | SDMMC_CMD_R1B)
+/** Cmd30(adtc, R1b): Send write protection */
+#define SDMMC_CMD30_SEND_WRITE_PROT (30 | SDMMC_CMD_R1)
+
+/*
+ * --- Lock Card (class 7) ---
+ */
+/** Cmd42(adtc, R1): Used to set/reset the password or lock/unlock the card. */
+#define SDMMC_CMD42_LOCK_UNLOCK (42 | SDMMC_CMD_R1)
+
+/*
+ * --- Application-specific commands (class 8) ---
+ */
+/**
+ * Cmd55(ac, R1): Indicate to the card that the next command is an application
+ * specific command rather than a standard command.
+ */
+#define SDMMC_CMD55_APP_CMD (55 | SDMMC_CMD_R1)
+/**
+ * Cmd 56(adtc, R1): Used either to transfer a data block to the card or to get
+ * a data block from the card for general purpose/application specific commands.
+ */
+#define SDMMC_CMD56_GEN_CMD (56 | SDMMC_CMD_R1)
+
+/**
+ * MMC Cmd6(ac, R1b) : Switche the mode of operation of the selected card
+ * or modifies the EXT_CSD registers.
+ */
+#define MMC_CMD6_SWITCH (6 | SDMMC_CMD_R1B)
+/**
+ * SD Cmd6(adtc, R1) : Check switchable function (mode 0)
+ * and switch card function (mode 1).
+ */
+#define SD_CMD6_SWITCH_FUNC (6 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
+/** ACMD6(ac, R1): Define the data bus width */
+#define SD_ACMD6_SET_BUS_WIDTH (6 | SDMMC_CMD_R1)
+/** ACMD13(adtc, R1): Send the SD Status. */
+#define SD_ACMD13_SD_STATUS (13 | SDMMC_CMD_R1)
+/**
+ * ACMD22(adtc, R1): Send the number of the written (with-out errors) write
+ * blocks.
+ */
+#define SD_ACMD22_SEND_NUM_WR_BLOCKS (22 | SDMMC_CMD_R1)
+/**
+ * ACMD23(ac, R1): Set the number of write blocks to be pre-erased before
+ * writing
+ */
+#define SD_ACMD23_SET_WR_BLK_ERASE_COUNT (23 | SDMMC_CMD_R1)
+/**
+ * ACMD41(bcr, R3): Send host capacity support information (HCS) and asks the
+ * accessed card to send its operating condition register (OCR) content
+ * in the response
+ */
+#define SD_MCI_ACMD41_SD_SEND_OP_COND (41 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN)
+/**
+ * ACMD41(R1): Send host capacity support information (HCS) and activates the
+ * card's initilization process
+ */
+#define SD_SPI_ACMD41_SD_SEND_OP_COND (41 | SDMMC_CMD_R1)
+/**
+ * ACMD42(ac, R1): Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on
+ * CD/DAT3 (pin 1) of the card.
+ */
+#define SD_ACMD42_SET_CLR_CARD_DETECT (42 | SDMMC_CMD_R1)
+/** ACMD51(adtc, R1): Read the SD Configuration Register (SCR). */
+#define SD_ACMD51_SEND_SCR (51 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
+
+/*
+ * --- I/O mode commands (class 9) ---
+ */
+/** MMC Cmd39(ac, R4): Used to write and read 8 bit (register) data fields. */
+#define MMC_CMD39_FAST_IO (39 | SDMMC_CMD_R4)
+/** MMC Cmd40(bcr, R5): Set the system into interrupt mode */
+#define MMC_CMD40_GO_IRQ_STATE (40 | SDMMC_CMD_R5 | SDMMC_CMD_OPENDRAIN)
+/** SDIO Cmd5(R4): Send operation condition */
+#define SDIO_CMD5_SEND_OP_COND (5 | SDMMC_CMD_R4 | SDMMC_CMD_OPENDRAIN)
+/** SDIO CMD52(R5): Direct IO read/write */
+#define SDIO_CMD52_IO_RW_DIRECT (52 | SDMMC_CMD_R5)
+/** SDIO CMD53(R5): Extended IO read/write */
+#define SDIO_CMD53_IO_R_BYTE_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE)
+#define SDIO_CMD53_IO_W_BYTE_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE | SDMMC_CMD_WRITE)
+#define SDIO_CMD53_IO_R_BLOCK_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK)
+#define SDIO_CMD53_IO_W_BLOCK_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK | SDMMC_CMD_WRITE)
+//! @}
+//! @}
+
+
+//! \name Macros for command argument definition
+//! @{
+
+ //! \name MMC CMD6 argument structure
+ //! @{
+//! [31:26] Set to 0
+//! [25:24] Access
+#define MMC_CMD6_ACCESS_COMMAND_SET (0lu << 24)
+#define MMC_CMD6_ACCESS_SET_BITS (1lu << 24)
+#define MMC_CMD6_ACCESS_CLEAR_BITS (2lu << 24)
+#define MMC_CMD6_ACCESS_WRITE_BYTE (3lu << 24)
+//! [23:16] Index for Mode Segment
+#define MMC_CMD6_INDEX_CMD_SET (EXT_CSD_CMD_SET_INDEX << 16)
+#define MMC_CMD6_INDEX_CMD_SET_REV (EXT_CSD_CMD_SET_REV_INDEX << 16)
+#define MMC_CMD6_INDEX_POWER_CLASS (EXT_CSD_POWER_CLASS_INDEX << 16)
+#define MMC_CMD6_INDEX_HS_TIMING (EXT_CSD_HS_TIMING_INDEX << 16)
+#define MMC_CMD6_INDEX_BUS_WIDTH (EXT_CSD_BUS_WIDTH_INDEX << 16)
+#define MMC_CMD6_INDEX_ERASED_MEM_CONT (EXT_CSD_ERASED_MEM_CONT_INDEX << 16)
+#define MMC_CMD6_INDEX_BOOT_CONFIG (EXT_CSD_BOOT_CONFIG_INDEX << 16)
+#define MMC_CMD6_INDEX_BOOT_BUS_WIDTH (EXT_CSD_BOOT_BUS_WIDTH_INDEX << 16)
+#define MMC_CMD6_INDEX_ERASE_GROUP_DEF (EXT_CSD_ERASE_GROUP_DEF_INDEX << 16)
+//! [15:8] Value
+#define MMC_CMD6_VALUE_BUS_WIDTH_1BIT (0x0lu << 8)
+#define MMC_CMD6_VALUE_BUS_WIDTH_4BIT (0x1lu << 8)
+#define MMC_CMD6_VALUE_BUS_WIDTH_8BIT (0x2lu << 8)
+#define MMC_CMD6_VALUE_HS_TIMING_ENABLE (0x1lu << 8)
+#define MMC_CMD6_VALUE_HS_TIMING_DISABLE (0x0lu << 8)
+//! [7:3] Set to 0
+//! [2:0] Cmd Set
+ //! @}
+
+ //! \name SD CMD6 argument structure
+ //! @{
+//! CMD6 arg[ 3: 0] function group 1, access mode
+#define SD_CMD6_GRP1_HIGH_SPEED (0x1lu << 0)
+#define SD_CMD6_GRP1_DEFAULT (0x0lu << 0)
+//! CMD6 arg[ 7: 4] function group 2, command system
+#define SD_CMD6_GRP2_NO_INFLUENCE (0xFlu << 4)
+#define SD_CMD6_GRP2_DEFAULT (0x0lu << 4)
+//! CMD6 arg[11: 8] function group 3, 0xF or 0x0
+#define SD_CMD6_GRP3_NO_INFLUENCE (0xFlu << 8)
+#define SD_CMD6_GRP3_DEFAULT (0x0lu << 8)
+//! CMD6 arg[15:12] function group 4, 0xF or 0x0
+#define SD_CMD6_GRP4_NO_INFLUENCE (0xFlu << 12)
+#define SD_CMD6_GRP4_DEFAULT (0x0lu << 12)
+//! CMD6 arg[19:16] function group 5, 0xF or 0x0
+#define SD_CMD6_GRP5_NO_INFLUENCE (0xFlu << 16)
+#define SD_CMD6_GRP5_DEFAULT (0x0lu << 16)
+//! CMD6 arg[23:20] function group 6, 0xF or 0x0
+#define SD_CMD6_GRP6_NO_INFLUENCE (0xFlu << 20)
+#define SD_CMD6_GRP6_DEFAULT (0x0lu << 20)
+//! CMD6 arg[30:24] reserved 0
+//! CMD6 arg[31 ] Mode, 0: Check, 1: Switch
+#define SD_CMD6_MODE_CHECK (0lu << 31)
+#define SD_CMD6_MODE_SWITCH (1lu << 31)
+ //! @}
+
+ //! \name SD CMD8 argument structure
+ //! @{
+#define SD_CMD8_PATTERN 0xAA
+#define SD_CMD8_MASK_PATTERN 0xFF
+#define SD_CMD8_HIGH_VOLTAGE 0x100
+#define SD_CMD8_MASK_VOLTAGE 0xF00
+ //! @}
+
+ //! \name SD ACMD41 arguments
+ //! @{
+#define SD_ACMD41_HCS (1lu << 30) //!< (SD) Host Capacity Support
+ //! @}
+//! @}
+
+
+//! \name SDIO definitions
+//! @{
+
+ //! \name SDIO state (in R5)
+ //! @{
+#define SDIO_R5_COM_CRC_ERROR (1lu << 15) /**< CRC check error */
+#define SDIO_R5_ILLEGAL_COMMAND (1lu << 14) /**< Illegal command */
+#define SDIO_R5_STATE (3lu << 12) /**< SDIO R5 state mask */
+#define SDIO_R5_STATE_DIS (0lu << 12) /**< Disabled */
+#define SDIO_R5_STATE_CMD (1lu << 12) /**< DAT lines free */
+#define SDIO_R5_STATE_TRN (2lu << 12) /**< Transfer */
+#define SDIO_R5_STATE_RFU (3lu << 12) /**< Reserved */
+#define SDIO_R5_ERROR (1lu << 11) /**< General error */
+#define SDIO_R5_FUNC_NUM (1lu << 9) /**< Invalid function number */
+#define SDIO_R5_OUT_OF_RANGE (1lu << 8) /**< Argument out of range */
+#define SDIO_R5_STATUS_ERR (SDIO_R5_ERROR | SDIO_R5_FUNC_NUM \
+ | SDIO_R5_OUT_OF_RANGE) //!< Errro status bits mask
+ //! @}
+
+ //! \name SDIO state (in R6)
+ //! @{
+/** The CRC check of the previous command failed. */
+#define SDIO_R6_COM_CRC_ERROR (1lu << 15)
+/** Command not legal for the card state. */
+#define SDIO_R6_ILLEGAL_COMMAND (1lu << 14)
+/** A general or an unknown error occurred during the operation. */
+#define SDIO_R6_ERROR (1lu << 13)
+/** Status bits mask for SDIO R6 */
+#define SDIO_STATUS_R6 (SDIO_R6_COM_CRC_ERROR \
+ | SDIO_R6_ILLEGAL_COMMAND | SDIO_R6_ERROR)
+ //! @}
+
+ //! \name SDIO CMD52 argument bit offset
+ //! @{
+//! CMD52 arg[ 7: 0] Write data or stuff bits
+#define SDIO_CMD52_WR_DATA 0
+//! CMD52 arg[ 8] Reserved
+#define SDIO_CMD52_STUFF0 8
+//! CMD52 arg[25: 9] Register address
+#define SDIO_CMD52_REG_ADRR 9
+//! CMD52 arg[ 26] Reserved
+#define SDIO_CMD52_STUFF1 26
+//! CMD52 arg[ 27] Read after Write flag
+#define SDIO_CMD52_RAW_FLAG 27
+//! CMD52 arg[30:28] Number of the function
+#define SDIO_CMD52_FUNCTION_NUM 28
+//! CMD52 arg[ 31] Direction, 1:write, 0:read.
+#define SDIO_CMD52_RW_FLAG 31
+# define SDIO_CMD52_READ_FLAG 0
+# define SDIO_CMD52_WRITE_FLAG 1
+ //! @}
+
+ //! \name SDIO CMD53 argument structure
+ //! @{
+/**
+ * [ 8: 0] Byte mode: number of bytes to transfer,
+ * 0 cause 512 bytes transfer.
+ * Block mode: number of blocks to transfer,
+ * 0 set count to infinite.
+ */
+#define SDIO_CMD53_COUNT 0
+//! CMD53 arg[25: 9] Start Address I/O register
+#define SDIO_CMD53_REG_ADDR 9
+//! CMD53 arg[ 26] 1:Incrementing address, 0: fixed
+#define SDIO_CMD53_OP_CODE 26
+//! CMD53 arg[ 27] (Optional) 1:block mode
+#define SDIO_CMD53_BLOCK_MODE 27
+//! CMD53 arg[30:28] Number of the function
+#define SDIO_CMD53_FUNCTION_NUM 28
+//! CMD53 arg[ 31] Direction, 1:WR, 0:RD
+#define SDIO_CMD53_RW_FLAG 31
+# define SDIO_CMD53_READ_FLAG 0
+# define SDIO_CMD53_WRITE_FLAG 1
+ //! @}
+
+ //! \name SDIO Functions
+ //! @{
+#define SDIO_CIA 0 /**< SDIO Function 0 (CIA) */
+#define SDIO_FN0 0 /**< SDIO Function 0 */
+#define SDIO_FN1 1 /**< SDIO Function 1 */
+#define SDIO_FN2 2 /**< SDIO Function 2 */
+#define SDIO_FN3 3 /**< SDIO Function 3 */
+#define SDIO_FN4 4 /**< SDIO Function 4 */
+#define SDIO_FN5 5 /**< SDIO Function 5 */
+#define SDIO_FN6 6 /**< SDIO Function 6 */
+#define SDIO_FN7 7 /**< SDIO Function 7 */
+ //! @}
+
+ //! \name SDIO Card Common Control Registers (CCCR)
+ //! @{
+#define SDIO_CCCR_SDIO_REV 0x00 /**< CCCR/SDIO revision (RO) */
+#define SDIO_CCCR_REV_1_00 (0x0lu << 0) /**< CCCR/FBR Version 1.00 */
+#define SDIO_CCCR_REV_1_10 (0x1lu << 0) /**< CCCR/FBR Version 1.10 */
+#define SDIO_CCCR_REV_2_00 (0x2lu << 0) /**< CCCR/FBR Version 2.00 */
+#define SDIO_CCCR_REV_3_00 (0x3lu << 0) /**< CCCR/FBR Version 3.00 */
+#define SDIO_SDIO_REV_1_00 (0x0lu << 4) /**< SDIO Spec 1.00 */
+#define SDIO_SDIO_REV_1_10 (0x1lu << 4) /**< SDIO Spec 1.10 */
+#define SDIO_SDIO_REV_1_20 (0x2lu << 4) /**< SDIO Spec 1.20(unreleased) */
+#define SDIO_SDIO_REV_2_00 (0x3lu << 4) /**< SDIO Spec Version 2.00 */
+#define SDIO_SDIO_REV_3_00 (0x4lu << 4) /**< SDIO Spec Version 3.00 */
+#define SDIO_CCCR_SD_REV 0x01 /**< SD Spec Revision (RO) */
+#define SDIO_SD_REV_1_01 (0x0lu << 0) /**< SD 1.01 (Mar 2000) */
+#define SDIO_SD_REV_1_10 (0x1lu << 0) /**< SD 1.10 (Oct 2004) */
+#define SDIO_SD_REV_2_00 (0x2lu << 0) /**< SD 2.00 (May 2006) */
+#define SDIO_SD_REV_3_00 (0x3lu << 0) /**< SD 3.00 */
+#define SDIO_CCCR_IOE 0x02 /**< I/O Enable (R/W) */
+#define SDIO_IOE_FN1 (0x1lu << 1) /**< Function 1 Enable/Disable */
+#define SDIO_IOE_FN2 (0x1lu << 2) /**< Function 2 Enable/Disable */
+#define SDIO_IOE_FN3 (0x1lu << 3) /**< Function 3 Enable/Disable */
+#define SDIO_IOE_FN4 (0x1lu << 4) /**< Function 4 Enable/Disable */
+#define SDIO_IOE_FN5 (0x1lu << 5) /**< Function 5 Enable/Disable */
+#define SDIO_IOE_FN6 (0x1lu << 6) /**< Function 6 Enable/Disable */
+#define SDIO_IOE_FN7 (0x1lu << 7) /**< Function 7 Enable/Disable */
+#define SDIO_CCCR_IOR 0x03 /**< I/O Ready (RO) */
+#define SDIO_IOR_FN1 (0x1lu << 1) /**< Function 1 ready */
+#define SDIO_IOR_FN2 (0x1lu << 2) /**< Function 2 ready */
+#define SDIO_IOR_FN3 (0x1lu << 3) /**< Function 3 ready */
+#define SDIO_IOR_FN4 (0x1lu << 4) /**< Function 4 ready */
+#define SDIO_IOR_FN5 (0x1lu << 5) /**< Function 5 ready */
+#define SDIO_IOR_FN6 (0x1lu << 6) /**< Function 6 ready */
+#define SDIO_IOR_FN7 (0x1lu << 7) /**< Function 7 ready */
+#define SDIO_CCCR_IEN 0x04 /**< Int Enable */
+#define SDIO_IENM (0x1lu << 0) /**< Int Enable Master (R/W) */
+#define SDIO_IEN_FN1 (0x1lu << 1) /**< Function 1 Int Enable */
+#define SDIO_IEN_FN2 (0x1lu << 2) /**< Function 2 Int Enable */
+#define SDIO_IEN_FN3 (0x1lu << 3) /**< Function 3 Int Enable */
+#define SDIO_IEN_FN4 (0x1lu << 4) /**< Function 4 Int Enable */
+#define SDIO_IEN_FN5 (0x1lu << 5) /**< Function 5 Int Enable */
+#define SDIO_IEN_FN6 (0x1lu << 6) /**< Function 6 Int Enable */
+#define SDIO_IEN_FN7 (0x1lu << 7) /**< Function 7 Int Enable */
+#define SDIO_CCCR_INT 0x05 /**< Int Pending */
+#define SDIO_INT_FN1 (0x1lu << 1) /**< Function 1 Int pending */
+#define SDIO_INT_FN2 (0x1lu << 2) /**< Function 2 Int pending */
+#define SDIO_INT_FN3 (0x1lu << 3) /**< Function 3 Int pending */
+#define SDIO_INT_FN4 (0x1lu << 4) /**< Function 4 Int pending */
+#define SDIO_INT_FN5 (0x1lu << 5) /**< Function 5 Int pending */
+#define SDIO_INT_FN6 (0x1lu << 6) /**< Function 6 Int pending */
+#define SDIO_INT_FN7 (0x1lu << 7) /**< Function 7 Int pending */
+#define SDIO_CCCR_IOA 0x06 /**< I/O Abort */
+#define SDIO_AS_FN1 (0x1lu << 0) /**< Abort function 1 IO */
+#define SDIO_AS_FN2 (0x2lu << 0) /**< Abort function 2 IO */
+#define SDIO_AS_FN3 (0x3lu << 0) /**< Abort function 3 IO */
+#define SDIO_AS_FN4 (0x4lu << 0) /**< Abort function 4 IO */
+#define SDIO_AS_FN5 (0x5lu << 0) /**< Abort function 5 IO */
+#define SDIO_AS_FN6 (0x6lu << 0) /**< Abort function 6 IO */
+#define SDIO_AS_FN7 (0x7lu << 0) /**< Abort function 7 IO */
+#define SDIO_RES (0x1lu << 3) /**< IO CARD RESET (WO) */
+#define SDIO_CCCR_BUS_CTRL 0x07 /**< Bus Interface Control */
+#define SDIO_BUSWIDTH_1B (0x0lu << 0) /**< 1-bit data bus */
+#define SDIO_BUSWIDTH_4B (0x2lu << 0) /**< 4-bit data bus */
+/** Enable Continuous SPI interrupt (R/W) */
+#define SDIO_BUS_ECSI (0x1lu << 5)
+/** Support Continuous SPI interrupt (RO) */
+#define SDIO_BUS_SCSI (0x1lu << 6)
+/** Connect(0)/Disconnect(1) pull-up on CD/DAT[3] (R/W) */
+#define SDIO_BUS_CD_DISABLE (0x1lu << 7)
+#define SDIO_CCCR_CAP 0x08 /**< Card Capability */
+/** Support Direct Commands during data transfer (RO) */
+#define SDIO_CAP_SDC (0x1lu << 0)
+/** Support Multi-Block (RO) */
+#define SDIO_CAP_SMB (0x1lu << 1)
+/** Support Read Wait (RO) */
+#define SDIO_CAP_SRW (0x1lu << 2)
+/** Support Suspend/Resume (RO) */
+#define SDIO_CAP_SBS (0x1lu << 3)
+/** Support interrupt between blocks of data in 4-bit SD mode (RO) */
+#define SDIO_CAP_S4MI (0x1lu << 4)
+/** Enable interrupt between blocks of data in 4-bit SD mode (R/W) */
+#define SDIO_CAP_E4MI (0x1lu << 5)
+/** Low-Speed Card (RO) */
+#define SDIO_CAP_LSC (0x1lu << 6)
+/** 4-bit support for Low-Speed Card (RO) */
+#define SDIO_CAP_4BLS (0x1lu << 7)
+/** Pointer to CIS (3B, LSB first) */
+#define SDIO_CCCR_CIS_PTR 0x09
+/** Bus Suspend */
+#define SDIO_CCCR_BUS_SUSPEND 0x0C
+/** Bus Status (transfer on DAT[x] lines) (RO) */
+#define SDIO_BS (0x1lu << 0)
+/** Bus Release Request/Status (R/W) */
+#define SDIO_BR (0x1lu << 1)
+#define SDIO_CCCR_FUN_SEL 0x0D /**< Function select */
+#define SDIO_DF (0x1lu << 7) /**< Resume Data Flag (RO) */
+#define SDIO_FS_CIA (0x0lu << 0) /**< Select CIA (function 0) */
+#define SDIO_FS_FN1 (0x1lu << 0) /**< Select Function 1 */
+#define SDIO_FS_FN2 (0x2lu << 0) /**< Select Function 2 */
+#define SDIO_FS_FN3 (0x3lu << 0) /**< Select Function 3 */
+#define SDIO_FS_FN4 (0x4lu << 0) /**< Select Function 4 */
+#define SDIO_FS_FN5 (0x5lu << 0) /**< Select Function 5 */
+#define SDIO_FS_FN6 (0x6lu << 0) /**< Select Function 6 */
+#define SDIO_FS_FN7 (0x7lu << 0) /**< Select Function 7 */
+#define SDIO_FS_MEM (0x8lu << 0) /**< Select memory in combo card */
+#define SDIO_CCCR_EXEC 0x0E /**< Exec Flags (RO) */
+#define SDIO_EXM (0x1lu << 0) /**< Executing status of memory */
+#define SDIO_EX_FN1 (0x1lu << 1) /**< Executing status of func 1 */
+#define SDIO_EX_FN2 (0x1lu << 2) /**< Executing status of func 2 */
+#define SDIO_EX_FN3 (0x1lu << 3) /**< Executing status of func 3 */
+#define SDIO_EX_FN4 (0x1lu << 4) /**< Executing status of func 4 */
+#define SDIO_EX_FN5 (0x1lu << 5) /**< Executing status of func 5 */
+#define SDIO_EX_FN6 (0x1lu << 6) /**< Executing status of func 6 */
+#define SDIO_EX_FN7 (0x1lu << 7) /**< Executing status of func 7 */
+#define SDIO_CCCR_READY 0x0F /**< Ready Flags (RO) */
+#define SDIO_RFM (0x1lu << 0) /**< Ready Flag for memory */
+#define SDIO_RF_FN1 (0x1lu << 1) /**< Ready Flag for function 1 */
+#define SDIO_RF_FN2 (0x1lu << 2) /**< Ready Flag for function 2 */
+#define SDIO_RF_FN3 (0x1lu << 3) /**< Ready Flag for function 3 */
+#define SDIO_RF_FN4 (0x1lu << 4) /**< Ready Flag for function 4 */
+#define SDIO_RF_FN5 (0x1lu << 5) /**< Ready Flag for function 5 */
+#define SDIO_RF_FN6 (0x1lu << 6) /**< Ready Flag for function 6 */
+#define SDIO_RF_FN7 (0x1lu << 7) /**< Ready Flag for function 7 */
+#define SDIO_CCCR_FN0_BLKSIZ 0x10 /**< FN0 Block Size (2B, LSB first) (R/W) */
+#define SDIO_CCCR_POWER 0x12 /**< Power Control */
+#define SDIO_POWER_SMPC (0x1lu << 0) /**< Support Master Power Control*/
+#define SDIO_POWER_EMPC (0x1lu << 1) /**< Enable Master Power Control */
+#define SDIO_CCCR_HS 0x13 /**< High-Speed */
+#define SDIO_SHS (0x1lu << 0) /**< Support High-Speed (RO) */
+#define SDIO_EHS (0x1lu << 1) /**< Enable High-Speed (R/W) */
+ //! @}
+
+ //! \name SDIO Card Metaformat
+ //! @{
+/** Null tuple (PCMCIA 3.1.9) */
+#define SDIO_CISTPL_NULL 0x00
+/** Device tuple (PCMCIA 3.2.2) */
+#define SDIO_CISTPL_DEVICE 0x01
+/** Checksum control (PCMCIA 3.1.1) */
+#define SDIO_CISTPL_CHECKSUM 0x10
+/** Level 1 version (PCMCIA 3.2.10) */
+#define SDIO_CISTPL_VERS_1 0x15
+/** Alternate Language String (PCMCIA 3.2.1) */
+#define SDIO_CISTPL_ALTSTR 0x16
+/** Manufacturer Identification String (PCMCIA 3.2.9) */
+#define SDIO_CISTPL_MANFID 0x20
+/** Function Identification (PCMCIA 3.2.7) */
+#define SDIO_CISTPL_FUNCID 0x21
+/** Function Extensions (PCMCIA 3.2.6) */
+#define SDIO_CISTPL_FUNCE 0x22
+/** Additional information for SDIO (PCMCIA 6.1.2) */
+#define SDIO_CISTPL_SDIO_STD 0x91
+/** Reserved for future SDIO (PCMCIA 6.1.3) */
+#define SDIO_CISTPL_SDIO_EXT 0x92
+/** The End-of-chain Tuple (PCMCIA 3.1.2) */
+#define SDIO_CISTPL_END 0xFF
+ //! @}
+
+//! @}
+
+//! \name CSD, OCR, SCR, Switch status, extend CSD definitions
+//! @{
+
+/**
+ * \brief Macro function to extract a bits field from a large SD MMC register
+ * Used by : CSD, SCR, Switch status
+ */
+static inline uint32_t SDMMC_UNSTUFF_BITS(uint8_t *reg, uint16_t reg_size,
+ uint16_t pos, uint8_t size)
+{
+ uint32_t value;
+ value = reg[((reg_size - pos + 7) / 8) - 1] >> (pos % 8);
+ if (((pos % 8) + size) > 8) {
+ value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 2] << (8 - (pos % 8));
+ }
+ if (((pos % 8) + size) > 16) {
+ value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 3] << (16 - (pos % 8));
+ }
+ if (((pos % 8) + size) > 16) {
+ value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 3] << (16 - (pos % 8));
+ }
+ value &= ((uint32_t)1 << size) - 1;
+ return value;
+}
+
+ //! \name CSD Fields
+ //! @{
+#define CSD_REG_BIT_SIZE 128 //!< 128 bits
+#define CSD_REG_BSIZE (CSD_REG_BIT_SIZE / 8) //!< 16 bytes
+#define CSD_STRUCTURE(csd, pos, size) \
+ SDMMC_UNSTUFF_BITS(csd, CSD_REG_BIT_SIZE, pos, size)
+#define CSD_STRUCTURE_VERSION(csd) CSD_STRUCTURE(csd, 126, 2)
+#define SD_CSD_VER_1_0 0
+#define SD_CSD_VER_2_0 1
+#define MMC_CSD_VER_1_0 0
+#define MMC_CSD_VER_1_1 1
+#define MMC_CSD_VER_1_2 2
+#define CSD_TRAN_SPEED(csd) CSD_STRUCTURE(csd, 96, 8)
+#define SD_CSD_1_0_C_SIZE(csd) CSD_STRUCTURE(csd, 62, 12)
+#define SD_CSD_1_0_C_SIZE_MULT(csd) CSD_STRUCTURE(csd, 47, 3)
+#define SD_CSD_1_0_READ_BL_LEN(csd) CSD_STRUCTURE(csd, 80, 4)
+#define SD_CSD_2_0_C_SIZE(csd) CSD_STRUCTURE(csd, 48, 22)
+#define MMC_CSD_C_SIZE(csd) CSD_STRUCTURE(csd, 62, 12)
+#define MMC_CSD_C_SIZE_MULT(csd) CSD_STRUCTURE(csd, 47, 3)
+#define MMC_CSD_READ_BL_LEN(csd) CSD_STRUCTURE(csd, 80, 4)
+#define MMC_CSD_SPEC_VERS(csd) CSD_STRUCTURE(csd, 122, 4)
+ //! @}
+
+ //! \name OCR Register Fields
+ //! @{
+#define OCR_REG_BSIZE (32 / 8) /**< 32 bits, 4 bytes */
+#define OCR_VDD_170_195 (1lu << 7)
+#define OCR_VDD_20_21 (1lu << 8)
+#define OCR_VDD_21_22 (1lu << 9)
+#define OCR_VDD_22_23 (1lu << 10)
+#define OCR_VDD_23_24 (1lu << 11)
+#define OCR_VDD_24_25 (1lu << 12)
+#define OCR_VDD_25_26 (1lu << 13)
+#define OCR_VDD_26_27 (1lu << 14)
+#define OCR_VDD_27_28 (1lu << 15)
+#define OCR_VDD_28_29 (1lu << 16)
+#define OCR_VDD_29_30 (1lu << 17)
+#define OCR_VDD_30_31 (1lu << 18)
+#define OCR_VDD_31_32 (1lu << 19)
+#define OCR_VDD_32_33 (1lu << 20)
+#define OCR_VDD_33_34 (1lu << 21)
+#define OCR_VDD_34_35 (1lu << 22)
+#define OCR_VDD_35_36 (1lu << 23)
+#define OCR_SDIO_S18R (1lu << 24) /**< Switching to 1.8V Accepted */
+#define OCR_SDIO_MP (1lu << 27) /**< Memory Present */
+#define OCR_SDIO_NF (7lu << 28) /**< Number of I/O Functions */
+#define OCR_ACCESS_MODE_MASK (3lu << 29) /**< (MMC) Access mode mask */
+#define OCR_ACCESS_MODE_BYTE (0lu << 29) /**< (MMC) Byte access mode */
+#define OCR_ACCESS_MODE_SECTOR (2lu << 29) /**< (MMC) Sector access mode */
+#define OCR_CCS (1lu << 30) /**< (SD) Card Capacity Status */
+#define OCR_POWER_UP_BUSY (1lu << 31) /**< Card power up status bit */
+ //! @}
+
+ //! \name SD SCR Register Fields
+ //! @{
+#define SD_SCR_REG_BIT_SIZE 64 //!< 64 bits
+#define SD_SCR_REG_BSIZE (SD_SCR_REG_BIT_SIZE / 8) //!< 8 bytes
+#define SD_SCR_STRUCTURE(scr, pos, size) \
+ SDMMC_UNSTUFF_BITS(scr, SD_SCR_REG_BIT_SIZE, pos, size)
+#define SD_SCR_SCR_STRUCTURE(scr) SD_SCR_STRUCTURE(scr, 60, 4)
+#define SD_SCR_SCR_STRUCTURE_1_0 0
+#define SD_SCR_SD_SPEC(scr) SD_SCR_STRUCTURE(scr, 56, 4)
+#define SD_SCR_SD_SPEC_1_0_01 0
+#define SD_SCR_SD_SPEC_1_10 1
+#define SD_SCR_SD_SPEC_2_00 2
+#define SD_SCR_DATA_STATUS_AFTER_ERASE(scr) SD_SCR_STRUCTURE(scr, 55, 1)
+#define SD_SCR_SD_SECURITY(scr) SD_SCR_STRUCTURE(scr, 52, 3)
+#define SD_SCR_SD_SECURITY_NO 0
+#define SD_SCR_SD_SECURITY_NOTUSED 1
+#define SD_SCR_SD_SECURITY_1_01 2
+#define SD_SCR_SD_SECURITY_2_00 3
+#define SD_SCR_SD_SECURITY_3_00 4
+#define SD_SCR_SD_BUS_WIDTHS(scr) SD_SCR_STRUCTURE(scr, 48, 4)
+#define SD_SCR_SD_BUS_WIDTH_1BITS (1lu << 0)
+#define SD_SCR_SD_BUS_WIDTH_4BITS (1lu << 2)
+#define SD_SCR_SD_SPEC3(scr) SD_SCR_STRUCTURE(scr, 47, 1)
+#define SD_SCR_SD_SPEC_3_00 1
+#define SD_SCR_SD_EX_SECURITY(scr) SD_SCR_STRUCTURE(scr, 43, 4)
+#define SD_SCR_SD_CMD_SUPPORT(scr) SD_SCR_STRUCTURE(scr, 32, 2)
+ //! @}
+
+ //! \name SD Switch Status Fields
+ //! @{
+#define SD_SW_STATUS_BIT_SIZE 512 //!< 512 bits
+#define SD_SW_STATUS_BSIZE (SD_SW_STATUS_BIT_SIZE / 8) //!< 64 bytes
+#define SD_SW_STATUS_STRUCTURE(sd_sw_status, pos, size) \
+ SDMMC_UNSTUFF_BITS(sd_sw_status, SD_SW_STATUS_BIT_SIZE, pos, size)
+#define SD_SW_STATUS_MAX_CURRENT_CONSUMPTION(status) \
+ SD_SW_STATUS_STRUCTURE(status, 496, 16)
+#define SD_SW_STATUS_FUN_GRP6_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 480, 16)
+#define SD_SW_STATUS_FUN_GRP5_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 464, 16)
+#define SD_SW_STATUS_FUN_GRP4_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 448, 16)
+#define SD_SW_STATUS_FUN_GRP3_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 432, 16)
+#define SD_SW_STATUS_FUN_GRP2_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 416, 16)
+#define SD_SW_STATUS_FUN_GRP1_INFO(status) \
+ SD_SW_STATUS_STRUCTURE(status, 400, 16)
+#define SD_SW_STATUS_FUN_GRP6_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 396, 4)
+#define SD_SW_STATUS_FUN_GRP5_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 392, 4)
+#define SD_SW_STATUS_FUN_GRP4_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 388, 4)
+#define SD_SW_STATUS_FUN_GRP3_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 384, 4)
+#define SD_SW_STATUS_FUN_GRP2_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 380, 4)
+#define SD_SW_STATUS_FUN_GRP1_RC(status) \
+ SD_SW_STATUS_STRUCTURE(status, 376, 4)
+#define SD_SW_STATUS_FUN_GRP_RC_ERROR 0xFU
+#define SD_SW_STATUS_DATA_STRUCT_VER(status) \
+ SD_SW_STATUS_STRUCTURE(status, 368, 8)
+#define SD_SW_STATUS_FUN_GRP6_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 352, 16)
+#define SD_SW_STATUS_FUN_GRP5_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 336, 16)
+#define SD_SW_STATUS_FUN_GRP4_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 320, 16)
+#define SD_SW_STATUS_FUN_GRP3_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 304, 16)
+#define SD_SW_STATUS_FUN_GRP2_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 288, 16)
+#define SD_SW_STATUS_FUN_GRP1_BUSY(status) \
+ SD_SW_STATUS_STRUCTURE(status, 272, 16)
+ //! @}
+
+ //! \name Card Status Fields
+ //! @{
+#define CARD_STATUS_APP_CMD (1lu << 5)
+#define CARD_STATUS_SWITCH_ERROR (1lu << 7)
+#define CARD_STATUS_READY_FOR_DATA (1lu << 8)
+#define CARD_STATUS_STATE_IDLE (0lu << 9)
+#define CARD_STATUS_STATE_READY (1lu << 9)
+#define CARD_STATUS_STATE_IDENT (2lu << 9)
+#define CARD_STATUS_STATE_STBY (3lu << 9)
+#define CARD_STATUS_STATE_TRAN (4lu << 9)
+#define CARD_STATUS_STATE_DATA (5lu << 9)
+#define CARD_STATUS_STATE_RCV (6lu << 9)
+#define CARD_STATUS_STATE_PRG (7lu << 9)
+#define CARD_STATUS_STATE_DIS (8lu << 9)
+#define CARD_STATUS_STATE (0xFlu << 9)
+#define CARD_STATUS_ERASE_RESET (1lu << 13)
+#define CARD_STATUS_WP_ERASE_SKIP (1lu << 15)
+#define CARD_STATUS_CIDCSD_OVERWRITE (1lu << 16)
+#define CARD_STATUS_OVERRUN (1lu << 17)
+#define CARD_STATUS_UNERRUN (1lu << 18)
+#define CARD_STATUS_ERROR (1lu << 19)
+#define CARD_STATUS_CC_ERROR (1lu << 20)
+#define CARD_STATUS_CARD_ECC_FAILED (1lu << 21)
+#define CARD_STATUS_ILLEGAL_COMMAND (1lu << 22)
+#define CARD_STATUS_COM_CRC_ERROR (1lu << 23)
+#define CARD_STATUS_UNLOCK_FAILED (1lu << 24)
+#define CARD_STATUS_CARD_IS_LOCKED (1lu << 25)
+#define CARD_STATUS_WP_VIOLATION (1lu << 26)
+#define CARD_STATUS_ERASE_PARAM (1lu << 27)
+#define CARD_STATUS_ERASE_SEQ_ERROR (1lu << 28)
+#define CARD_STATUS_BLOCK_LEN_ERROR (1lu << 29)
+#define CARD_STATUS_ADDRESS_MISALIGN (1lu << 30)
+#define CARD_STATUS_ADDR_OUT_OF_RANGE (1lu << 31)
+
+#define CARD_STATUS_ERR_RD_WR (CARD_STATUS_ADDR_OUT_OF_RANGE \
+ | CARD_STATUS_ADDRESS_MISALIGN \
+ | CARD_STATUS_BLOCK_LEN_ERROR \
+ | CARD_STATUS_WP_VIOLATION \
+ | CARD_STATUS_ILLEGAL_COMMAND \
+ | CARD_STATUS_CC_ERROR \
+ | CARD_STATUS_ERROR)
+ //! @}
+
+ //! \name SD Status Field
+ //! @{
+#define SD_STATUS_BSIZE (512 / 8) /**< 512 bits, 64bytes */
+ //! @}
+
+ //! \name MMC Extended CSD Register Field
+ //! @{
+#define EXT_CSD_BSIZE 512 /**< 512 bytes. */
+/* Below belongs to Properties Segment */
+#define EXT_CSD_S_CMD_SET_INDEX 504lu
+#define EXT_CSD_BOOT_INFO_INDEX 228lu
+#define EXT_CSD_BOOT_SIZE_MULTI_INDEX 226lu
+#define EXT_CSD_ACC_SIZE_INDEX 225lu
+#define EXT_CSD_HC_ERASE_GRP_SIZE_INDEX 224lu
+#define EXT_CSD_ERASE_TIMEOUT_MULT_INDEX 223lu
+#define EXT_CSD_REL_WR_SEC_C_INDEX 222lu
+#define EXT_CSD_HC_WP_GRP_SIZE_INDEX 221lu
+#define EXT_CSD_S_C_VCC_INDEX 220lu
+#define EXT_CSD_S_C_VCCQ_INDEX 219lu
+#define EXT_CSD_S_A_TIMEOUT_INDEX 217lu
+#define EXT_CSD_SEC_COUNT_INDEX 212lu
+#define EXT_CSD_MIN_PERF_W_8_52_INDEX 210lu
+#define EXT_CSD_MIN_PERF_R_8_52_INDEX 209lu
+#define EXT_CSD_MIN_PERF_W_8_26_4_52_INDEX 208lu
+#define EXT_CSD_MIN_PERF_R_8_26_4_52_INDEX 207lu
+#define EXT_CSD_MIN_PERF_W_4_26_INDEX 206lu
+#define EXT_CSD_MIN_PERF_R_4_26_INDEX 205lu
+#define EXT_CSD_PWR_CL_26_360_INDEX 203lu
+#define EXT_CSD_PWR_CL_52_360_INDEX 202lu
+#define EXT_CSD_PWR_CL_26_195_INDEX 201lu
+#define EXT_CSD_PWR_CL_52_195_INDEX 200lu
+#define EXT_CSD_CARD_TYPE_INDEX 196lu
+/* MMC card type */
+# define MMC_CTYPE_26MHZ 0x1
+# define MMC_CTYPE_52MHZ 0x2
+#define EXT_CSD_CSD_STRUCTURE_INDEX 194lu
+#define EXT_CSD_EXT_CSD_REV_INDEX 192lu
+
+/* Below belongs to Mode Segment */
+#define EXT_CSD_CMD_SET_INDEX 191lu
+#define EXT_CSD_CMD_SET_REV_INDEX 189lu
+#define EXT_CSD_POWER_CLASS_INDEX 187lu
+#define EXT_CSD_HS_TIMING_INDEX 185lu
+#define EXT_CSD_BUS_WIDTH_INDEX 183lu
+#define EXT_CSD_ERASED_MEM_CONT_INDEX 181lu
+#define EXT_CSD_BOOT_CONFIG_INDEX 179lu
+#define EXT_CSD_BOOT_BUS_WIDTH_INDEX 177lu
+#define EXT_CSD_ERASE_GROUP_DEF_INDEX 175lu
+ //! @}
+//! @}
+
+
+//! \name Definition for SPI mode only
+//! @{
+
+//! SPI commands start with a start bit "0" and a transmit bit "1"
+#define SPI_CMD_ENCODE(x) (0x40 | (x & 0x3F))
+
+//! \name Register R1 definition for SPI mode
+//! The R1 register is always send after a command.
+//! @{
+#define R1_SPI_IDLE (1lu << 0)
+#define R1_SPI_ERASE_RESET (1lu << 1)
+#define R1_SPI_ILLEGAL_COMMAND (1lu << 2)
+#define R1_SPI_COM_CRC (1lu << 3)
+#define R1_SPI_ERASE_SEQ (1lu << 4)
+#define R1_SPI_ADDRESS (1lu << 5)
+#define R1_SPI_PARAMETER (1lu << 6)
+// R1 bit 7 is always zero, reuse this bit for error
+#define R1_SPI_ERROR (1lu << 7)
+//! @}
+
+//! \name Register R2 definition for SPI mode
+//! The R2 register can be send after R1 register.
+//! @{
+#define R2_SPI_CARD_LOCKED (1lu << 0)
+#define R2_SPI_WP_ERASE_SKIP (1lu << 1)
+#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
+#define R2_SPI_ERROR (1lu << 2)
+#define R2_SPI_CC_ERROR (1lu << 3)
+#define R2_SPI_CARD_ECC_ERROR (1lu << 4)
+#define R2_SPI_WP_VIOLATION (1lu << 5)
+#define R2_SPI_ERASE_PARAM (1lu << 6)
+#define R2_SPI_OUT_OF_RANGE (1lu << 7)
+#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
+//! @}
+
+//! \name Control Tokens in SPI Mode
+//! @{
+ //! \name Tokens used for a read operation
+ //! @{
+#define SPI_TOKEN_SINGLE_MULTI_READ 0xFE
+#define SPI_TOKEN_DATA_ERROR_VALID(token) (((token) & 0xF0) == 0)
+#define SPI_TOKEN_DATA_ERROR_ERRORS (0x0F)
+#define SPI_TOKEN_DATA_ERROR_ERROR (1lu << 0)
+#define SPI_TOKEN_DATA_ERROR_CC_ERROR (1lu << 1)
+#define SPI_TOKEN_DATA_ERROR_ECC_ERROR (1lu << 2)
+#define SPI_TOKEN_DATA_ERROR_OUT_RANGE (1lu << 3)
+ //! @}
+ //! \name Tokens used for a write operation
+ //! @{
+#define SPI_TOKEN_SINGLE_WRITE 0xFE
+#define SPI_TOKEN_MULTI_WRITE 0xFC
+#define SPI_TOKEN_STOP_TRAN 0xFD
+#define SPI_TOKEN_DATA_RESP_VALID(token) \
+ ((((token) & (1 << 4)) == 0) && (((token) & (1 << 0)) == 1))
+#define SPI_TOKEN_DATA_RESP_CODE(token) ((token) & 0x1E)
+#define SPI_TOKEN_DATA_RESP_ACCEPTED (2lu << 1)
+#define SPI_TOKEN_DATA_RESP_CRC_ERR (5lu << 1)
+#define SPI_TOKEN_DATA_RESP_WRITE_ERR (6lu << 1)
+ //! @}
+//! @}
+//! @}
+
+
+//! @} end of sd_mmc_protocol
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SD_MMC_PROTOCOL_H_INCLUDED */
diff --git a/src/Libraries/sd_mmc/sd_mmc_spi.c b/src/Libraries/sd_mmc/sd_mmc_spi.c
new file mode 100644
index 00000000..adcaf662
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc_spi.c
@@ -0,0 +1,629 @@
+/**
+ * \file
+ *
+ * \brief Common SPI interface for SD/MMC stack
+ *
+ * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include <compiler.h>
+#include <status_codes.h>
+#include <board.h>
+#include <string.h>
+#include "Core.h"
+#include "conf_board.h"
+#include "conf_sd_mmc.h"
+#include "sd_mmc_protocol.h"
+#include "sd_mmc_spi.h"
+#include "sd_mmc.h"
+
+#if SD_MMC_SPI_MEM_CNT != 0
+
+/**
+ * \ingroup sd_mmc_stack_spi
+ * \defgroup sd_mmc_stack_spi_internal Common SPI interface for SD/MMC stack
+ * implementation
+ *
+ * @{
+ */
+
+#include <SharedSpi.h>
+
+// Enable debug information for SD/MMC SPI module
+#ifdef SD_MMC_SPI_DEBUG
+extern void debugPrintf(const char* fmt, ...);
+#define sd_mmc_spi_debug(...) debugPrintf(__VA_ARGS__)
+#else
+#define sd_mmc_spi_debug(...)
+#endif
+
+//! Internal global error status
+static sd_mmc_spi_errno_t sd_mmc_spi_err;
+
+//! Slot array of SPI structures
+static struct sspi_device sd_mmc_spi_devices[SD_MMC_SPI_MEM_CNT];
+
+//! 32 bits response of the last command
+static uint32_t sd_mmc_spi_response_32;
+//! Current position (byte) of the transfer started by mci_adtc_start()
+static uint32_t sd_mmc_spi_transfert_pos;
+//! Size block requested by last mci_adtc_start()
+static uint16_t sd_mmc_spi_block_size;
+//! Total number of block requested by last mci_adtc_start()
+static uint16_t sd_mmc_spi_nb_block;
+
+static uint8_t sd_mmc_spi_crc7(uint8_t * buf, uint8_t size);
+static bool sd_mmc_spi_wait_busy(void);
+static bool sd_mmc_spi_start_read_block(void);
+static void sd_mmc_spi_stop_read_block(void);
+static void sd_mmc_spi_start_write_block(void);
+static bool sd_mmc_spi_stop_write_block(void);
+static bool sd_mmc_spi_stop_multiwrite_block(void);
+
+/**
+ * \brief Calculates the CRC7
+ *
+ * \param buf Buffer data to compute
+ * \param size Size of buffer data
+ *
+ * \return CRC7 computed
+ */
+static uint8_t sd_mmc_spi_crc7(uint8_t * buf, uint8_t size)
+{
+ uint8_t crc, value, i;
+
+ crc = 0;
+ while (size--) {
+ value = *buf++;
+ for (i = 0; i < 8; i++) {
+ crc <<= 1;
+ if ((value & 0x80) ^ (crc & 0x80)) {
+ crc ^= 0x09;
+ }
+ value <<= 1;
+ }
+ }
+ crc = (crc << 1) | 1;
+ return crc;
+}
+
+/**
+ * \brief Wait the end of busy on DAT0 line
+ *
+ * \return true if success, otherwise false
+ */
+static bool sd_mmc_spi_wait_busy(void)
+{
+ uint8_t line = 0xFF;
+
+ /* Delay before check busy
+ * Nbr timing minimum = 8 cylces
+ */
+ sspi_read_packet(&line, 1);
+
+ /* Wait end of busy signal
+ * Nec timing: 0 to unlimited
+ * However a timeout is used.
+ * 200 000 * 8 cycles
+ */
+ uint32_t nec_timeout = 200000;
+ sspi_read_packet(&line, 1);
+ do {
+ sspi_read_packet(&line, 1);
+ if (!(nec_timeout--)) {
+ return false;
+ }
+ } while (line != 0xFF);
+ return true;
+}
+
+/**
+ * \brief Sends the correct TOKEN on the line to start a read block transfer
+ *
+ * \return true if success, otherwise false
+ * with a update of \ref sd_mmc_spi_err.
+ */
+static bool sd_mmc_spi_start_read_block(void)
+{
+ uint32_t i;
+ uint8_t token;
+
+ Assert(!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size));
+
+ /* Wait for start data token:
+ * The read timeout is the Nac timing.
+ * Nac must be computed trough CSD values,
+ * or it is 100ms for SDHC / SDXC
+ * Compute the maximum timeout:
+ * Frequency maximum = 25MHz
+ * 1 byte = 8 cycles
+ * 100ms = 312500 x sd_mmc_spi_drv_read_packet() maximum
+ */
+ token = 0;
+ i = 500000;
+ do {
+ if (i-- == 0) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_READ_TIMEOUT;
+ sd_mmc_spi_debug("%s: Read blocks timeout\n\r", __func__);
+ return false;
+ }
+ sspi_read_packet(&token, 1);
+ if (SPI_TOKEN_DATA_ERROR_VALID(token)) {
+ Assert(SPI_TOKEN_DATA_ERROR_ERRORS & token);
+ if (token & (SPI_TOKEN_DATA_ERROR_ERROR
+ | SPI_TOKEN_DATA_ERROR_ECC_ERROR
+ | SPI_TOKEN_DATA_ERROR_CC_ERROR)) {
+ sd_mmc_spi_debug("%s: CRC data error token\n\r", __func__);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_READ_CRC;
+ } else {
+ sd_mmc_spi_debug("%s: Out of range data error token\n\r", __func__);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_OUT_OF_RANGE;
+ }
+ return false;
+ }
+ } while (token != SPI_TOKEN_SINGLE_MULTI_READ);
+
+ return true;
+}
+
+/**
+ * \brief Executed the end of a read block transfer
+ */
+static void sd_mmc_spi_stop_read_block(void)
+{
+ uint8_t crc[2];
+ // Read 16-bit CRC (not cheked)
+ sspi_read_packet(crc, 2);
+}
+
+/**
+ * \brief Sends the correct TOKEN on the line to start a write block transfer
+ */
+static void sd_mmc_spi_start_write_block(void)
+{
+ uint8_t dummy = 0xFF;
+ Assert(!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size));
+ // Delay before start write block:
+ // Nwr timing minimum = 8 cycles
+ sspi_write_packet(&dummy, 1);
+ // Send start token
+ uint8_t token;
+ if (1 == sd_mmc_spi_nb_block) {
+ token = SPI_TOKEN_SINGLE_WRITE;
+ } else {
+ token = SPI_TOKEN_MULTI_WRITE;
+ }
+ sspi_write_packet(&token, 1);
+}
+
+/**
+ * \brief Waits the TOKEN which notify the end of write block transfer
+ *
+ * \return true if success, otherwise false
+ * with a update of \ref sd_mmc_spi_err.
+ */
+static bool sd_mmc_spi_stop_write_block(void)
+{
+ uint8_t resp;
+ uint16_t crc;
+
+ // Send CRC
+ crc = 0xFFFF; /// CRC is disabled in SPI mode
+ sspi_write_packet((uint8_t *)&crc, 2);
+ // Receive data response token
+ sspi_read_packet(&resp, 1);
+ if (!SPI_TOKEN_DATA_RESP_VALID(resp)) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR;
+ sd_mmc_spi_debug("%s: Invalid Data Response Token 0x%x\n\r", __func__, resp);
+ return false;
+ }
+ // Check data response
+ switch (SPI_TOKEN_DATA_RESP_CODE(resp)) {
+ case SPI_TOKEN_DATA_RESP_ACCEPTED:
+ break;
+ case SPI_TOKEN_DATA_RESP_CRC_ERR:
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_CRC;
+ sd_mmc_spi_debug("%s: Write blocks, SD_MMC_SPI_ERR_CRC, resp 0x%x\n\r", __func__, resp);
+ return false;
+ case SPI_TOKEN_DATA_RESP_WRITE_ERR:
+ default:
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE;
+ sd_mmc_spi_debug("%s: Write blocks SD_MMC_SPI_ERR_WR, resp 0x%x\n\r", __func__, resp);
+ return false;
+ }
+ return true;
+}
+
+/**
+ * \brief Executed the end of a multi blocks write transfer
+ *
+ * \return true if success, otherwise false
+ * with a update of \ref sd_mmc_spi_err.
+ */
+static bool sd_mmc_spi_stop_multiwrite_block(void)
+{
+ uint8_t value;
+
+ if (1 == sd_mmc_spi_nb_block) {
+ return true; // Single block write
+ }
+ if (sd_mmc_spi_nb_block > (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size)) {
+ return true; // It is not the End of multi write
+ }
+
+ // Delay before start write block:
+ // Nwr timing minimum = 8 cylces
+ value = 0xFF;
+ sspi_write_packet(&value, 1);
+ // Send stop token
+ value = SPI_TOKEN_STOP_TRAN;
+ sspi_write_packet(&value, 1);
+ // Wait busy
+ if (!sd_mmc_spi_wait_busy()) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_TIMEOUT;
+ sd_mmc_spi_debug("%s: Stop write blocks timeout\n\r", __func__);
+ return false;
+ }
+ return true;
+}
+
+
+//-------------------------------------------------------------------
+//--------------------- PUBLIC FUNCTIONS ----------------------------
+
+#if 1 //dc42
+
+// Get the speed of the SPI SD card interface for reporting purposes, in bytes/sec
+uint32_t spi_mmc_get_speed(void)
+{
+ return SD_MMC_SPI_MAX_CLOCK/8;
+}
+
+static spiIdleFunc_t spiIdleFunc = NULL;
+
+// Set the idle function and return the old one
+spiIdleFunc_t sd_mmc_spi_set_idle_func(spiIdleFunc_t p)
+{
+ spiIdleFunc_t ret = spiIdleFunc;
+ spiIdleFunc = p;
+ return ret;
+}
+
+#endif
+
+sd_mmc_spi_errno_t sd_mmc_spi_get_errno(void)
+{
+ return sd_mmc_spi_err;
+}
+
+void sd_mmc_spi_init(const Pin csPins[SD_MMC_SPI_MEM_CNT])
+{
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+
+ // Initialize SPI interface and enable it
+ for (size_t i = 0; i < SD_MMC_SPI_MEM_CNT; ++i)
+ {
+ sd_mmc_spi_devices[i].csPin = csPins[i];
+ sd_mmc_spi_devices[i].csPolarity = false;
+ sspi_master_init(&sd_mmc_spi_devices[i], 8);
+ }
+}
+
+void sd_mmc_spi_select_device(uint8_t slot, uint32_t clock, uint8_t bus_width, bool high_speed)
+{
+ UNUSED(bus_width);
+ UNUSED(high_speed);
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+
+#ifdef SD_MMC_SPI_MAX_CLOCK
+ if (clock > SD_MMC_SPI_MAX_CLOCK) {
+ clock = SD_MMC_SPI_MAX_CLOCK;
+ }
+#endif
+
+ struct sspi_device *dev = &sd_mmc_spi_devices[slot];
+ dev->spiMode = SPI_MODE_0;
+ dev->clockFrequency = clock;
+ sspi_master_setup_device(dev);
+ sspi_select_device(dev);
+ delayMicroseconds(1);
+}
+
+void sd_mmc_spi_deselect_device(uint8_t slot)
+{
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ sspi_deselect_device(&sd_mmc_spi_devices[slot]);
+ delayMicroseconds(1);
+}
+
+void sd_mmc_spi_send_clock(void)
+{
+ uint8_t i;
+ uint8_t dummy = 0xFF;
+
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ //! Send 80 cycles
+ for (i = 0; i < 10; i++) {
+ sspi_write_packet(&dummy, 1); // 8 cycles
+ }
+}
+
+bool sd_mmc_spi_send_cmd(sdmmc_cmd_def_t cmd, uint32_t arg)
+{
+ return sd_mmc_spi_adtc_start(cmd, arg, 0, 0, false);
+}
+
+bool sd_mmc_spi_adtc_start(sdmmc_cmd_def_t cmd, uint32_t arg,
+ uint16_t block_size, uint16_t nb_block, bool access_block)
+{
+ uint8_t dummy = 0xFF;
+ uint8_t cmd_token[6];
+ uint8_t ncr_timeout;
+ uint8_t r1; //! R1 response
+
+ UNUSED(access_block);
+ Assert(cmd & SDMMC_RESP_PRESENT); // Always a response in SPI mode
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+
+ // Encode SPI command
+ cmd_token[0] = SPI_CMD_ENCODE(SDMMC_CMD_GET_INDEX(cmd));
+ cmd_token[1] = arg >> 24;
+ cmd_token[2] = arg >> 16;
+ cmd_token[3] = arg >> 8;
+ cmd_token[4] = arg;
+ cmd_token[5] = sd_mmc_spi_crc7(cmd_token, 5);
+
+ // 8 cycles to respect Ncs timing
+ // Note: This byte does not include start bit "0",
+ // thus it is ignored by card.
+ sspi_write_packet(&dummy, 1);
+ // Send command
+ sspi_write_packet(cmd_token, sizeof(cmd_token));
+
+ // Wait for response
+ // Two retry will be done to manage the Ncr timing between command and reponse
+ // Ncr: Min. 1x8 clock cycle, Max. 8x8 clock cycles
+ // WORKAROUND for no compliance card (Atmel Internal ref. SD13):
+ r1 = 0xFF;
+ // Ignore first byte because Ncr min. = 8 clock cylces
+ sspi_read_packet(&r1, 1);
+ ncr_timeout = 7;
+ while (1) {
+ sspi_read_packet(&r1, 1); // 8 cycles
+ if ((r1 & R1_SPI_ERROR) == 0) {
+ // Valid R1 response
+ break;
+ }
+ if (--ncr_timeout == 0) {
+ // Here Valid R1 response received
+ sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lX, R1 timeout\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_TIMEOUT;
+ return false;
+ }
+ }
+
+ // Save R1 (Specific to SPI interface) in 32 bit response
+ // The R1_SPI_IDLE bit can be checked by high level
+ sd_mmc_spi_response_32 = r1;
+
+ // Manage error in R1
+ if (r1 & R1_SPI_COM_CRC) {
+ sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%02x, R1_SPI_COM_CRC\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_CRC;
+ return false;
+ }
+ if (r1 & R1_SPI_ILLEGAL_COMMAND) {
+ sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%x, R1 ILLEGAL_COMMAND\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_ILLEGAL_COMMAND;
+ return false;
+ }
+ if (r1 & ~R1_SPI_IDLE) {
+ // Other error
+ sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%x, R1 error\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1);
+ sd_mmc_spi_err = SD_MMC_SPI_ERR;
+ return false;
+ }
+
+ // Manage other responses
+ if (cmd & SDMMC_RESP_BUSY) {
+ if (!sd_mmc_spi_wait_busy()) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_BUSY_TIMEOUT;
+ sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, Busy signal always high\n\r",
+ __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg);
+ return false;
+ }
+ }
+ if (cmd & SDMMC_RESP_8) {
+ sd_mmc_spi_response_32 = 0;
+ sspi_read_packet((uint8_t*) & sd_mmc_spi_response_32, 1);
+ sd_mmc_spi_response_32 = le32_to_cpu(sd_mmc_spi_response_32);
+ }
+ if (cmd & SDMMC_RESP_32) {
+ sspi_read_packet((uint8_t*) & sd_mmc_spi_response_32, 4);
+ sd_mmc_spi_response_32 = be32_to_cpu(sd_mmc_spi_response_32);
+ }
+
+ sd_mmc_spi_block_size = block_size;
+ sd_mmc_spi_nb_block = nb_block;
+ sd_mmc_spi_transfert_pos = 0;
+ return true; // Command complete
+}
+
+uint32_t sd_mmc_spi_get_response(void)
+{
+ return sd_mmc_spi_response_32;
+}
+
+bool sd_mmc_spi_read_word(uint32_t* value)
+{
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ Assert(sd_mmc_spi_nb_block >
+ (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size));
+
+ if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) {
+ // New block
+ if (!sd_mmc_spi_start_read_block()) {
+ return false;
+ }
+ }
+ // Read data
+ sspi_read_packet((uint8_t*)value, 4);
+ *value = le32_to_cpu(*value);
+ sd_mmc_spi_transfert_pos += 4;
+
+ if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) {
+ // End of block
+ sd_mmc_spi_stop_read_block();
+ }
+ return true;
+}
+
+bool sd_mmc_spi_write_word(uint32_t value)
+{
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ Assert(sd_mmc_spi_nb_block >
+ (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size));
+
+ if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) {
+ // New block
+ sd_mmc_spi_start_write_block();
+ }
+
+ // Write data
+ value = cpu_to_le32(value);
+ sspi_write_packet((uint8_t*)&value, 4);
+ sd_mmc_spi_transfert_pos += 4;
+
+ if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) {
+ // End of block
+ if (!sd_mmc_spi_stop_write_block()) {
+ return false;
+ }
+ // Wait busy due to data programmation
+ if (!sd_mmc_spi_wait_busy()) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_TIMEOUT;
+ sd_mmc_spi_debug("%s: Write blocks timeout\n\r", __func__);
+ return false;
+ }
+ }
+ return sd_mmc_spi_stop_multiwrite_block();
+}
+
+bool sd_mmc_spi_start_read_blocks(void *dest, uint16_t nb_block)
+{
+ uint32_t pos;
+
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ pos = 0;
+ while (nb_block--) {
+ Assert(sd_mmc_spi_nb_block >
+ (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size));
+ if (!sd_mmc_spi_start_read_block()) {
+ return false;
+ }
+
+ // Read block
+ sspi_read_packet(&((uint8_t*)dest)[pos], sd_mmc_spi_block_size);
+ pos += sd_mmc_spi_block_size;
+ sd_mmc_spi_transfert_pos += sd_mmc_spi_block_size;
+
+ sd_mmc_spi_stop_read_block();
+ }
+ return true;
+}
+
+bool sd_mmc_spi_wait_end_of_read_blocks(void)
+{
+ return true;
+}
+
+bool sd_mmc_spi_start_write_blocks(const void *src, uint16_t nb_block)
+{
+ uint32_t pos;
+
+ sd_mmc_spi_err = SD_MMC_SPI_NO_ERR;
+ pos = 0;
+ while (nb_block--) {
+ Assert(sd_mmc_spi_nb_block >
+ (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size));
+ sd_mmc_spi_start_write_block();
+
+ // Write block
+ sspi_write_packet(&((uint8_t*)src)[pos], sd_mmc_spi_block_size);
+ pos += sd_mmc_spi_block_size;
+ sd_mmc_spi_transfert_pos += sd_mmc_spi_block_size;
+
+ if (!sd_mmc_spi_stop_write_block()) {
+ return false;
+ }
+ // Do not check busy of last block
+ // but delay it to mci_wait_end_of_write_blocks()
+ if (nb_block) {
+ // Wait busy due to data programmation
+ if (!sd_mmc_spi_wait_busy()) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_TIMEOUT;
+ sd_mmc_spi_debug("%s: Write blocks timeout\n\r", __func__);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool sd_mmc_spi_wait_end_of_write_blocks(void)
+{
+ // Wait busy due to data programmation of last block writed
+ if (!sd_mmc_spi_wait_busy()) {
+ sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_TIMEOUT;
+ sd_mmc_spi_debug("%s: Write blocks timeout\n\r", __func__);
+ return false;
+ }
+ return sd_mmc_spi_stop_multiwrite_block();
+}
+
+//! @}
+
+#endif
+
+// End
diff --git a/src/Libraries/sd_mmc/sd_mmc_spi.h b/src/Libraries/sd_mmc/sd_mmc_spi.h
new file mode 100644
index 00000000..c9c429a1
--- /dev/null
+++ b/src/Libraries/sd_mmc/sd_mmc_spi.h
@@ -0,0 +1,249 @@
+/**
+ * \file
+ *
+ * \brief Common SPI interface for SD/MMC stack
+ *
+ * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SD_MMC_SPI_H_INCLUDED
+#define SD_MMC_SPI_H_INCLUDED
+
+#include "compiler.h"
+#include "sd_mmc_protocol.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \ingroup sd_mmc_stack_group
+ * \defgroup sd_mmc_stack_spi Common SPI interface for SD/MMC stack
+ * @{
+ */
+
+//! Type of return error code
+typedef uint8_t sd_mmc_spi_errno_t;
+
+//! \name Return error codes
+//! @{
+#define SD_MMC_SPI_NO_ERR 0 //! No error
+#define SD_MMC_SPI_ERR 1 //! General or an unknown error
+#define SD_MMC_SPI_ERR_RESP_TIMEOUT 2 //! Timeout during command
+#define SD_MMC_SPI_ERR_RESP_BUSY_TIMEOUT 3 //! Timeout on busy signal of R1B response
+#define SD_MMC_SPI_ERR_READ_TIMEOUT 4 //! Timeout during read operation
+#define SD_MMC_SPI_ERR_WRITE_TIMEOUT 5 //! Timeout during write operation
+#define SD_MMC_SPI_ERR_RESP_CRC 6 //! Command CRC error
+#define SD_MMC_SPI_ERR_READ_CRC 7 //! CRC error during read operation
+#define SD_MMC_SPI_ERR_WRITE_CRC 8 //! CRC error during write operation
+#define SD_MMC_SPI_ERR_ILLEGAL_COMMAND 9 //! Command not supported
+#define SD_MMC_SPI_ERR_WRITE 10 //! Error during write operation
+#define SD_MMC_SPI_ERR_OUT_OF_RANGE 11 //! Data access out of range
+//! @}
+
+
+/** \brief Return the error code of last function
+ *
+ * \return error code
+ */
+sd_mmc_spi_errno_t sd_mmc_spi_get_errno(void) noexcept;
+
+/** \brief Initializes the low level driver
+ *
+ * This enable the clock required and the hardware interface.
+ */
+void sd_mmc_spi_init(const Pin csPins[SD_MMC_SPI_MEM_CNT]) noexcept;
+
+/** \brief Return the maximum bus width of a slot
+ *
+ * \param slot Selected slot
+ *
+ * \return 1, 4 or 8 lines.
+ */
+static __inline__ uint8_t sd_mmc_spi_get_bus_width(uint8_t slot) noexcept
+{
+ UNUSED(slot);
+ return 1;
+}
+
+/** \brief Return the high speed capability of the driver
+ *
+ * \return true, if the high speed is supported
+ */
+static __inline__ bool sd_mmc_spi_is_high_speed_capable(void) noexcept
+{
+ return false;
+}
+
+/**
+ * \brief Select a slot and initialize it
+ *
+ * \param slot Selected slot
+ * \param clock Maximum clock to use (Hz)
+ * \param bus_width Bus width to use (1, 4 or 8)
+ * \param high_speed true, to enable high speed mode
+ */
+void sd_mmc_spi_select_device(uint8_t slot, uint32_t clock, uint8_t bus_width, bool high_speed) noexcept;
+
+/**
+ * \brief Deselect a slot
+ *
+ * \param slot Selected slot
+ */
+void sd_mmc_spi_deselect_device(uint8_t slot) noexcept;
+
+/** \brief Send 74 clock cycles on the line of selected slot
+ * Note: It is required after card plug and before card install.
+ */
+void sd_mmc_spi_send_clock(void) noexcept;
+
+/** \brief Send a command on the selected slot
+ *
+ * \param cmd Command definition
+ * \param arg Argument of the command
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_send_cmd(sdmmc_cmd_def_t cmd, uint32_t arg) noexcept;
+
+/** \brief Return the 32 bits response of the last command
+ *
+ * \return 32 bits response
+ */
+uint32_t sd_mmc_spi_get_response(void) noexcept;
+static __inline__ void sd_mmc_spi_get_response_128(uint8_t *resp) noexcept
+{
+ UNUSED(resp);
+ return;
+}
+
+
+/** \brief Send a adtc command on the selected slot
+ * A adtc command is used for read/write access.
+ *
+ * \param cmd Command definition
+ * \param arg Argument of the command
+ * \param block_size Block size used for the transfer
+ * \param nb_block Total number of block for this transfer
+ * \param access_block if true, the x_read_blocks() and x_write_blocks()
+ * functions must be used after this function.
+ * If false, the mci_read_word() and mci_write_word()
+ * functions must be used after this function.
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_adtc_start(sdmmc_cmd_def_t cmd, uint32_t arg, uint16_t block_size, uint16_t nb_block, bool access_block) noexcept;
+
+/** \brief Send a command to stop a adtc command on the selected slot
+ *
+ * \param cmd Command definition
+ * \param arg Argument of the command
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_adtc_stop(sdmmc_cmd_def_t cmd, uint32_t arg) noexcept;
+
+/** \brief Read a word on the line
+ *
+ * \param value Pointer on a word to fill
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_read_word(uint32_t* value) noexcept;
+
+/** \brief Write a word on the line
+ *
+ * \param value Word to send
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_write_word(uint32_t value) noexcept;
+
+/** \brief Start a read blocks transfer on the line
+ * Note: The driver will use the DMA available to speed up the transfer.
+ *
+ * \param dest Pointer on the buffer to fill
+ * \param nb_block Number of block to transfer
+ *
+ * \return true if started, otherwise false
+ */
+bool sd_mmc_spi_start_read_blocks(void *dest, uint16_t nb_block) noexcept;
+
+/** \brief Wait the end of transfer initiated by mci_start_read_blocks()
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_wait_end_of_read_blocks(void) noexcept;
+
+/** \brief Start a write blocks transfer on the line
+ * Note: The driver will use the DMA available to speed up the transfer.
+ *
+ * \param src Pointer on the buffer to send
+ * \param nb_block Number of block to transfer
+ *
+ * \return true if started, otherwise false
+ */
+bool sd_mmc_spi_start_write_blocks(const void *src, uint16_t nb_block) noexcept;
+
+/** \brief Wait the end of transfer initiated by mci_start_write_blocks()
+ *
+ * \return true if success, otherwise false
+ */
+bool sd_mmc_spi_wait_end_of_write_blocks(void) noexcept;
+
+#if 1 //dc42
+
+// Get the speed of the SPI SD card interface for reporting purposes, in bytes/sec
+uint32_t spi_mmc_get_speed(void) noexcept;
+
+typedef void (*spiIdleFunc_t)(uint32_t, uint32_t) noexcept;
+
+// Set the idle function and return the old one
+spiIdleFunc_t sd_mmc_spi_set_idle_func(spiIdleFunc_t) noexcept;
+
+#endif
+//! @}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SD_MMC_SPI_H_INCLUDED */