commit
b4aa24ef82
|
@ -0,0 +1,198 @@
|
|||
/******************************************************************************
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file libmaple/sdio.c
|
||||
* @author stevstrong
|
||||
* @brief Secure digital input/output interface.
|
||||
*/
|
||||
|
||||
#include <libmaple/sdio.h>
|
||||
#include <libmaple/gpio.h>
|
||||
#include <boards.h>
|
||||
#include "wirish.h"
|
||||
|
||||
|
||||
//#include <libmaple/libmaple.h>
|
||||
//#include <libmaple/rcc.h>
|
||||
//#include <series/gpio.h>
|
||||
//#include "wirish.h"
|
||||
//#include "boards.h"
|
||||
//
|
||||
|
||||
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
|
||||
|
||||
sdio_dev * SDIO = SDIO_BASE;
|
||||
|
||||
#define DELAY_LONG 10
|
||||
#define DELAY_SHORT 1
|
||||
|
||||
uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers
|
||||
|
||||
/*
|
||||
* SDIO convenience routines
|
||||
*/
|
||||
void sdio_gpios_init(void)
|
||||
{
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP);
|
||||
/*
|
||||
* Todo just remove it, not needed for F1.
|
||||
*/
|
||||
/*
|
||||
gpio_set_af_mode(BOARD_SDIO_D0, 12);
|
||||
gpio_set_af_mode(BOARD_SDIO_D1, 12);
|
||||
gpio_set_af_mode(BOARD_SDIO_D2, 12);
|
||||
gpio_set_af_mode(BOARD_SDIO_D3, 12);
|
||||
gpio_set_af_mode(BOARD_SDIO_CLK, 12);
|
||||
gpio_set_af_mode(BOARD_SDIO_CMD, 12);
|
||||
*/
|
||||
}
|
||||
|
||||
void sdio_gpios_deinit(void)
|
||||
{
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING);
|
||||
|
||||
/*
|
||||
* Todo just remove it, not needed for F1.
|
||||
*/
|
||||
/*
|
||||
gpio_set_af_mode(BOARD_SDIO_D0, 0);
|
||||
gpio_set_af_mode(BOARD_SDIO_D1, 0);
|
||||
gpio_set_af_mode(BOARD_SDIO_D2, 0);
|
||||
gpio_set_af_mode(BOARD_SDIO_D3, 0);
|
||||
gpio_set_af_mode(BOARD_SDIO_CLK, 0);
|
||||
gpio_set_af_mode(BOARD_SDIO_CMD, 0);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize and reset the SDIO device.
|
||||
*/
|
||||
void sdio_init(void)
|
||||
{
|
||||
rcc_clk_enable(RCC_SDIO);
|
||||
rcc_reset_dev(RCC_SDIO);
|
||||
}
|
||||
|
||||
void sdio_power_on(void)
|
||||
{
|
||||
SDIO->POWER = SDIO_POWER_PWRCTRL_ON;
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods.
|
||||
delay_us(DELAY_LONG);
|
||||
}
|
||||
|
||||
void sdio_power_off(void)
|
||||
{
|
||||
SDIO->POWER = SDIO_POWER_PWRCTRL_OFF;
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods.
|
||||
delay_us(DELAY_LONG);
|
||||
}
|
||||
|
||||
void sdio_set_clock(uint32_t clk)
|
||||
{
|
||||
if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz
|
||||
|
||||
if (clk<1000000) dly = DELAY_LONG;
|
||||
else dly = DELAY_SHORT;
|
||||
|
||||
sdio_disable();
|
||||
SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV);
|
||||
delay_us(dly);
|
||||
}
|
||||
|
||||
void sdio_set_dbus_width(uint16_t bus_w)
|
||||
{
|
||||
SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w;
|
||||
delay_us(dly);
|
||||
}
|
||||
|
||||
void sdio_set_dblock_size(uint8_t dbsize)
|
||||
{
|
||||
SDIO->DCTRL = (SDIO->DCTRL&(~SDIO_DCTRL_DBLOCKSIZE)) | ((dbsize&0xF)<<4);
|
||||
delay_us(dly);
|
||||
}
|
||||
|
||||
void sdio_enable(void)
|
||||
{
|
||||
SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
|
||||
delay_us(dly);
|
||||
}
|
||||
|
||||
void sdio_disable(void)
|
||||
{
|
||||
SDIO->CLKCR ^= SDIO_CLKCR_CLKEN;
|
||||
delay_us(dly);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure and enable the SDIO device.
|
||||
*/
|
||||
void sdio_begin(void)
|
||||
{
|
||||
sdio_gpios_init();
|
||||
sdio_init();
|
||||
sdio_power_on();
|
||||
// Set initial SCK rate.
|
||||
sdio_set_clock(400000);
|
||||
delay_us(200); // generate 80 pulses at 400kHz
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the SDIO device.
|
||||
*/
|
||||
void sdio_end(void)
|
||||
{
|
||||
sdio_disable();
|
||||
while ( sdio_cmd_xfer_ongoing() );
|
||||
sdio_power_off();
|
||||
rcc_clk_disable(RCC_SDIO);
|
||||
sdio_gpios_deinit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command by the SDIO device.
|
||||
*/
|
||||
uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg)
|
||||
{
|
||||
uint8_t retries = 10; // in case of errors
|
||||
do { // retry command if errors detected
|
||||
// clear interrupt flags - IMPORTANT!!!
|
||||
SDIO->ICR = SDIO_ICR_CMD_FLAGS;
|
||||
// write command
|
||||
SDIO->ARG = arg;
|
||||
SDIO->CMD = (uint32_t)(SDIO_CMD_CPSMEN | cmd_index_resp_type );
|
||||
while ( (SDIO->STA&SDIO_STA_CMDACT) ) ; // wait for actual command transfer to finish
|
||||
// wait for response, if the case
|
||||
if ( cmd_index_resp_type&(SDIO_CMD_WAIT_SHORT_RESP|SDIO_CMD_WAIT_LONG_RESP) ) {
|
||||
while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ;
|
||||
} else break; // no response required
|
||||
if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) )
|
||||
break; // response received or timeout
|
||||
// ignore CRC error for CMD5 and ACMD41
|
||||
if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) )
|
||||
break;
|
||||
} while ( (--retries) );
|
||||
return (uint8_t)retries;
|
||||
}
|
||||
|
||||
#endif // defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
|
|
@ -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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SdioF1.h"
|
||||
#include <libmaple/sdio.h>
|
||||
#include <libmaple/dma.h>
|
||||
#include <boards.h>
|
||||
|
||||
|
||||
#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<uint8_t*>(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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
#ifndef _SDIOF4_H_
|
||||
#define _SDIOF4_H_
|
||||
|
||||
#include <SdFat.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,270 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file sdio.h
|
||||
* @brief Secure digital input/output interface.
|
||||
*/
|
||||
|
||||
#ifndef _SDIO_H_
|
||||
#define _SDIO_H_
|
||||
|
||||
#include <libmaple/libmaple_types.h>
|
||||
#include <libmaple/stm32.h>
|
||||
#include <libmaple/gpio.h>
|
||||
|
||||
|
||||
/*
|
||||
#include <libmaple/rcc.h>
|
||||
#include <libmaple/nvic.h>
|
||||
|
||||
//#include <boards.h>
|
||||
#include <stdint.h>
|
||||
//#include <wirish.h>
|
||||
*/
|
||||
|
||||
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
|
||||
|
||||
/*
|
||||
* DMA controller and channel used in STM32F103
|
||||
*/
|
||||
|
||||
#define SDIO_DMA_DEV DMA2
|
||||
#define SDIO_DMA_CHANNEL DMA_CH4
|
||||
/*
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
*/
|
||||
|
||||
/*
|
||||
* Register maps and devices
|
||||
*/
|
||||
|
||||
// SDIO register map type
|
||||
typedef struct sdio_reg_map {
|
||||
__io uint32 POWER; // 0x00
|
||||
__io uint32 CLKCR; // 0x04
|
||||
__io uint32 ARG; // 0x08
|
||||
__io uint32 CMD; // 0x0C
|
||||
__io uint32 RESPCMD; // 0x10 (0x3F)
|
||||
const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response.
|
||||
__io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods.
|
||||
__io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred
|
||||
__io uint32 DCTRL; // 0x2C
|
||||
__io uint32 DCOUNT; // 0x30 (0x01FF FFFF)
|
||||
__io uint32 STA; // 0x34
|
||||
__io uint32 ICR; // 0x38
|
||||
__io uint32 MASK; // 0x3C
|
||||
const uint32 RESERVED1[2];
|
||||
__io uint32 FIFOCNT; // 0x48 (0x01FF FFFF)
|
||||
const uint32 RESERVED2[13];
|
||||
__io uint32 FIFO; // 0x80
|
||||
} sdio_reg_map;
|
||||
#define sdio_dev sdio_reg_map
|
||||
|
||||
/** SDIO register map base pointer */
|
||||
#define SDIO_BASE ((struct sdio_reg_map*)0x40018000)
|
||||
|
||||
extern sdio_dev * SDIO;
|
||||
|
||||
/*
|
||||
* Register bit definitions
|
||||
*/
|
||||
|
||||
/* NOR/PSRAM chip-select control registers */
|
||||
|
||||
// SDIO_POWER register bits
|
||||
// At least seven HCLK clock periods are needed between two write accesses to this register.
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods.
|
||||
#define SDIO_POWER_PWRCTRL_OFF 0x00
|
||||
#define SDIO_POWER_PWRCTRL_ON 0x03
|
||||
|
||||
// SDIO_CLKCR register bits
|
||||
// Controls the SDIO_CK output clock.
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods. SDIO_CK can also be stopped during the read wait interval
|
||||
// for SD I/O cards: in this case the SDIO_CLKCR register does not control SDIO_CK.
|
||||
#define SDIO_CLKCR_HWFC_EN (1<<14) // HW Flow Control enable - DON'T USE!!! (see errata sheet 2.12.1)
|
||||
// Overrun errors (Rx mode) and FIFO underrun (Tx mode)
|
||||
// should be managed by the application software.
|
||||
#define SDIO_CLKCR_NEGEDGE (1<<13) // SDIO_CK de-phasing selection bit - DON'T USE!!! (see errata sheet 2.12.4)
|
||||
#define SDIO_CLKCR_WIDBUS (3<<11) // Data bus width
|
||||
#define SDIO_CLKCR_WIDBUS_1BIT (0<<11) // 1 bit (SDIO_D0 used)
|
||||
#define SDIO_CLKCR_WIDBUS_4BIT (1<<11) // 4-bit (SDIO_D[3:0] used)
|
||||
#define SDIO_CLKCR_BYPASS (1<<10) // Clock divider bypass enable bit - SDIO_CK = SDIOCLK, CLKDIV not relevant.
|
||||
#define SDIO_CLKCR_PWRSAV (1<<9) // 0: SDIO_CK clock is always enabled, 1: SDIO_CK is only enabled when the bus is active
|
||||
#define SDIO_CLKCR_CLKEN (1<<8) // Clock enable
|
||||
#define SDIO_CLKCR_CLKDIV (0xFF) // SDIO_CK = SDIOCLK / [CLKDIV + 2]
|
||||
#define SDIOCLK 72000000UL // SDIO master clock frequency
|
||||
|
||||
// SDIO_CMD register bits
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods.
|
||||
// MultiMediaCards can send two kinds of response: short responses, 48 bits long, or long
|
||||
// responses,136 bits long. SD card and SD I/O card can send only short responses, the
|
||||
// argument can vary according to the type of response: the software will distinguish the type
|
||||
// of response according to the sent command. CE-ATA devices send only short responses.
|
||||
#define SDIO_CMD_ATACMD (1<<14)
|
||||
#define SDIO_CMD_NIEN (1<<13)
|
||||
#define SDIO_CMD_ENCMDCOMPL (1<<12)
|
||||
#define SDIO_CMD_SDIOSUSPEND (1<<11)
|
||||
#define SDIO_CMD_CPSMEN (1<<10)
|
||||
#define SDIO_CMD_WAITPEND (1<<9)
|
||||
#define SDIO_CMD_WAITINT (1<<8)
|
||||
#define SDIO_CMD_WAITRESP (3<<6)
|
||||
#define SDIO_CMD_WAIT_NO_RESP (0<<6)
|
||||
#define SDIO_CMD_WAIT_SHORT_RESP (1<<6)
|
||||
#define SDIO_CMD_WAIT_LONG_RESP (3<<6)
|
||||
#define SDIO_CMD_CMDINDEX (0x3F)
|
||||
|
||||
// SDIO_DLEN register bits
|
||||
// For a block data transfer, the value in the data length register must be a multiple of the block
|
||||
// size (see SDIO_DCTRL). A data transfer must be written to the data timer register and the
|
||||
// data length register before being written to the data control register.
|
||||
// For an SDIO multibyte transfer the value in the data length register must be between 1 and 512.
|
||||
#define SDIO_DLEN_DATALENGTH (0x01FFFFFF)
|
||||
|
||||
// SDIO_DCTRL register bits
|
||||
// Controls the data path state machine (DPSM).
|
||||
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
||||
// plus two PCLK2 clock periods.
|
||||
#define SDIO_DCTRL_SDIOEN (1<<11) // the DPSM performs an SD I/O-card-specific operation.
|
||||
#define SDIO_DCTRL_RWMODE (1<<10) // 0: Read Wait control stopping SDIO_D2, 1:Read Wait control using SDIO_CK
|
||||
#define SDIO_DCTRL_RWSTOP (1<<9) // 0: Read wait in progress if RWSTART bit is set, 1: Enable for read wait stop if RWSTART bit is set
|
||||
#define SDIO_DCTRL_RWSTART (1<<8) // read wait operation starts
|
||||
#define SDIO_DCTRL_DBLOCKSIZE (0xF<<4) // Define the data block length when the block data transfer mode is selected: 2^N bytes
|
||||
#define SDIO_BLOCKSIZE_64 (6<<4)
|
||||
#define SDIO_BLOCKSIZE_512 (9<<4)
|
||||
#define SDIO_DCTRL_DMAEN (1<<3) // DMA enable
|
||||
#define SDIO_DCTRL_DTMODE (1<<2) // Data transfer mode selection: 0: Block data transfer, 1: Stream or SDIO multi-byte data transfer
|
||||
#define SDIO_DCTRL_DTDIR (1<<1) // Data transfer direction selection: 0: From controller to card, 1: From card to controller.
|
||||
#define SDIO_DIR_TX (0<<1)
|
||||
#define SDIO_DIR_RX (1<<1)
|
||||
#define SDIO_DCTRL_DTEN (1<<0) // Start data transfer. Depending on the direction bit, DTDIR,
|
||||
// the DPSM moves to the Wait_S, Wait_R state or Readwait if RW Start is set immediately at
|
||||
// the beginning of the transfer. It is not necessary to clear the enable bit after the end of a data
|
||||
// transfer but the SDIO_DCTRL must be updated to enable a new data transfer
|
||||
// The meaning of the DTMODE bit changes according to the value of the SDIOEN bit:
|
||||
// When DTEN=0 and DTMODE=1, the MultiMediaCard stream mode is enabled.
|
||||
// When DTEN=1 and DTMODE=1, the peripheral enables an SDIO multi-byte transfer.
|
||||
|
||||
// SDIO_STA register bits
|
||||
#define SDIO_STA_CEATAEND (1<<23) // CE-ATA command completion signal received for CMD61
|
||||
#define SDIO_STA_SDIOIT (1<<22) // SDIO interrupt received
|
||||
#define SDIO_STA_RXDAVL (1<<21) // Data available in receive FIFO
|
||||
#define SDIO_STA_TXDAVL (1<<20) // Data available in transmit FIFO
|
||||
#define SDIO_STA_RXFIFOE (1<<19) // Receive FIFO empty
|
||||
#define SDIO_STA_TXFIFOE (1<<18) // Transmit FIFO empty (2 words)
|
||||
#define SDIO_STA_RXFIFOF (1<<17) // Receive FIFO full (2 words before the FIFO is full.)
|
||||
#define SDIO_STA_TXFIFOF (1<<16) // Transmit FIFO full
|
||||
#define SDIO_STA_RXFIFOHF (1<<15) // Receive FIFO half full: there are at least 8 words in the FIFO
|
||||
#define SDIO_STA_TXFIFOHE (1<<14) // Transmit FIFO half empty: at least 8 words can be written into the FIFO
|
||||
#define SDIO_STA_RXACT (1<<13) // Data receive in progress
|
||||
#define SDIO_STA_TXACT (1<<12) // Data transmit in progress
|
||||
#define SDIO_STA_CMDACT (1<<11) // Command transfer in progress
|
||||
#define SDIO_STA_DBCKEND (1<<10) // Data block sent/received (CRC check passed)
|
||||
#define SDIO_STA_STBITERR (1<<9) // Start bit not detected on all data signals in wide bus mode
|
||||
#define SDIO_STA_DATAEND (1<<8) // Data end (data counter SDIOCOUNT is zero)
|
||||
#define SDIO_STA_CMDSENT (1<<7) // Command sent (no response required)
|
||||
#define SDIO_STA_CMDREND (1<<6) // Command response received (CRC check passed)
|
||||
#define SDIO_STA_RXOVERR (1<<5) // Received FIFO overrun error
|
||||
#define SDIO_STA_TXUNDERR (1<<4) // Transmit FIFO underrun error
|
||||
#define SDIO_STA_DTIMEOUT (1<<3) // Data timeout
|
||||
#define SDIO_STA_CTIMEOUT (1<<2) // Command response timeout. The Command TimeOut period has a fixed value of 64 SDIO_CK clock periods.
|
||||
#define SDIO_STA_DCRCFAIL (1<<1) // Data block sent/received (CRC check failed)
|
||||
#define SDIO_STA_CCRCFAIL (1<<0) // Command response received (CRC check failed)
|
||||
|
||||
#define SDIO_STA_CMD_ERROR_FLAGS (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)
|
||||
#define SDIO_STA_TRX_ERROR_FLAGS (SDIO_STA_STBITERR | SDIO_STA_RXOVERR | SDIO_STA_TXUNDERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL)
|
||||
#define SDIO_STA_TRX_ACT_FLAGS (SDIO_STA_RXACT|SDIO_STA_TXACT)
|
||||
|
||||
// SDIO_ICR register bits (WO - write only)
|
||||
#define SDIO_ICR_CEATAENDC (1<<23) // clear CEATAEND flag
|
||||
#define SDIO_ICR_SDIOITC (1<<22) // clear SDIOIT flag
|
||||
#define SDIO_ICR_DBCKENDC (1<<10) // clear DBCKENDC flag
|
||||
#define SDIO_ICR_STBITERRC (1<<9) // clear STBITERRC flag
|
||||
#define SDIO_ICR_DATAENDC (1<<8) // clear DATAENDC flag
|
||||
#define SDIO_ICR_CMDSENTC (1<<7) // clear CMDSENTC flag
|
||||
#define SDIO_ICR_CMDRENDC (1<<6) // clear CMDREND flag
|
||||
#define SDIO_ICR_RXOVERRC (1<<5) // clear RXOVERR flag
|
||||
#define SDIO_ICR_TXUNDERRC (1<<4) // clear TXUNDERR flag
|
||||
#define SDIO_ICR_DTIMEOUTC (1<<3) // clear DTIMEOUT flag
|
||||
#define SDIO_ICR_CTIMEOUTC (1<<2) // clear CTIMEOUT flag
|
||||
#define SDIO_ICR_DCRCFAILC (1<<1) // clear DCRCFAIL flag
|
||||
#define SDIO_ICR_CCRCFAILC (1<<0) // clear CCRCFAIL flag
|
||||
|
||||
#define SDIO_ICR_CMD_FLAGS (SDIO_ICR_CEATAENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CMDSENTC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC)
|
||||
#define SDIO_ICR_DATA_FLAGS (SDIO_ICR_DBCKENDC | SDIO_ICR_STBITERRC | SDIO_ICR_DATAENDC | SDIO_ICR_RXOVERRC | SDIO_ICR_TXUNDERRC | SDIO_ICR_DTIMEOUTC | SDIO_ICR_DCRCFAILC)
|
||||
|
||||
// SDIO_MASK register bits
|
||||
// Determines which status flags generate an interrupt request by setting the corresponding bit to 1b.
|
||||
#define SDIO_MASK_CEATAENDIE (1<<23) // enable CEATAEND interrupt
|
||||
#define SDIO_MASK_SDIOITIE (1<<22) // enable SDIOIT interrupt
|
||||
#define SDIO_MASK_RXDAVLIE (1<<21) // enable RXDAVL interrupt
|
||||
#define SDIO_MASK_TXDAVLIE (1<<20) // enable TXDAVL interrupt
|
||||
#define SDIO_MASK_RXFIFOEIE (1<<19) // enable RXFIFOE interrupt
|
||||
#define SDIO_MASK_TXFIFOEIE (1<<18) // enable TXFIFOE interrupt
|
||||
#define SDIO_MASK_RXFIFOFIE (1<<17) // enable RXFIFOF interrupt
|
||||
#define SDIO_MASK_TXFIFOFIE (1<<16) // enable TXFIFOF interrupt
|
||||
#define SDIO_MASK_RXFIFOHFIE (1<<15) // enable RXFIFOHF interrupt
|
||||
#define SDIO_MASK_TXFIFOHEIE (1<<14) // enable TXFIFOHE interrupt
|
||||
#define SDIO_MASK_RXACTIE (1<<13) // enable RXACT interrupt
|
||||
#define SDIO_MASK_TXACTIE (1<<12) // enable TXACT interrupt
|
||||
#define SDIO_MASK_CMDACTIE (1<<11) // enable CMDACT interrupt
|
||||
#define SDIO_MASK_DBCKENDIE (1<<10) // enable DBCKENDC interrupt
|
||||
#define SDIO_MASK_STBITERRIE (1<<9) // enable STBITERR interrupt
|
||||
#define SDIO_MASK_DATAENDIE (1<<8) // enable DATAENDC interrupt
|
||||
#define SDIO_MASK_CMDSENTIE (1<<7) // enable CMDSENTC interrupt
|
||||
#define SDIO_MASK_CMDRENDIE (1<<6) // enable CMDREND interrupt
|
||||
#define SDIO_MASK_RXOVERRIE (1<<5) // enable RXOVERR interrupt
|
||||
#define SDIO_MASK_TXUNDERRIE (1<<4) // enable TXUNDERR interrupt
|
||||
#define SDIO_MASK_DTIMEOUTIE (1<<3) // enable DTIMEOUT interrupt
|
||||
#define SDIO_MASK_CTIMEOUTIE (1<<2) // enable CTIMEOUT interrupt
|
||||
#define SDIO_MASK_DCRCFAILIE (1<<1) // enable DCRCFAIL interrupt
|
||||
#define SDIO_MASK_CCRCFAILIE (1<<0) // enable CCRCFAIL interrupt
|
||||
|
||||
|
||||
void sdio_enable(void);
|
||||
void sdio_disable(void);
|
||||
void sdio_begin(void);
|
||||
uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg);
|
||||
void sdio_set_clock(uint32_t clk);
|
||||
void sdio_set_dbus_width(uint16_t bus_w);
|
||||
void sdio_set_dblock_size(uint8_t dbsize);
|
||||
//void sdio_trx_enable(uint8_t dir);
|
||||
inline void sdio_trx_enable(void)
|
||||
{
|
||||
SDIO->DCTRL |= SDIO_DCTRL_DTEN; // enable data transfer
|
||||
}
|
||||
|
||||
inline uint32_t sdio_cmd_xfer_ongoing(void) { return (SDIO->STA&SDIO_STA_CMDACT); }
|
||||
inline uint32_t sdio_cmd_complete(void) { return (SDIO->STA&SDIO_STA_CMDSENT); }
|
||||
|
||||
inline void sdio_setup_transfer(uint32_t dtimer, uint32_t dlen, uint16_t flags)
|
||||
{
|
||||
SDIO->ICR = SDIO_ICR_DATA_FLAGS; // clear data access relevant flags
|
||||
SDIO->DTIMER = dtimer;
|
||||
SDIO->DLEN = dlen;
|
||||
SDIO->DCTRL = flags;// | SDIO_DCTRL_DTEN; // enable data transfer
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif /* (STM32_HIGH_DENSITY) || (STM32_XL_DENSITY) */
|
||||
|
||||
#endif
|
|
@ -102,6 +102,16 @@
|
|||
#define BOARD_USB_DISC_DEV GPIOC
|
||||
#define BOARD_USB_DISC_BIT 12
|
||||
|
||||
/*
|
||||
* SDIO Pins
|
||||
*/
|
||||
#define BOARD_SDIO_D0 PC8
|
||||
#define BOARD_SDIO_D1 PC9
|
||||
#define BOARD_SDIO_D2 PC10
|
||||
#define BOARD_SDIO_D3 PC11
|
||||
#define BOARD_SDIO_CLK PC12
|
||||
#define BOARD_SDIO_CMD PD2
|
||||
|
||||
/* Pin aliases: these give the GPIO port/bit for each pin as an
|
||||
* enum. These are optional, but recommended. They make it easier to
|
||||
* write code using low-level GPIO functionality. */
|
||||
|
|
Loading…
Reference in New Issue