diff --git a/STM32F1/libraries/SDIO/SdioF1.cpp b/STM32F1/libraries/SDIO/SdioF1.cpp
new file mode 100644
index 0000000..8957b37
--- /dev/null
+++ b/STM32F1/libraries/SDIO/SdioF1.cpp
@@ -0,0 +1,852 @@
+/* Arduino SdCard Library
+ * Copyright (C) 2016 by William Greiman
+ *
+ * This file is part of the Arduino SdSpiCard Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdSpiCard Library. If not, see
+ * .
+ */
+
+#include "SdioF1.h"
+#include
+#include
+#include
+
+
+#define USE_DEBUG_MODE 0
+#define USE_YIELD 0
+
+//==============================================================================
+//#define SDHC_PROCTL_DTW_4BIT 0x01
+#define CMD8_RETRIES 10
+#define BUSY_TIMEOUT_MILLIS 1500
+//==============================================================================
+#define CMD_RESP_NONE SDIO_CMD_WAIT_NO_RESP
+#define CMD_RESP_R1 SDIO_CMD_WAIT_SHORT_RESP // normal response
+#define CMD_RESP_R1b SDIO_CMD_WAIT_SHORT_RESP // normal response + busy data line (optional)
+#define CMD_RESP_R2 SDIO_CMD_WAIT_LONG_RESP // CID, CSD
+#define CMD_RESP_R3 SDIO_CMD_WAIT_SHORT_RESP // OCR register, response to ACMD41
+#define CMD_RESP_R6 SDIO_CMD_WAIT_SHORT_RESP // published RCA response, response to CMD3
+#define CMD_RESP_R7 SDIO_CMD_WAIT_SHORT_RESP // response to CMD8
+
+#define CMD0_XFERTYP (uint16_t)( CMD0 | CMD_RESP_NONE )
+#define CMD2_XFERTYP (uint16_t)( CMD2 | CMD_RESP_R2 )
+#define CMD3_XFERTYP (uint16_t)( CMD3 | CMD_RESP_R6 )
+#define CMD6_XFERTYP (uint16_t)( CMD6 | CMD_RESP_R1 )
+#define ACMD6_XFERTYP (uint16_t)( ACMD6 | CMD_RESP_R1 )
+#define CMD7_XFERTYP (uint16_t)( CMD7 | CMD_RESP_R1b )
+#define CMD8_XFERTYP (uint16_t)( CMD8 | CMD_RESP_R7 )
+#define CMD9_XFERTYP (uint16_t)( CMD9 | CMD_RESP_R2 )
+#define CMD10_XFERTYP (uint16_t)( CMD10 | CMD_RESP_R2 )
+#define CMD12_XFERTYP (uint16_t)( CMD12 | CMD_RESP_R1b )
+#define CMD13_XFERTYP (uint16_t)( CMD13 | CMD_RESP_R1 )
+#define CMD17_XFERTYP (uint16_t)( CMD17 | CMD_RESP_R1 )
+#define CMD18_XFERTYP (uint16_t)( CMD18 | CMD_RESP_R1 )
+#define ACMD23_XFERTYP (uint16_t)( ACMD23 | CMD_RESP_R1 )
+#define CMD24_XFERTYP (uint16_t)( CMD24 | CMD_RESP_R1 )
+#define CMD25_XFERTYP (uint16_t)( CMD25 | CMD_RESP_R1 )
+#define CMD32_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 )
+#define CMD33_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 )
+#define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b )
+#define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 )
+
+#define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 )
+
+//=============================================================================
+//static void enableGPIO(bool enable);
+//static void enableDmaIrs();
+static void initSDHC(void);
+static bool isBusyCMD13(void);
+static bool isBusyTransferComplete(void);
+//static bool isBusyCommandComplete();
+//static bool isBusyCommandInhibit();
+static bool readReg16(uint32_t xfertyp, void* data);
+//static void setSdclk(uint32_t kHzMax);
+static bool yieldTimeout(bool (*fcn)(void));
+static bool waitDmaStatus(void);
+static bool waitTimeout(bool (*fcn)(void));
+//-----------------------------------------------------------------------------
+#define TRX_RD 0
+#define TRX_WR 1
+static uint8_t m_dir = TRX_RD;
+static bool (*m_busyFcn)() = 0;
+static bool m_initDone = false;
+static uint32_t m_lba; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop
+static uint32_t m_cnt; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop
+static bool m_version2;
+static bool m_highCapacity;
+static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
+static uint32_t m_errorLine = 0;
+static uint32_t m_rca;
+//static volatile bool m_dmaBusy = false;
+static volatile uint32_t m_irqstat;
+static uint32_t m_sdClkKhz = 0;
+static uint32_t m_ocr;
+static cid_t m_cid;
+static csd_t m_csd;
+static uint32_t t = 0;
+//=============================================================================
+/*
+ * Todo Remove this or change it, but rather remove since this can be checked with debugger.
+ */
+#if USE_DEBUG_MODE
+#define DBG_PRINT() { \
+ Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \
+ Serial.print("DMA->LISR: "); Serial.print(SDIO_DMA_DEV->regs->LISR, HEX); \
+ /*Serial.print("DMA->HISR: "); Serial.println(SDIO_DMA_DEV->regs->HISR, HEX);*/ \
+ Serial.print(", DMA->CR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].CR, HEX); \
+ Serial.print(", DMA->NDTR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].NDTR, HEX); \
+ /**/Serial.print(", DMA->PAR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].PAR, HEX); \
+ /**/Serial.print(", DMA->M0AR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].M0AR, HEX); \
+ Serial.print(", DMA->FCR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].FCR, HEX); \
+ \
+ /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \
+ Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \
+ Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \
+ Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \
+ /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \
+ Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \
+ Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \
+ /*delay(1);*/ \
+}
+#define DBG_PIN PD0
+
+#else // USE_DEBUG_MODE
+#define DBG_PRINT()
+#endif // USE_DEBUG_MODE
+
+/*****************************************************************************/
+static void _panic(const char *message, uint32_t code)
+{
+ Serial.print(message); Serial.println(code, HEX);
+ //Block the execution with blinky leds
+ while (1);
+/*
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ //pinMode(BOARD_LED2_PIN, OUTPUT);
+ while (1) {
+ digitalWrite(BOARD_LED_PIN, HIGH);
+ //digitalWrite(BOARD_LED2_PIN, LOW);
+ delay(250);
+ digitalWrite(BOARD_LED_PIN, LOW);
+ //digitalWrite(BOARD_LED2_PIN, HIGH);
+ delay(250);
+ }
+ */
+}
+/*===========================================================================*/
+/*
+ * Todo: Change the DMA parts so it works with F1 DMA, but since yield is disabled, we can ignore it for now.
+*/
+
+#if USE_YIELD
+void yield(void)
+{
+ uint32_t val = SDIO->STA;
+ if ( val & SDIO_STA_TRX_ERROR_FLAGS ) {
+ Serial.print("SDIO ERROR:: SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \
+ Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \
+ Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \
+ Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \
+ Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \
+ Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); \
+ Serial.print(", SDIO->RESP0: "); Serial.println(SDIO->RESP[0], HEX); \
+ if (val & SDIO_STA_STBITERR) Serial.print(" STBITERR");
+ if (val & SDIO_STA_RXOVERR) Serial.print(" RXOVERR");
+ if (val & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR");
+ if (val & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT");
+ if (val & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL");
+ _panic(" - SDIO: Data Transmission Error ", val);
+ }
+
+ val = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ if ( val & DMA_ISR_FEIF ) {
+ val ^= DMA_ISR_FEIF;
+ dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ }
+ if ( val ) {
+ if (val & DMA_ISR_TEIF) Serial.print(" TEIF");
+ if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF");
+ //if (val & DMA_ISR_FEIF) Serial.print(" FEIF");
+ _panic(" - DMA: Data Transmission Error ", val);
+ }
+ //Serial.write('.');
+}
+#endif
+//=============================================================================
+// Error function and macro.
+inline bool setSdErrorCode(uint8_t code, uint32_t line) {
+ m_errorCode = code;
+ m_errorLine = line;
+ return false; // setSdErrorCode
+}
+#define sdError(code) setSdErrorCode(code, __LINE__)
+//=============================================================================
+/* ISR
+void sdhc_isr() {
+ SDHC_IRQSIGEN = 0;
+ m_irqstat = SDHC_IRQSTAT;
+ SDHC_IRQSTAT = m_irqstat;
+ m_dmaBusy = false;
+}*/
+//=============================================================================
+// Static functions.
+//-----------------------------------------------------------------------------
+static bool cardCommand(uint16_t xfertyp, uint32_t arg)
+{
+#if USE_DEBUG_MODE==2
+ Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX);
+#endif
+ uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK
+#if USE_DEBUG_MODE==2
+ Serial.print(", resp: "); Serial.print(resp, HEX);
+ Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX);
+ if ( (xfertyp&SDIO_CMD_WAIT_LONG_RESP)==SDIO_CMD_WAIT_LONG_RESP ) {
+ Serial.print(", "); Serial.print(SDIO->RESP[1], HEX); Serial.print(", "); Serial.print(SDIO->RESP[2], HEX); Serial.print(", "); Serial.println(SDIO->RESP[3], HEX);
+ } else Serial.println();
+#endif
+ return resp; // return non-zero when OK
+}
+//-----------------------------------------------------------------------------
+static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
+ return cardCommand(CMD55_XFERTYP, rca) && cardCommand((uint16_t)xfertyp, arg);
+}
+/*---------------------------------------------------------------------------*/
+static bool cardCMD6(uint32_t arg, uint8_t* status) {
+ // CMD6 returns 64 bytes.
+ // use polling only for the moment
+ if (waitTimeout(isBusyCMD13)) {
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+ // get the 64 bytes over data lines
+ sdio_setup_transfer(80000, 64, (SDIO_BLOCKSIZE_64 | SDIO_DIR_RX | SDIO_DCTRL_DTEN));
+
+ cardCommand(CMD6_XFERTYP, arg);
+
+ // wait data Rx response
+ if (waitTimeout(isBusyTransferComplete)) {
+ return sdError(SD_CARD_ERROR_CMD6);
+ }
+DBG_PRINT();
+ // copy 64 bytes as 16 words from FIFO to buffer
+ for (uint8_t i=0; i<16; i++) {
+ *(uint32_t*)(&status[i<<2]) = SDIO->FIFO;
+ }
+ //SDIO->DCTRL = 0; // disable data controller
+
+#if USE_DEBUG_MODE
+ Serial.print("read data: "); for (uint8_t i=0; i<17; i++) { Serial.print(status[i], HEX); Serial.print(", "); } Serial.println();
+#endif
+return true;
+}
+//-----------------------------------------------------------------------------
+static void initSDHC(void)
+{
+ sdio_begin();
+ DBG_PRINT();
+}
+/*---------------------------------------------------------------------------*/
+static bool isBusyCMD13(void) {
+ if (!cardCommand(CMD13_XFERTYP, m_rca)) { // SEND_STATUS
+ // Caller will timeout.
+ return true;
+ }
+ return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA);
+}
+/*---------------------------------------------------------------------------*/
+static bool isBusyDMA(void)
+{
+ uint8_t isr = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ isr &= DMA_ISR_TCIF | DMA_ISR_TEIF;
+ //if (isr&DMA_ISR_TCIF) dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ return !(isr); // ignore transfer error flag
+}
+/*---------------------------------------------------------------------------*/
+static bool isBusyTransferComplete(void)
+{
+ uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS);
+#if USE_DEBUG_MODE
+ if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) {
+ Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX);
+ if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR");
+ if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR");
+ if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR");
+ if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT");
+ if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL");
+ Serial.println();
+ }
+#endif
+ if (mask) {
+ dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ return false;
+ }
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir)
+{
+ m_dir = dir;
+ uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DTEN);
+ if (dir==TRX_RD) flags |= SDIO_DIR_RX;
+ // setup SDIO to transfer n blocks of 512 bytes
+ sdio_setup_transfer(0x00FFFFFF, n, flags);
+}
+/*---------------------------------------------------------------------------*/
+static bool trxStop()
+{
+ if (!cardCommand(CMD12_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_CMD12);
+ }
+ if ( t ) {
+ Serial.print(", in "); Serial.println(millis()-t);
+ t = 0;
+ }
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir)
+{
+ m_dir = dir;
+ if ((3 & (uint32_t)buf) || n == 0) { // check alignment
+ _panic("- transferStart: unaligned buffer address ", (uint32_t)buf);
+ return sdError(SD_CARD_ERROR_DMA);
+ }
+ if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) {
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+ uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN);
+ if (dir==TRX_RD) flags |= SDIO_DIR_RX;
+ // setup SDIO to transfer n blocks of 512 bytes
+ sdio_setup_transfer(0x00FFFFFF, n, flags);
+ // setup SDIO_DMA_DEV stream 3 channel 4
+ /*
+ * Moved to begin.
+ */
+ //dma_init(SDIO_DMA_DEV);
+ /*
+ * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers
+ */
+ //dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH);
+ flags = (DMA_MINC_MODE);
+ // not extra flag if read
+ if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write
+ dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags);
+ dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item.
+ //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL
+ dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL);
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+static bool dmaTrxEnd(bool multi_block)
+{
+ if ( !waitDmaStatus() ) {
+ DBG_PRINT();
+ return sdError(SD_CARD_ERROR_DMA);
+ }
+ if ( waitTimeout(isBusyTransferComplete) ) {
+ if (m_dir==TRX_RD)
+ return sdError(SD_CARD_ERROR_READ_TIMEOUT);
+ else
+ return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
+ }
+ if (multi_block) {
+ return trxStop();
+ } else {
+ if ( t ) {
+ Serial.print(", in "); Serial.println(millis()-t);
+ t = 0;
+ }
+ return true;
+ }
+}
+//-----------------------------------------------------------------------------
+// Read 16 byte CID or CSD register.
+static bool readReg16(uint32_t xfertyp, void* data)
+{
+ uint8_t* d = reinterpret_cast(data);
+ if (!cardCommand(xfertyp, m_rca)) {
+ return false; // Caller will set errorCode.
+ }
+ *(uint32_t*)(&d[0]) = __builtin_bswap32(SDIO->RESP[0]);
+ *(uint32_t*)(&d[4]) = __builtin_bswap32(SDIO->RESP[1]);
+ *(uint32_t*)(&d[8]) = __builtin_bswap32(SDIO->RESP[2]);
+ *(uint32_t*)(&d[12]) = __builtin_bswap32(SDIO->RESP[3]);
+ d[15] = 0;
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+// Return true if timeout occurs.
+static bool yieldTimeout(bool (*fcn)()) {
+ uint32_t m = millis();
+ while (fcn()) {
+ if ((millis() - m) > BUSY_TIMEOUT_MILLIS) {
+ return true;
+ }
+ yield();
+ }
+ return false; // Caller will set errorCode.
+}
+/*---------------------------------------------------------------------------*/
+static bool waitDmaStatus(void)
+{
+ if (yieldTimeout(isBusyDMA)) {
+ return false; // Caller will set errorCode.
+ }
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+// Return true if timeout occurs.
+static bool waitTimeout(bool (*fcn)(void)) {
+ uint32_t m = millis();
+ while (fcn()) {
+ if ((millis() - m) > BUSY_TIMEOUT_MILLIS) {
+ return true;
+ }
+ delayMicroseconds(1);
+ }
+ return false; // Caller will set errorCode.
+}
+
+uint32_t aligned[128]; // temporary buffer for misaligned buffers
+//=============================================================================
+bool SdioCard::begin(void)
+{
+ m_initDone = false;
+ m_errorCode = SD_CARD_ERROR_NONE;
+ m_highCapacity = false;
+ m_version2 = false;
+
+#if USE_DEBUG_MODE
+pinMode(DBG_PIN, OUTPUT);
+digitalWrite(DBG_PIN, HIGH);
+delay(100);
+#endif
+ // initialize controller.
+ initSDHC();
+
+ // initialize DMA device
+ dma_init(SDIO_DMA_DEV);
+ dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); // Disable DMA in case it was left enabled from a previous use.
+ /*
+ * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers
+ */
+ dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH);
+
+ if (!cardCommand(CMD0_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_CMD0);
+ }
+ // Try several times for case of reset delay.
+ for (uint32_t i = 0; i < CMD8_RETRIES; i++) {
+ if (cardCommand(CMD8_XFERTYP, 0X1AA)) {
+ if (SDIO->RESP[0] != 0X1AA) {
+ return sdError(SD_CARD_ERROR_CMD8);
+ }
+ m_version2 = true;
+ break;
+ }
+ }
+ uint32_t arg = m_version2 ? 0X40300000 : 0x00300000;
+ uint32_t m = millis();
+ do {
+ if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
+ ((millis() - m) > BUSY_TIMEOUT_MILLIS)) {
+ return sdError(SD_CARD_ERROR_ACMD41);
+ }
+ } while ((SDIO->RESP[0] & 0x80000000) == 0);
+
+ m_ocr = SDIO->RESP[0];
+ if (m_ocr & 0x40000000) {
+ // Is high capacity.
+ m_highCapacity = true;
+ }
+ if (!cardCommand(CMD2_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_CMD2);
+ }
+ if (!cardCommand(CMD3_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_CMD3);
+ }
+ m_rca = SDIO->RESP[0] & 0xFFFF0000;
+ if (!readReg16(CMD9_XFERTYP, &m_csd)) {
+ return sdError(SD_CARD_ERROR_CMD9);
+ }
+ if (!readReg16(CMD10_XFERTYP, &m_cid)) {
+ return sdError(SD_CARD_ERROR_CMD10);
+ }
+ if (!cardCommand(CMD7_XFERTYP, m_rca)) {
+ return sdError(SD_CARD_ERROR_CMD7);
+ }
+ // Set card to bus width four.
+ /*
+ if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) {
+ return sdError(SD_CARD_ERROR_ACMD6);
+ }
+ sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT);
+ */
+
+ // Determine if High Speed mode is supported and set frequency.
+ uint8_t status[64];
+ // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13.
+ // Support Bits of Functions in Function Group 1: bits 415:400, which are bytes [12][13]
+ // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16]
+ if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
+ cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
+ //Serial.println("\n*** 50MHz clock supported ***");
+ } else {
+ //_panic("*** Only 25MHz clock supported! ***", 0);
+ }
+
+ /*
+ * Todo Raise clock to 24Mhz once transfers work
+ */
+ m_sdClkKhz = 24000; // set clock to 24MHz
+ sdio_set_clock(m_sdClkKhz*1000);
+
+ m_initDone = true;
+ return true;
+}
+//-----------------------------------------------------------------------------
+uint32_t SdioCard::cardSize(void) {
+ return sdCardCapacity(&m_csd);
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
+ // check for single block erase
+ if (!m_csd.v1.erase_blk_en) {
+ // erase size mask
+ uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
+ if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
+ // error card can't erase specified area
+ return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
+ }
+ }
+ if (!m_highCapacity) {
+ firstBlock <<= 9;
+ lastBlock <<= 9;
+ }
+ if (!cardCommand(CMD32_XFERTYP, firstBlock)) {
+ return sdError(SD_CARD_ERROR_CMD32);
+ }
+ if (!cardCommand(CMD33_XFERTYP, lastBlock)) {
+ return sdError(SD_CARD_ERROR_CMD33);
+ }
+ if (!cardCommand(CMD38_XFERTYP, 0)) {
+ return sdError(SD_CARD_ERROR_CMD38);
+ }
+ if (waitTimeout(isBusyCMD13)) {
+ return sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
+ }
+ return true;
+}
+//-----------------------------------------------------------------------------
+uint8_t SdioCard::errorCode() {
+ return m_errorCode;
+}
+//-----------------------------------------------------------------------------
+uint32_t SdioCard::errorData() {
+ return m_irqstat;
+}
+//-----------------------------------------------------------------------------
+uint32_t SdioCard::errorLine() {
+ return m_errorLine;
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::isBusy() {
+ return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
+}
+//-----------------------------------------------------------------------------
+uint32_t SdioCard::kHzSdClk() {
+ return m_sdClkKhz;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::readBlock(uint32_t lba, uint8_t* buf)
+{
+#if USE_DEBUG_MODE
+ Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX);
+#endif
+ // prepare SDIO and DMA for data read transfer
+ dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD);
+ // send command to start data transfer
+ if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD17);
+ }
+ if ( dmaTrxEnd(0)) {
+ if ( (uint32_t)buf & 3 ) {
+ //memcpy(buf, aligned, 512);
+ register uint8_t * dst = buf;
+ register uint8_t * src = (uint8_t *)aligned;
+ register uint16_t i = 64;
+ while ( i-- ) { // do 8 byte copies, is much faster than single byte copy
+ *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++;
+ *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n)
+{
+#if USE_DEBUG_MODE
+ Serial.print("readBlocks: "); Serial.print(lba);
+ //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX);
+ Serial.print(", "); Serial.println(n);
+#endif
+ if ((uint32_t)buf & 3) {
+ for (size_t i = 0; i < n; i++, lba++, buf += 512) {
+ if (!readBlock(lba, buf)) {
+ return false; // readBlock will set errorCode.
+ }
+ }
+ return true;
+ }
+ // prepare SDIO and DMA for data read transfer
+ dmaTrxStart(buf, 512*n, TRX_RD);
+ // send command to start data transfer
+ if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD18);
+ }
+ return dmaTrxEnd(1);
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::readCID(void* cid) {
+ memcpy(cid, &m_cid, 16);
+ return true;
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::readCSD(void* csd) {
+ memcpy(csd, &m_csd, 16);
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::readData(uint8_t *dst)
+{
+ //Serial.print("readData: "); Serial.print(m_lba); Serial.print(", m_cnt: "); Serial.println(m_cnt);
+ if ( m_cnt==0 ) return false;
+ if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+ // non-DMA block read
+ trxStart(dst, 512, TRX_RD);
+ // send command to start data transfer
+ if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD17);
+ }
+ // Receive a data block from the SDIO
+ register uint32_t STA; // to speed up SDIO flags checking
+ register uint16_t cnt = 512;
+ register uint32_t * ptr = (uint32_t *)dst;
+ // ----> TIME CRITICAL SECTION BEGIN <----
+ do {
+ STA = SDIO->STA;
+ if (STA & SDIO_STA_RXFIFOHF) {
+ // Receive FIFO half full, there are at least 8 words in it
+ noInterrupts();
+ *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO;
+ *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO;
+ interrupts();
+ cnt -= 8;
+ }
+ } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) );
+ // <---- TIME CRITICAL SECTION END ---->
+
+ // read data still available in FIFO
+ while ( (SDIO->STA & SDIO_STA_RXDAVL) && (cnt--) ) {
+ *ptr++ = SDIO->FIFO;
+ }
+ // check error, temporary stuff, remove for final version
+ if ( SDIO->STA & SDIO_STA_TRX_ERROR_FLAGS ) {
+ _panic("ERROR: non-DMA read error ", SDIO->STA);
+ return false;
+ }
+ m_lba++;
+ m_cnt--;
+ return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS);
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::readOCR(uint32_t* ocr) {
+ *ocr = m_ocr;
+ return true;
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::readStart(uint32_t lba)
+{
+ m_lba = lba;
+ m_cnt = 1024;
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+// SDHC will do Auto CMD12 after count blocks.
+bool SdioCard::readStart(uint32_t lba, uint32_t count)
+{
+ //Serial.print("readStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count);
+ m_lba = lba;
+ m_cnt = count;
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::readStop()
+{
+ //Serial.println("readStop.");
+ m_lba = 0;
+ m_cnt = 0;
+ return true;
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::syncBlocks() {
+ return true;
+}
+//-----------------------------------------------------------------------------
+uint8_t SdioCard::type() {
+ return m_version2 ? m_highCapacity ?
+ SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf)
+{
+#if USE_DEBUG_MODE
+ Serial.print("writeBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX);
+#endif
+ uint8_t * ptr = (uint8_t *)buf;
+ if (3 & (uint32_t)ptr) {
+ Serial.print("writeBlock: "); Serial.print(lba);
+ Serial.print(", buf: "); Serial.print((uint32_t)ptr, HEX);
+ //memcpy(aligned, buf, 512);
+ register uint8_t * src = (uint8_t *)ptr;
+ ptr = (uint8_t *)aligned;
+ register uint8_t * dst = ptr;
+ register uint16_t i = 64;
+ while ( i-- ) { // do 8 byte copies, is much faster than single byte copy
+ *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++;
+ *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++;
+ }
+ }
+ if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+ // send command to start data transfer
+ if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD24);
+ }
+ // prepare SDIO and DMA for data transfer
+ dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer
+
+ return dmaTrxEnd(0);
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n)
+{
+#if USE_DEBUG_MODE
+ Serial.print("writeBlocks: "); Serial.print(lba);
+ //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX);
+ Serial.print(", "); Serial.println(n);
+#endif
+ if (3 & (uint32_t)buf) { // misaligned buffer address, write single blocks
+ for (size_t i = 0; i < n; i++, lba++, buf += 512) {
+ if (!writeBlock(lba, buf)) {
+ return false; // writeBlock will set errorCode.
+ }
+ }
+ return true;
+ }
+ if (yieldTimeout(isBusyCMD13)) {
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+#if 0
+ // set number of blocks to write - this can speed up block write
+ if ( !cardAcmd(m_rca, ACMD23_XFERTYP, n) ) {
+ return sdError(SD_CARD_ERROR_ACMD23);
+ }
+#endif
+ // send command to start data transfer
+ if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD25);
+ }
+ // prepare SDIO and DMA for data transfer
+ dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer
+
+ return dmaTrxEnd(1);
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::writeData(const uint8_t* src)
+{
+ //Serial.print("writeData: "); Serial.print(m_lba); Serial.print(", cnt: "); Serial.println(m_cnt);
+ if ( !m_cnt ) return false;
+ if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end
+ return sdError(SD_CARD_ERROR_CMD13);
+ }
+ // send command to start block data transfer
+ if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) {
+ return sdError(SD_CARD_ERROR_CMD24);
+ }
+ // non-DMA block write
+ trxStart((uint8_t*)src, 512, TRX_WR);
+ // Receive a data block from the SDIO
+ register uint32_t STA; // to speed up SDIO flags checking
+ register uint16_t cnt = 512;
+ register uint32_t * ptr = (uint32_t*)src;
+ // pre-fill up the FIFO with 32 words
+ noInterrupts();
+ while ( (cnt--)>(512-32) ) SDIO->FIFO = *ptr++;
+ interrupts();
+ // ----> TIME CRITICAL SECTION BEGIN <----
+ do {
+ STA = SDIO->STA;
+ if (STA & SDIO_STA_TXFIFOHE) {
+ // Transmit FIFO half empty, fill up the remaining 16 words
+ noInterrupts();
+ SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++;
+ SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++;
+ SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++;
+ SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++;
+ interrupts();
+ cnt -= 16;
+ }
+ } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) && cnt);
+ // <---- TIME CRITICAL SECTION END ---->
+ if ( waitTimeout(isBusyTransferComplete) ) {
+ return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
+ }
+ m_lba++;
+ m_cnt--;
+ if (SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS) {
+ _panic("writeData error: ", SDIO->STA);
+ }
+ return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS);
+}
+//-----------------------------------------------------------------------------
+bool SdioCard::writeStart(uint32_t lba)
+{
+ m_lba = lba;
+ m_cnt = 1024;
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+// SDHC will do Auto CMD12 after count blocks.
+bool SdioCard::writeStart(uint32_t lba, uint32_t count)
+{
+ //Serial.print("writeStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count);
+ m_lba = lba;
+ m_cnt = count;
+ return true;
+}
+/*---------------------------------------------------------------------------*/
+bool SdioCard::writeStop()
+{
+ //Serial.println("writeStop.");
+ m_lba = 0;
+ m_cnt = 0;
+ return true;
+}