forked from xuos/xiuos
2822 lines
89 KiB
C
2822 lines
89 KiB
C
/*
|
||
* Copyright (c) Guangzhou Xingyi Electronic Technology Co., Ltd
|
||
*
|
||
* Change Logs:
|
||
* Date Author Notes
|
||
* 2014-7-4 alientek first version
|
||
*/
|
||
|
||
/**
|
||
* @file sdio_sd.c
|
||
* @brief support hal sdio function
|
||
* @version 1.0
|
||
* @author AIIT XUOS Lab
|
||
* @date 2021-04-22
|
||
*/
|
||
|
||
/*********************************************************************************
|
||
* file :sdio_sd.c
|
||
* description:4bit sdio driver on stm32f407
|
||
* hardware connection:
|
||
* ------------------------------
|
||
* | PC8 -SDIO-D0 :DATA0 |
|
||
* | PC9 -SDIO-D1 :DATA1 |
|
||
* | PC10-SDIO-D2 :DATA2 |
|
||
* | PC11-SDIO-D3 :CD/DATA3 |
|
||
* | PC12-SDIO-CLK:CLK |
|
||
* | PD2 -SDIO-CMD:CMD |
|
||
* ------------------------------
|
||
* ***** : *******************************
|
||
* ***** : *******************************
|
||
**********************************************************************************/
|
||
|
||
/*************************************************
|
||
File name: sdio_sd.c
|
||
Description: support aiit-arm32-board sdio
|
||
Others: hardware/sdio/sdio.c for references
|
||
History:
|
||
1. Date: 2021-04-22
|
||
Author: AIIT XUOS Lab
|
||
Modification: Support aiit-arm32-board sdio using source files
|
||
*************************************************/
|
||
|
||
#include <board.h>
|
||
#include <hardware_dma.h>
|
||
#include <hardware_sdio.h>
|
||
#include <hardware_rcc.h>
|
||
#include <hardware_gpio.h>
|
||
#include <misc.h>
|
||
#include "sdio_sd.h"
|
||
#include <stm32_assert_template.h>
|
||
#include <xiuos.h>
|
||
|
||
/* Private macro -------------------------------------------------------------*/
|
||
/**
|
||
* @brief SDIO Static flags, TimeOut, FIFO Address
|
||
*/
|
||
|
||
/*#define NULL 0*/
|
||
|
||
#define SDIO_STATIC_FLAGS ((uint32_t)0x000005FF)
|
||
#define SDIO_CMD0TIMEOUT ((uint32_t)0x00010000)
|
||
|
||
/**
|
||
* @brief Mask for errors Card Status R1 (OCR Register)
|
||
*/
|
||
#define SD_OCR_ADDR_OUT_OF_RANGE ((uint32_t)0x80000000)
|
||
#define SD_OCR_ADDR_MISALIGNED ((uint32_t)0x40000000)
|
||
#define SD_OCR_BLOCK_LEN_ERR ((uint32_t)0x20000000)
|
||
#define SD_OCR_ERASE_SEQ_ERR ((uint32_t)0x10000000)
|
||
#define SD_OCR_BAD_ERASE_PARAM ((uint32_t)0x08000000)
|
||
#define SD_OCR_WRITE_PROT_VIOLATION ((uint32_t)0x04000000)
|
||
#define SD_OCR_LOCK_UNLOCK_FAILED ((uint32_t)0x01000000)
|
||
#define SD_OCR_COM_CRC_FAILED ((uint32_t)0x00800000)
|
||
#define SD_OCR_ILLEGAL_CMD ((uint32_t)0x00400000)
|
||
#define SD_OCR_CARD_ECC_FAILED ((uint32_t)0x00200000)
|
||
#define SD_OCR_CC_ERROR ((uint32_t)0x00100000)
|
||
#define SD_OCR_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00080000)
|
||
#define SD_OCR_STREAM_READ_UNDERRUN ((uint32_t)0x00040000)
|
||
#define SD_OCR_STREAM_WRITE_OVERRUN ((uint32_t)0x00020000)
|
||
#define SD_OCR_CID_CSD_OVERWRIETE ((uint32_t)0x00010000)
|
||
#define SD_OCR_WP_ERASE_SKIP ((uint32_t)0x00008000)
|
||
#define SD_OCR_CARD_ECC_DISABLED ((uint32_t)0x00004000)
|
||
#define SD_OCR_ERASE_RESET ((uint32_t)0x00002000)
|
||
#define SD_OCR_AKE_SEQ_ERROR ((uint32_t)0x00000008)
|
||
#define SD_OCR_ERRORBITS ((uint32_t)0xFDFFE008)
|
||
|
||
/**
|
||
* @brief Masks for R6 Response
|
||
*/
|
||
#define SD_R6_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00002000)
|
||
#define SD_R6_ILLEGAL_CMD ((uint32_t)0x00004000)
|
||
#define SD_R6_COM_CRC_FAILED ((uint32_t)0x00008000)
|
||
|
||
#define SD_VOLTAGE_WINDOW_SD ((uint32_t)0x80100000)
|
||
#define SD_HIGH_CAPACITY ((uint32_t)0x40000000)
|
||
#define SD_STD_CAPACITY ((uint32_t)0x00000000)
|
||
#define SD_CHECK_PATTERN ((uint32_t)0x000001AA)
|
||
|
||
#define SD_MAX_VOLT_TRIAL ((uint32_t)0x0000FFFF)
|
||
#define SD_ALLZERO ((uint32_t)0x00000000)
|
||
|
||
#define SD_WIDE_BUS_SUPPORT ((uint32_t)0x00040000)
|
||
#define SD_SINGLE_BUS_SUPPORT ((uint32_t)0x00010000)
|
||
#define SD_CARD_LOCKED ((uint32_t)0x02000000)
|
||
|
||
#define SD_DATATIMEOUT ((uint32_t)0xFFFFFFFF)
|
||
#define SD_0TO7BITS ((uint32_t)0x000000FF)
|
||
#define SD_8TO15BITS ((uint32_t)0x0000FF00)
|
||
#define SD_16TO23BITS ((uint32_t)0x00FF0000)
|
||
#define SD_24TO31BITS ((uint32_t)0xFF000000)
|
||
#define SD_MAX_DATA_LENGTH ((uint32_t)0x01FFFFFF)
|
||
|
||
#define SD_HALFFIFO ((uint32_t)0x00000008)
|
||
#define SD_HALFFIFOBYTES ((uint32_t)0x00000020)
|
||
|
||
/**
|
||
* @brief Command Class Supported
|
||
*/
|
||
#define SD_CCCC_LOCK_UNLOCK ((uint32_t)0x00000080)
|
||
#define SD_CCCC_WRITE_PROT ((uint32_t)0x00000040)
|
||
#define SD_CCCC_ERASE ((uint32_t)0x00000020)
|
||
|
||
/**
|
||
* @brief Following commands are SD Card Specific commands.
|
||
* SDIO_APP_CMD should be sent before sending these commands.
|
||
*/
|
||
#define SDIO_SEND_IF_COND ((uint32_t)0x00000008)
|
||
|
||
|
||
|
||
/* Private variables ---------------------------------------------------------*/
|
||
//static uint32_t CardType = SDIO_STD_CAPACITY_SD_CARD_V1_1; //sd card type, init it to v1.1
|
||
static uint32_t CSD_Tab[4], CID_Tab[4], RCA = 0; //CSD,DID,register and card address
|
||
static uint8_t SDSTATUS_Tab[16]; //sd card type, part of CSR
|
||
__IO uint32_t StopCondition = 0; //sign for stopping operate card
|
||
__IO SD_Error TransferError = SD_OK; //sign for showing card error, init as normal
|
||
__IO uint32_t DMAEndOfTransfer = 0;
|
||
__IO uint32_t TransferEnd = 0; //sign for showing if transfer is over, using in irq
|
||
SD_CardInfo SDCardInfo; //SD card info
|
||
|
||
/*SDIO init struct*/
|
||
SDIO_InitTypeDef SDIO_InitStructure;
|
||
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
|
||
SDIO_DataInitTypeDef SDIO_DataInitStructure;
|
||
|
||
|
||
/* Private function prototypes -----------------------------------------------*/
|
||
static SD_Error CmdError(void);
|
||
static SD_Error CmdResp1Error(uint8_t cmd);
|
||
static SD_Error CmdResp7Error(void);
|
||
static SD_Error CmdResp3Error(void);
|
||
static SD_Error CmdResp2Error(void);
|
||
static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca);
|
||
static SD_Error SDEnWideBus(FunctionalState NewState);
|
||
static SD_Error IsCardProgramming(uint8_t *pstatus);
|
||
static SD_Error FindSCR(uint16_t rca, uint32_t *pscr);
|
||
|
||
static void SD_GPIO_Configuration(void);
|
||
static void SD_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize);
|
||
static void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize);
|
||
static uint32_t SD_DMAEndOfTransferStatus(void);
|
||
|
||
uint8_t convert_from_bytes_to_power_of_two(uint16_t NumberOfBytes);
|
||
|
||
/* Private functions ---------------------------------------------------------*/
|
||
|
||
|
||
uint8_t SD_Detect(void)
|
||
{
|
||
__IO uint8_t status = SD_PRESENT;
|
||
|
||
/*!< Check GPIO to detect SD */
|
||
// if (GPIO_ReadInputDataBit(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) != Bit_RESET)
|
||
// {
|
||
// status = SD_NOT_PRESENT;
|
||
// }
|
||
return status;
|
||
}
|
||
|
||
/**
|
||
* @brief Configures SDIO IRQ channel.
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
void SD_NVIC_Configuration(void)
|
||
{
|
||
NVIC_InitTypeDef NVIC_InitStructure;
|
||
|
||
/* Configure the NVIC Preemption Priority Bits */
|
||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
|
||
|
||
NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||
NVIC_Init(&NVIC_InitStructure);
|
||
|
||
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn;
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||
NVIC_Init(&NVIC_InitStructure);
|
||
}
|
||
|
||
/**
|
||
* @brief Returns the DMA End Of Transfer Status.
|
||
* @param None
|
||
* @retval DMA SDIO Channel Status.
|
||
*/
|
||
uint32_t SD_DMAEndOfTransferStatus(void)
|
||
{
|
||
return (uint32_t)DMA_GetFlagStatus(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_TCIF); //Channel4 transfer complete flag.
|
||
}
|
||
|
||
|
||
void SD_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize)
|
||
{
|
||
DMA_InitTypeDef DMA_InitStructure;
|
||
|
||
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_FEIF | SD_SDIO_DMA_FLAG_DMEIF | SD_SDIO_DMA_FLAG_TEIF | SD_SDIO_DMA_FLAG_HTIF | SD_SDIO_DMA_FLAG_TCIF);
|
||
|
||
/*!< DMA2 Stream6 disable */
|
||
DMA_Cmd(SD_SDIO_DMA_STREAM, DISABLE);
|
||
|
||
DMA_DeInit(SD_SDIO_DMA_STREAM);
|
||
/*!< DMA2 Channel4 Config */
|
||
DMA_InitStructure.DMA_Channel = SD_SDIO_DMA_CHANNEL;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;
|
||
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)BufferDST;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
|
||
//DMA_InitStructure.DMA_BufferSize = BufferSize / 4;
|
||
DMA_InitStructure.DMA_BufferSize = BufferSize;
|
||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
|
||
//DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
|
||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
||
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
|
||
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
|
||
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
|
||
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
|
||
DMA_Init(SD_SDIO_DMA_STREAM, &DMA_InitStructure);
|
||
/*!< DMA2 Channel4 enable */
|
||
// DMA_ITConfig(SD_SDIO_DMA_STREAM,DMA_IT_TC,ENABLE);
|
||
DMA_FlowControllerConfig(SD_SDIO_DMA_STREAM, DMA_FlowCtrl_Peripheral);
|
||
DMA_Cmd(SD_SDIO_DMA_STREAM, ENABLE);
|
||
}
|
||
|
||
|
||
void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize)
|
||
{
|
||
|
||
DMA_InitTypeDef DMA_InitStructure;
|
||
|
||
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_FEIF | SD_SDIO_DMA_FLAG_DMEIF | SD_SDIO_DMA_FLAG_TEIF | SD_SDIO_DMA_FLAG_HTIF | SD_SDIO_DMA_FLAG_TCIF);
|
||
|
||
/*!< DMA2 Stream6 disable */
|
||
DMA_Cmd(SD_SDIO_DMA_STREAM, DISABLE);
|
||
DMA_DeInit(SD_SDIO_DMA_STREAM);
|
||
/*!< DMA2 Channel4 Config */
|
||
DMA_InitStructure.DMA_Channel = SD_SDIO_DMA_CHANNEL;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;
|
||
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)BufferSRC;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
||
//DMA_InitStructure.DMA_BufferSize = BufferSize / 4;
|
||
DMA_InitStructure.DMA_BufferSize = BufferSize;
|
||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
|
||
//DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
|
||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
||
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
|
||
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
|
||
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
|
||
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
|
||
DMA_Init(SD_SDIO_DMA_STREAM, &DMA_InitStructure);
|
||
/*!< DMA2 Channel4 enable */
|
||
// DMA_ITConfig(SD_SDIO_DMA_STREAM,DMA_IT_TC,ENABLE);
|
||
DMA_FlowControllerConfig(SD_SDIO_DMA_STREAM, DMA_FlowCtrl_Peripheral);
|
||
DMA_Cmd(SD_SDIO_DMA_STREAM, ENABLE);
|
||
|
||
}
|
||
|
||
|
||
static void SD_GPIO_Configuration(void)
|
||
{
|
||
GPIO_InitTypeDef gpio_initstructure;
|
||
|
||
/*!< GPIOC and GPIOD Periph clock enable */
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
|
||
|
||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);
|
||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
|
||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
|
||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
|
||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);
|
||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
|
||
|
||
/*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_8;
|
||
gpio_initstructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||
gpio_initstructure.GPIO_Mode = GPIO_Mode_AF;
|
||
gpio_initstructure.GPIO_PuPd = GPIO_PuPd_UP;
|
||
gpio_initstructure.GPIO_OType = GPIO_OType_PP;
|
||
GPIO_Init(GPIOC, &gpio_initstructure);
|
||
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_9;
|
||
GPIO_Init(GPIOC, &gpio_initstructure);
|
||
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_10;
|
||
GPIO_Init(GPIOC, &gpio_initstructure);
|
||
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_11;
|
||
GPIO_Init(GPIOC, &gpio_initstructure);
|
||
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_2;
|
||
GPIO_Init(GPIOD, &gpio_initstructure);
|
||
|
||
gpio_initstructure.GPIO_Pin = GPIO_Pin_12;
|
||
gpio_initstructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||
GPIO_Init(GPIOC, &gpio_initstructure);
|
||
|
||
/*!< Configure PD.02 CMD line */
|
||
|
||
/*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
|
||
// gpio_initstructure.GPIO_Pin = SD_DETECT_PIN;
|
||
// gpio_initstructure.GPIO_Mode = GPIO_Mode_IN;
|
||
// GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_initstructure);
|
||
|
||
/*!< Enable the SDIO AHB Clock */
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
|
||
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO, ENABLE);
|
||
|
||
/*!< Enable the DMA2 Clock */
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
|
||
}
|
||
|
||
|
||
SD_Error SD_Init(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
SD_NVIC_Configuration();
|
||
|
||
SD_GPIO_Configuration();
|
||
|
||
SDIO_DeInit();
|
||
|
||
errorstatus = SD_PowerON();
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
/*!< CMD Response TimeOut (wait for CMDSENT flag) */
|
||
return(errorstatus);
|
||
}
|
||
|
||
errorstatus = SD_InitializeCards();
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
/*!< CMD Response TimeOut (wait for CMDSENT flag) */
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Configure the SDIO peripheral
|
||
!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */
|
||
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
|
||
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
|
||
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
|
||
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; //enable the function, close SD_CLK when bus is not busy
|
||
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
|
||
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
|
||
SDIO_Init(&SDIO_InitStructure);
|
||
|
||
if (errorstatus == SD_OK)
|
||
{
|
||
/*----------------- Read CSD/CID MSD registers ------------------*/
|
||
errorstatus = SD_GetCardInfo(&SDCardInfo); //read csd/cid register
|
||
}
|
||
|
||
if (errorstatus == SD_OK)
|
||
{
|
||
/*----------------- Select Card --------------------------------*/
|
||
errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16)); //use cmd7 ,rca choose the card
|
||
}
|
||
|
||
if (errorstatus == SD_OK)
|
||
{
|
||
errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Gets the cuurent sd card data transfer status.
|
||
* @param None
|
||
* @retval SDTransferState: Data Transfer state.
|
||
* This value can be:
|
||
* - SD_TRANSFER_OK: No data transfer is acting
|
||
* - SD_TRANSFER_BUSY: Data transfer is acting
|
||
*/
|
||
SDTransferState SD_GetStatus(void)
|
||
{
|
||
SDCardState cardstate = SD_CARD_TRANSFER;
|
||
|
||
cardstate = SD_GetState();
|
||
|
||
if (cardstate == SD_CARD_TRANSFER)
|
||
{
|
||
return(SD_TRANSFER_OK);
|
||
}
|
||
else if(cardstate == SD_CARD_ERROR)
|
||
{
|
||
return (SD_TRANSFER_ERROR);
|
||
}
|
||
else
|
||
{
|
||
return(SD_TRANSFER_BUSY);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Returns the current card's state.
|
||
* @param None
|
||
* @retval SDCardState: SD Card Error or SD Card Current State.
|
||
*/
|
||
SDCardState SD_GetState(void)
|
||
{
|
||
uint32_t resp1 = 0;
|
||
if(SD_Detect()== SD_PRESENT)
|
||
{
|
||
if (SD_SendStatus(&resp1) != SD_OK)
|
||
{
|
||
return SD_CARD_ERROR;
|
||
}
|
||
else
|
||
{
|
||
return (SDCardState)((resp1 >> 9) & 0x0F);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return SD_CARD_ERROR;
|
||
}
|
||
}
|
||
|
||
|
||
SD_Error SD_PowerON(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t response = 0, count = 0, validvoltage = 0;
|
||
uint32_t SDType = SD_STD_CAPACITY;
|
||
|
||
/*!< Power ON Sequence -----------------------------------------------------*/
|
||
/*!< Configure the SDIO peripheral */
|
||
/*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) */
|
||
/*!< SDIO_CK for initialization should not exceed 400 KHz */
|
||
SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; /* SDIO_CK = HCLK/(SDIO_INIT_CLK_DIV + 2) */
|
||
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
|
||
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
|
||
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
|
||
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
|
||
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
|
||
SDIO_Init(&SDIO_InitStructure);
|
||
|
||
/*!< Set Power State to ON */
|
||
SDIO_SetPowerState(SDIO_PowerState_ON);
|
||
|
||
/*!< Enable SDIO Clock */
|
||
SDIO_ClockCmd(ENABLE);
|
||
/*start to check the card info*/
|
||
/*!< CMD0: GO_IDLE_STATE ---------------------------------------------------*/
|
||
/*!< No CMD response required */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //enable CPSM wait transfer stop before sending cmd
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdError();
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
/*!< CMD Response TimeOut (wait for CMDSENT flag) */
|
||
return(errorstatus);
|
||
}
|
||
/*!< CMD8: SEND_IF_COND ----------------------------------------------------*/
|
||
/*!< Send CMD8 to verify SD card interface operating condition */
|
||
/*!< Argument: - [31:12]: Reserved (shall be set to '0')
|
||
- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
|
||
- [7:0]: Check Pattern (recommended 0xAA) */
|
||
/*!< CMD Response: R7 */
|
||
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //R7
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //close wait interrupt
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp7Error();
|
||
|
||
if (errorstatus == SD_OK) //follow ver2.0
|
||
{
|
||
SDCardInfo.CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 ,define as sdsc firstly */
|
||
SDType = SD_HIGH_CAPACITY; //acmd41, check sdsc or sdhc
|
||
}
|
||
else //no response, v1.x or mmc
|
||
{
|
||
/*!< CMD55 */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
}
|
||
/*!< CMD55 */
|
||
//cmd55,check sd or mmc or not support
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD); //check response, if not, mmc or not support
|
||
|
||
/*!< If errorstatus is Command TimeOut, it is a MMC card */
|
||
/*!< If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)
|
||
or SD card 1.x */
|
||
if (errorstatus == SD_OK) //response cmd55,sd card, v1.x or v2.0
|
||
{
|
||
/*send voltage cmd */
|
||
|
||
/*!< SD CARD */
|
||
/*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
|
||
while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
|
||
{
|
||
//send CMD55 before ACMD41
|
||
/*!< SEND CMD55 APP_CMD with RCA as 0 */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
//ACMD41,cmd param is voltage and HCS(check SDSC or SDHC)
|
||
SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r3
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp3Error();
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
response = SDIO_GetResponse(SDIO_RESP1); //read card register and card status
|
||
validvoltage = (((response >> 31) == 1) ? 1 : 0); //read ocr register to check pwr_up bit
|
||
count++;
|
||
}
|
||
if (count >= SD_MAX_VOLT_TRIAL)
|
||
{
|
||
errorstatus = SD_INVALID_VOLTRANGE; //SDIO do not support card voltage
|
||
return(errorstatus);
|
||
}
|
||
/*check HCS bit*/
|
||
if (response &= SD_HIGH_CAPACITY) //check ccs bit of ocr register
|
||
{
|
||
SDCardInfo.CardType = SDIO_HIGH_CAPACITY_SD_CARD;//change SDSC to SDHC
|
||
}
|
||
|
||
}/*!< else MMC Card */
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
SD_Error SD_PowerOFF(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
/*!< Set Power State to OFF */
|
||
SDIO_SetPowerState(SDIO_PowerState_OFF);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
SD_Error SD_InitializeCards(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint16_t rca = 0x01;
|
||
|
||
if (SDIO_GetPowerState() == SDIO_PowerState_OFF)
|
||
{
|
||
errorstatus = SD_REQUEST_NOT_APPLICABLE;
|
||
return(errorstatus);
|
||
}
|
||
|
||
if (SDIO_SECURE_DIGITAL_IO_CARD != SDCardInfo.CardType)
|
||
{
|
||
/*!< Send CMD2 ALL_SEND_CID */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp2Error();
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
|
||
CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
|
||
CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
|
||
CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
|
||
}
|
||
|
||
/*SD card init*/
|
||
if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == SDCardInfo.CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == SDCardInfo.CardType)
|
||
|| (SDIO_SECURE_DIGITAL_IO_COMBO_CARD == SDCardInfo.CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == SDCardInfo.CardType)) //使用的是2.0的卡
|
||
{
|
||
/*!< Send CMD3 SET_REL_ADDR with argument 0 */
|
||
/*!< SD Card publishes its RCA. */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;//CMD3
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;//R6
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca); //store address
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
}
|
||
|
||
if (SDIO_SECURE_DIGITAL_IO_CARD != SDCardInfo.CardType)
|
||
{
|
||
RCA = rca;
|
||
|
||
/*!< Send CMD9 SEND_CSD with argument as card's RCA */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp2Error();
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
|
||
CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
|
||
CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
|
||
CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
|
||
}
|
||
|
||
errorstatus = SD_OK; /*!< All cards get intialized */
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint8_t tmp = 0;
|
||
|
||
cardinfo->CardType = (uint8_t)SDCardInfo.CardType;
|
||
cardinfo->RCA = (uint16_t)RCA;
|
||
|
||
/*!< Byte 0 */
|
||
tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);
|
||
cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;
|
||
cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;
|
||
cardinfo->SD_csd.Reserved1 = tmp & 0x03;
|
||
|
||
/*!< Byte 1 */
|
||
tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_csd.TAAC = tmp;
|
||
|
||
/*!< Byte 2 */
|
||
tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_csd.NSAC = tmp;
|
||
|
||
/*!< Byte 3 */
|
||
tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);
|
||
cardinfo->SD_csd.MaxBusClkFrec = tmp;
|
||
|
||
/*!< Byte 4 */
|
||
tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);
|
||
cardinfo->SD_csd.CardComdClasses = tmp << 4;
|
||
|
||
/*!< Byte 5 */
|
||
tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;
|
||
cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;
|
||
|
||
/*!< Byte 6 */
|
||
tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_csd.PartBlockRead = (tmp & 0x80) >> 7;
|
||
cardinfo->SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;
|
||
cardinfo->SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;
|
||
cardinfo->SD_csd.DSRImpl = (tmp & 0x10) >> 4;
|
||
cardinfo->SD_csd.Reserved2 = 0; /*!< Reserved */
|
||
|
||
if ((SDCardInfo.CardType == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (SDCardInfo.CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0))
|
||
{
|
||
cardinfo->SD_csd.DeviceSize = (tmp & 0x03) << 10;
|
||
|
||
/*!< Byte 7 */
|
||
tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
|
||
cardinfo->SD_csd.DeviceSize |= (tmp) << 2;
|
||
|
||
/*!< Byte 8 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);
|
||
cardinfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;
|
||
|
||
cardinfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;
|
||
cardinfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);
|
||
|
||
/*!< Byte 9 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;
|
||
cardinfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;
|
||
cardinfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1;
|
||
/*!< Byte 10 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;
|
||
|
||
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) ;
|
||
cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
|
||
cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
|
||
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
|
||
}
|
||
else if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
/*!< Byte 7 */
|
||
tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
|
||
cardinfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16;
|
||
|
||
/*!< Byte 8 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);
|
||
|
||
cardinfo->SD_csd.DeviceSize |= (tmp << 8);
|
||
|
||
/*!< Byte 9 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);
|
||
|
||
cardinfo->SD_csd.DeviceSize |= (tmp);
|
||
|
||
/*!< Byte 10 */
|
||
tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);
|
||
|
||
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024;
|
||
cardinfo->CardBlockSize = 512;
|
||
}
|
||
|
||
|
||
cardinfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6;
|
||
cardinfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1;
|
||
|
||
/*!< Byte 11 */
|
||
tmp = (uint8_t)(CSD_Tab[2] & 0x000000FF);
|
||
cardinfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;
|
||
cardinfo->SD_csd.WrProtectGrSize = (tmp & 0x7F);
|
||
|
||
/*!< Byte 12 */
|
||
tmp = (uint8_t)((CSD_Tab[3] & 0xFF000000) >> 24);
|
||
cardinfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7;
|
||
cardinfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5;
|
||
cardinfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2;
|
||
cardinfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2;
|
||
|
||
/*!< Byte 13 */
|
||
tmp = (uint8_t)((CSD_Tab[3] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6;
|
||
cardinfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5;
|
||
cardinfo->SD_csd.Reserved3 = 0;
|
||
cardinfo->SD_csd.ContentProtectAppli = (tmp & 0x01);
|
||
|
||
/*!< Byte 14 */
|
||
tmp = (uint8_t)((CSD_Tab[3] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7;
|
||
cardinfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6;
|
||
cardinfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5;
|
||
cardinfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4;
|
||
cardinfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2;
|
||
cardinfo->SD_csd.ECC = (tmp & 0x03);
|
||
|
||
/*!< Byte 15 */
|
||
tmp = (uint8_t)(CSD_Tab[3] & 0x000000FF);
|
||
cardinfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1;
|
||
cardinfo->SD_csd.Reserved4 = 1;
|
||
|
||
|
||
/*!< Byte 0 */
|
||
tmp = (uint8_t)((CID_Tab[0] & 0xFF000000) >> 24);
|
||
cardinfo->SD_cid.ManufacturerID = tmp;
|
||
|
||
/*!< Byte 1 */
|
||
tmp = (uint8_t)((CID_Tab[0] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_cid.OEM_AppliID = tmp << 8;
|
||
|
||
/*!< Byte 2 */
|
||
tmp = (uint8_t)((CID_Tab[0] & 0x000000FF00) >> 8);
|
||
cardinfo->SD_cid.OEM_AppliID |= tmp;
|
||
|
||
/*!< Byte 3 */
|
||
tmp = (uint8_t)(CID_Tab[0] & 0x000000FF);
|
||
cardinfo->SD_cid.ProdName1 = tmp << 24;
|
||
|
||
/*!< Byte 4 */
|
||
tmp = (uint8_t)((CID_Tab[1] & 0xFF000000) >> 24);
|
||
cardinfo->SD_cid.ProdName1 |= tmp << 16;
|
||
|
||
/*!< Byte 5 */
|
||
tmp = (uint8_t)((CID_Tab[1] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_cid.ProdName1 |= tmp << 8;
|
||
|
||
/*!< Byte 6 */
|
||
tmp = (uint8_t)((CID_Tab[1] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_cid.ProdName1 |= tmp;
|
||
|
||
/*!< Byte 7 */
|
||
tmp = (uint8_t)(CID_Tab[1] & 0x000000FF);
|
||
cardinfo->SD_cid.ProdName2 = tmp;
|
||
|
||
/*!< Byte 8 */
|
||
tmp = (uint8_t)((CID_Tab[2] & 0xFF000000) >> 24);
|
||
cardinfo->SD_cid.ProdRev = tmp;
|
||
|
||
/*!< Byte 9 */
|
||
tmp = (uint8_t)((CID_Tab[2] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_cid.ProdSN = tmp << 24;
|
||
|
||
/*!< Byte 10 */
|
||
tmp = (uint8_t)((CID_Tab[2] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_cid.ProdSN |= tmp << 16;
|
||
|
||
/*!< Byte 11 */
|
||
tmp = (uint8_t)(CID_Tab[2] & 0x000000FF);
|
||
cardinfo->SD_cid.ProdSN |= tmp << 8;
|
||
|
||
/*!< Byte 12 */
|
||
tmp = (uint8_t)((CID_Tab[3] & 0xFF000000) >> 24);
|
||
cardinfo->SD_cid.ProdSN |= tmp;
|
||
|
||
/*!< Byte 13 */
|
||
tmp = (uint8_t)((CID_Tab[3] & 0x00FF0000) >> 16);
|
||
cardinfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;
|
||
cardinfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8;
|
||
|
||
/*!< Byte 14 */
|
||
tmp = (uint8_t)((CID_Tab[3] & 0x0000FF00) >> 8);
|
||
cardinfo->SD_cid.ManufactDate |= tmp;
|
||
|
||
/*!< Byte 15 */
|
||
tmp = (uint8_t)(CID_Tab[3] & 0x000000FF);
|
||
cardinfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1;
|
||
cardinfo->SD_cid.Reserved2 = 1;
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Enables wide bus opeartion for the requeseted card if supported by
|
||
* card.
|
||
* @param WideMode: Specifies the SD card wide bus mode.
|
||
* This parameter can be one of the following values:
|
||
* @arg SDIO_BusWide_8b: 8-bit data transfer (Only for MMC)
|
||
* @arg SDIO_BusWide_4b: 4-bit data transfer
|
||
* @arg SDIO_BusWide_1b: 1-bit data transfer
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_GetCardStatus(SD_CardStatus *cardstatus)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint8_t tmp = 0;
|
||
|
||
errorstatus = SD_SendSDStatus((uint32_t *)SDSTATUS_Tab);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Byte 0 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[0] & 0xC0) >> 6);
|
||
cardstatus->DAT_BUS_WIDTH = tmp;
|
||
|
||
/*!< Byte 0 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[0] & 0x20) >> 5);
|
||
cardstatus->SECURED_MODE = tmp;
|
||
|
||
/*!< Byte 2 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[2] & 0xFF));
|
||
cardstatus->SD_CARD_TYPE = tmp << 8;
|
||
|
||
/*!< Byte 3 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[3] & 0xFF));
|
||
cardstatus->SD_CARD_TYPE |= tmp;
|
||
|
||
/*!< Byte 4 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[4] & 0xFF);
|
||
cardstatus->SIZE_OF_PROTECTED_AREA = tmp << 24;
|
||
|
||
/*!< Byte 5 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[5] & 0xFF);
|
||
cardstatus->SIZE_OF_PROTECTED_AREA |= tmp << 16;
|
||
|
||
/*!< Byte 6 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[6] & 0xFF);
|
||
cardstatus->SIZE_OF_PROTECTED_AREA |= tmp << 8;
|
||
|
||
/*!< Byte 7 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[7] & 0xFF);
|
||
cardstatus->SIZE_OF_PROTECTED_AREA |= tmp;
|
||
|
||
/*!< Byte 8 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[8] & 0xFF));
|
||
cardstatus->SPEED_CLASS = tmp;
|
||
|
||
/*!< Byte 9 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[9] & 0xFF));
|
||
cardstatus->PERFORMANCE_MOVE = tmp;
|
||
|
||
/*!< Byte 10 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[10] & 0xF0) >> 4);
|
||
cardstatus->AU_SIZE = tmp;
|
||
|
||
/*!< Byte 11 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[11] & 0xFF);
|
||
cardstatus->ERASE_SIZE = tmp << 8;
|
||
|
||
/*!< Byte 12 */
|
||
tmp = (uint8_t)(SDSTATUS_Tab[12] & 0xFF);
|
||
cardstatus->ERASE_SIZE |= tmp;
|
||
|
||
/*!< Byte 13 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[13] & 0xFC) >> 2);
|
||
cardstatus->ERASE_TIMEOUT = tmp;
|
||
|
||
/*!< Byte 13 */
|
||
tmp = (uint8_t)((SDSTATUS_Tab[13] & 0x3));
|
||
cardstatus->ERASE_OFFSET = tmp;
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/*
|
||
* Function name:SD_EnableWideBusOperation
|
||
* Description :configure the data width of card(depend on the card type)
|
||
* Input:-WideMode data width
|
||
* @arg SDIO_BusWide_8b: 8-bit data transfer (Only for MMC)
|
||
* @arg SDIO_BusWide_4b: 4-bit data transfer
|
||
* @arg SDIO_BusWide_1b: 1-bit data transfer (default)
|
||
* Input :-SD_Error SD card error status
|
||
* when successfully is SD_OK
|
||
* Call:outside callback
|
||
*/
|
||
SD_Error SD_EnableWideBusOperation(uint32_t WideMode)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
/*!< MMC Card doesn't support this feature */
|
||
if (SDIO_MULTIMEDIA_CARD == SDCardInfo.CardType)
|
||
{
|
||
errorstatus = SD_UNSUPPORTED_FEATURE;
|
||
return(errorstatus);
|
||
}
|
||
else if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == SDCardInfo.CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == SDCardInfo.CardType)
|
||
|| (SDIO_HIGH_CAPACITY_SD_CARD == SDCardInfo.CardType))
|
||
{
|
||
if (SDIO_BusWide_8b == WideMode)
|
||
{
|
||
errorstatus = SD_UNSUPPORTED_FEATURE;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_BusWide_4b == WideMode)
|
||
{
|
||
errorstatus = SDEnWideBus(ENABLE); //ACMD6 set bus wide
|
||
|
||
if (SD_OK == errorstatus)
|
||
{
|
||
/*!< Configure the SDIO peripheral */
|
||
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
|
||
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
|
||
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
|
||
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
|
||
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_4b;
|
||
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
|
||
SDIO_Init(&SDIO_InitStructure);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
errorstatus = SDEnWideBus(DISABLE);
|
||
|
||
if (SD_OK == errorstatus)
|
||
{
|
||
/*!< Configure the SDIO peripheral */
|
||
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
|
||
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
|
||
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
|
||
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
|
||
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
|
||
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
|
||
SDIO_Init(&SDIO_InitStructure);
|
||
}
|
||
}
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*
|
||
* Function name:SD_SelectDeselect
|
||
* Description:cmd7,select the addr card, if addr = 0, cancel all the card
|
||
* Input :-card address
|
||
* Output :-SD_Error SD card error status
|
||
* when successfully is SD_OK
|
||
* Call :outside callback
|
||
*/
|
||
SD_Error SD_SelectDeselect(uint32_t addr)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
/*!< Send CMD7 SDIO_SEL_DESEL_CARD */
|
||
SDIO_CmdInitStructure.SDIO_Argument = addr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEL_DESEL_CARD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SEL_DESEL_CARD);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Allows to read one block from a specified address in a card. The Data
|
||
* transfer can be managed by DMA mode or Polling mode.
|
||
* @note This operation should be followed by two functions to check if the
|
||
* DMA Controller and SD Card status.
|
||
* - SD_ReadWaitOperation(): this function insure that the DMA
|
||
* controller has finished all data transfer.
|
||
* - SD_GetStatus(): to check that the SD Card has finished the
|
||
* data transfer and it is ready for data.
|
||
* @param readbuff: pointer to the buffer that will contain the received data
|
||
* @param ReadAddr: Address from where data are to be read.
|
||
* @param BlockSize: the SD card Data block size. The Block size should be 512.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
#if defined (SD_POLLING_MODE)
|
||
uint32_t count = 0, *tempbuff = (uint32_t *)readbuff;
|
||
#endif
|
||
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0; //transfer end flag , set 1 in irq
|
||
StopCondition = 0;
|
||
|
||
SDIO->DCTRL = 0x0;
|
||
|
||
|
||
if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
BlockSize = 512;
|
||
ReadAddr /= 512;
|
||
}
|
||
|
||
|
||
/* Set Block Size for Card */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
/*!< Send CMD17 READ_SINGLE_BLOCK */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
#if defined (SD_POLLING_MODE)
|
||
/*!< In case of single block transfer, no need of stop transfer at all.*/
|
||
/*!< Polling mode */
|
||
while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))
|
||
{
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)
|
||
{
|
||
for (count = 0; count < 8; count++)
|
||
{
|
||
*(tempbuff + count) = SDIO_ReadData();
|
||
}
|
||
tempbuff += 8;
|
||
}
|
||
}
|
||
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
|
||
errorstatus = SD_DATA_CRC_FAIL;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
|
||
errorstatus = SD_RX_OVERRUN;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
|
||
errorstatus = SD_START_BIT_ERR;
|
||
return(errorstatus);
|
||
}
|
||
while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
|
||
{
|
||
*tempbuff = SDIO_ReadData();
|
||
tempbuff++;
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
#elif defined (SD_DMA_MODE)
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SDIO_DMACmd(ENABLE);
|
||
SD_DMA_RxConfig((uint32_t *)readbuff, BlockSize);
|
||
#endif
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief Allows to read blocks from a specified address in a card. The Data
|
||
* transfer can be managed by DMA mode or Polling mode.
|
||
* @note This operation should be followed by two functions to check if the
|
||
* DMA Controller and SD Card status.
|
||
* - SD_ReadWaitOperation(): this function insure that the DMA
|
||
* controller has finished all data transfer.
|
||
* - SD_GetStatus(): to check that the SD Card has finished the
|
||
* data transfer and it is ready for data.
|
||
* @param readbuff: pointer to the buffer that will contain the received data.
|
||
* @param ReadAddr: Address from where data are to be read.
|
||
* @param BlockSize: the SD card Data block size. The Block size should be 512.
|
||
* @param NumberOfBlocks: number of blocks to be read.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0;
|
||
StopCondition = 1;
|
||
|
||
SDIO->DCTRL = 0x0; //reset data control register
|
||
|
||
if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
BlockSize = 512;
|
||
ReadAddr /= 512;
|
||
}
|
||
|
||
/*!< Set Block Size for Card */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
/*!< Send CMD18 READ_MULT_BLOCK with argument data address */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_READ_MULT_BLOCK);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SDIO_DMACmd(ENABLE);
|
||
SD_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * BlockSize));
|
||
return(errorstatus);
|
||
}
|
||
|
||
SD_Error SD_LBA_ReadBlocks(uint8_t *readbuff, uint32_t BlockAddr, uint32_t NumberOfBlocks)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0;
|
||
StopCondition = 1;
|
||
|
||
SDIO->DCTRL = 0x0; //reset data control register
|
||
|
||
if (SDCardInfo.CardType != SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
//BlockSize = 512;
|
||
BlockAddr = BlockAddr * 512;
|
||
}
|
||
|
||
/*!< Set Block Size for Card,cmd16, SDSC can set block size, SDHC block size is 512, not support cmd16*/
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = 512;
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_SET_BLOCKLEN | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);*/
|
||
SDIO->DTIMER = SD_DATATIMEOUT;
|
||
SDIO->DLEN = NumberOfBlocks * 512;
|
||
SDIO->DCTRL = (SDIO->DCTRL & 0xFFFFFF08) | ((uint32_t) 9 << 4) | SDIO_TransferDir_ToSDIO | SDIO_DPSM_Enable;
|
||
|
||
/*!< Send CMD18 READ_MULT_BLOCK with argument data address */
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = (uint32_t) BlockAddr;
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_READ_MULT_BLOCK | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_READ_MULT_BLOCK);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SDIO_DMACmd(ENABLE);
|
||
SD_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * 512));
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief This function waits until the SDIO DMA data transfer is finished.
|
||
* This function should be called after SDIO_ReadMultiBlocks() function
|
||
* to insure that all data sent by the card are already transferred by
|
||
* the DMA controller.
|
||
* @param None.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_WaitReadOperation(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t timeout;
|
||
timeout = SD_DATATIMEOUT;
|
||
while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK)&&(timeout > 0))
|
||
{
|
||
timeout--;
|
||
}
|
||
|
||
DMAEndOfTransfer = 0x00;
|
||
|
||
timeout = SD_DATATIMEOUT;
|
||
|
||
if (TransferError != SD_OK)
|
||
{
|
||
return(TransferError);
|
||
}
|
||
|
||
//wait for transfering data over or timeout
|
||
while(((SDIO->STA & SDIO_FLAG_RXACT)) && (timeout > 0))
|
||
{
|
||
timeout--;
|
||
}
|
||
|
||
//if StopCondition, stop transfer data
|
||
if (StopCondition == 1)
|
||
{
|
||
errorstatus = SD_StopTransfer();
|
||
}
|
||
|
||
//check if timeout
|
||
if ((timeout == 0) && (errorstatus == SD_OK))
|
||
{
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
}
|
||
|
||
//clear static flag
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
//check transfer is ok or not
|
||
if (TransferError != SD_OK)
|
||
{
|
||
return(TransferError);
|
||
}
|
||
else
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Allows to write one block starting from a specified address in a card.
|
||
* The Data transfer can be managed by DMA mode or Polling mode.
|
||
* @note This operation should be followed by two functions to check if the
|
||
* DMA Controller and SD Card status.
|
||
* - SD_ReadWaitOperation(): this function insure that the DMA
|
||
* controller has finished all data transfer.
|
||
* - SD_GetStatus(): to check that the SD Card has finished the
|
||
* data transfer and it is ready for data.
|
||
* @param writebuff: pointer to the buffer that contain the data to be transferred.
|
||
* @param WriteAddr: Address from where data are to be read.
|
||
* @param BlockSize: the SD card Data block size. The Block size should be 512.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
#if defined (SD_POLLING_MODE)
|
||
uint32_t bytestransferred = 0, count = 0, restwords = 0;
|
||
uint32_t *tempbuff = (uint32_t *)writebuff;
|
||
#endif
|
||
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0;
|
||
StopCondition = 0;
|
||
|
||
SDIO->DCTRL = 0x0;
|
||
|
||
|
||
if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
BlockSize = 512;
|
||
WriteAddr /= 512;
|
||
}
|
||
|
||
/*!< Set Block Size for Card,cmd16, SDSC can set block size, SDHC block size is 512, not support cmd16*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*********************************************************************************/
|
||
|
||
/*!< Send CMD24 WRITE_SINGLE_BLOCK */
|
||
SDIO_CmdInitStructure.SDIO_Argument = WriteAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //R1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_WRITE_SINGLE_BLOCK);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4; //SDIO_DataBlockSize_512b
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable; //enable DPSM mode
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
/*!< In case of single data block transfer no need of stop command at all */
|
||
#if defined (SD_POLLING_MODE)
|
||
while (!(SDIO->STA & (SDIO_FLAG_DBCKEND | SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR)))
|
||
{
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)
|
||
{
|
||
if ((512 - bytestransferred) < 32)
|
||
{
|
||
restwords = ((512 - bytestransferred) % 4 == 0) ? ((512 - bytestransferred) / 4) : (( 512 - bytestransferred) / 4 + 1);
|
||
for (count = 0; count < restwords; count++, tempbuff++, bytestransferred += 4)
|
||
{
|
||
SDIO_WriteData(*tempbuff);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (count = 0; count < 8; count++)
|
||
{
|
||
SDIO_WriteData(*(tempbuff + count));
|
||
}
|
||
tempbuff += 8;
|
||
bytestransferred += 32;
|
||
}
|
||
}
|
||
}
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
|
||
errorstatus = SD_DATA_CRC_FAIL;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
|
||
errorstatus = SD_TX_UNDERRUN;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
|
||
errorstatus = SD_START_BIT_ERR;
|
||
return(errorstatus);
|
||
}
|
||
#elif defined (SD_DMA_MODE)
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SD_DMA_TxConfig((uint32_t *)writebuff, BlockSize);
|
||
SDIO_DMACmd(ENABLE);
|
||
#endif
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Allows to write blocks starting from a specified address in a card.
|
||
* The Data transfer can be managed by DMA mode only.
|
||
* @note This operation should be followed by two functions to check if the
|
||
* DMA Controller and SD Card status.
|
||
* - SD_ReadWaitOperation(): this function insure that the DMA
|
||
* controller has finished all data transfer.
|
||
* - SD_GetStatus(): to check that the SD Card has finished the
|
||
* data transfer and it is ready for data.
|
||
* @param WriteAddr: Address from where data are to be read.
|
||
* @param writebuff: pointer to the buffer that contain the data to be transferred.
|
||
* @param BlockSize: the SD card Data block size. The Block size should be 512.
|
||
* @param NumberOfBlocks: number of blocks to be written.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
|
||
/*
|
||
* Function name:SD_WriteMultiBlocks
|
||
* Description:start to write blocks from input address only supported in DMA mode
|
||
Attention:after SD_WriteMultiBlocks, need to call
|
||
SD_WaitWriteOperation() wait for DMA is stop
|
||
SD_GetStatus() check the FIFO transfer between card and SDIO is over or not
|
||
* Input:
|
||
* @param WriteAddr: Address from where data are to be read.
|
||
* @param writebuff: pointer to the buffer that contain the data to be transferred.
|
||
* @param BlockSize: the SD card Data block size. The Block size should be 512.
|
||
* @param NumberOfBlocks: number of blocks to be written.
|
||
* Output :SD error status
|
||
*/
|
||
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
__IO uint32_t count = 0;
|
||
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0;
|
||
StopCondition = 1;
|
||
|
||
SDIO->DCTRL = 0x0;
|
||
|
||
if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
BlockSize = 512;
|
||
WriteAddr /= 512;
|
||
}
|
||
|
||
/*******************add, avoid died in checking DMA*************************************/
|
||
/*!< Set Block Size for Card,cmd16, SDSC can set block size, SDHC block size is 512, not support cmd16*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*********************************************************************************/
|
||
|
||
/*!< To improve performance */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; // cmd55
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*!< To improve performance */ // pre-erased
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)NumberOfBlocks;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT; //CMD23
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCK_COUNT);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/*!< Send CMD25 WRITE_MULT_BLOCK with argument data address */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)WriteAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_WRITE_MULT_BLOCK);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SDIO_DMACmd(ENABLE);
|
||
SD_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * BlockSize));
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
SD_Error SD_LBA_WriteBlocks(uint8_t *writebuff, uint32_t BlockAddr, uint32_t NumberOfBlocks)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
__IO uint32_t count = 0;
|
||
|
||
TransferError = SD_OK;
|
||
TransferEnd = 0;
|
||
StopCondition = 1;
|
||
|
||
SDIO->DCTRL = 0x0;
|
||
|
||
if (SDCardInfo.CardType != SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{
|
||
//BlockSize = 512;
|
||
BlockAddr = BlockAddr * 512;
|
||
}
|
||
|
||
/*******************add, avoid died in checking DMA*************************************/
|
||
/*!< Set Block Size for Card,cmd16, SDSC can set block size, SDHC block size is 512, not support cmd16*/
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = 512;
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_SET_BLOCKLEN | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*********************************************************************************/
|
||
|
||
/*!< To improve performance */
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; // cmd55
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = (uint32_t) (RCA << 16);
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_APP_CMD | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*!< To improve performance */ // pre-erased,when writing multi blocks
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)NumberOfBlocks;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT; //CMD23
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = NumberOfBlocks;
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_SET_BLOCK_COUNT | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCK_COUNT);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/*!< Send CMD25 WRITE_MULT_BLOCK with argument data address */
|
||
/*SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)WriteAddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);*/
|
||
SDIO->ARG = BlockAddr;
|
||
SDIO->CMD = (SDIO->CMD & 0xFFFFF800) | SD_CMD_WRITE_MULT_BLOCK | SDIO_Response_Short | SDIO_CPSM_Enable;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_WRITE_MULT_BLOCK);
|
||
|
||
if (SD_OK != errorstatus)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block; //0x00000000
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);*/
|
||
SDIO->DTIMER = SD_DATATIMEOUT;
|
||
SDIO->DLEN = NumberOfBlocks * 512;
|
||
SDIO->DCTRL = (SDIO->DCTRL & 0xFFFFFF08) | ((uint32_t) 9 << 4) | SDIO_TransferDir_ToCard | SDIO_DPSM_Enable;
|
||
|
||
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, ENABLE);
|
||
SDIO_DMACmd(ENABLE);
|
||
SD_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * 512));
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief This function waits until the SDIO DMA data transfer is finished.
|
||
* This function should be called after SDIO_WriteBlock() and
|
||
* SDIO_WriteMultiBlocks() function to insure that all data sent by the
|
||
* card are already transferred by the DMA controller.
|
||
* @param None.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_WaitWriteOperation(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t timeout;
|
||
timeout = SD_DATATIMEOUT;
|
||
|
||
//wait for DMA Transfer stop
|
||
while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK)&& (timeout > 0))
|
||
{
|
||
timeout--;
|
||
}
|
||
|
||
DMAEndOfTransfer = 0x00;
|
||
|
||
timeout = SD_DATATIMEOUT;
|
||
|
||
while(((SDIO->STA & SDIO_FLAG_TXACT)) && (timeout > 0))
|
||
{
|
||
timeout--;
|
||
}
|
||
|
||
if (StopCondition == 1)
|
||
{
|
||
errorstatus = SD_StopTransfer();
|
||
}
|
||
|
||
if ((timeout == 0) && (errorstatus == SD_OK))
|
||
{
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
if (TransferError != SD_OK)
|
||
{
|
||
return(TransferError);
|
||
}
|
||
else
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Gets the cuurent data transfer state.
|
||
* @param None
|
||
* @retval SDTransferState: Data Transfer state.
|
||
* This value can be:
|
||
* - SD_TRANSFER_OK: No data transfer is acting
|
||
* - SD_TRANSFER_BUSY: Data transfer is acting
|
||
*/
|
||
SDTransferState SD_GetTransferState(void)
|
||
{
|
||
if (SDIO->STA & (SDIO_FLAG_TXACT | SDIO_FLAG_RXACT))
|
||
{
|
||
return(SD_TRANSFER_BUSY);
|
||
}
|
||
else
|
||
{
|
||
return(SD_TRANSFER_OK);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Aborts an ongoing data transfer.
|
||
* @param None
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_StopTransfer(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
/*!< Send CMD12 STOP_TRANSMISSION */
|
||
SDIO->ARG = 0x0;
|
||
SDIO->CMD = 0x44C;
|
||
errorstatus = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Allows to erase memory area specified for the given card.
|
||
* @param startaddr: the start address.
|
||
* @param endaddr: the end address.
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t delay = 0;
|
||
__IO uint32_t maxdelay = 0;
|
||
uint8_t cardstate = 0;
|
||
|
||
/*!< Check if the card coomnd class supports erase command */
|
||
if (((CSD_Tab[1] >> 20) & SD_CCCC_ERASE) == 0)
|
||
{
|
||
errorstatus = SD_REQUEST_NOT_APPLICABLE;
|
||
return(errorstatus);
|
||
}
|
||
|
||
maxdelay = 120000 / ((SDIO->CLKCR & 0xFF) + 2); //delay
|
||
|
||
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) //card is locked
|
||
{
|
||
errorstatus = SD_LOCK_UNLOCK_FAILED;
|
||
return(errorstatus);
|
||
}
|
||
|
||
if (SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
|
||
{ //SDHC address param is block address, SDSC is byte address
|
||
startaddr /= 512;
|
||
endaddr /= 512;
|
||
}
|
||
|
||
/*!< According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */
|
||
if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == SDCardInfo.CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == SDCardInfo.CardType)
|
||
|| (SDIO_HIGH_CAPACITY_SD_CARD == SDCardInfo.CardType))
|
||
{
|
||
/*!< Send CMD32 SD_ERASE_GRP_START with argument as addr */
|
||
SDIO_CmdInitStructure.SDIO_Argument = startaddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_START;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //R1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_START);
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Send CMD33 SD_ERASE_GRP_END with argument as addr */
|
||
SDIO_CmdInitStructure.SDIO_Argument = endaddr;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_END;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_END);
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
}
|
||
|
||
/*!< Send CMD38 ERASE */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ERASE;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_ERASE);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
for (delay = 0; delay < maxdelay; delay++)
|
||
{}
|
||
|
||
/*!< Wait till the card is in programming state */
|
||
errorstatus = IsCardProgramming(&cardstate);
|
||
delay = SD_DATATIMEOUT;
|
||
while ((errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate)))
|
||
{
|
||
errorstatus = IsCardProgramming(&cardstate);
|
||
delay--;
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Returns the current card's status.
|
||
* @param pcardstatus: pointer to the buffer that will contain the SD card
|
||
* status (Card Status register).
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_SendStatus(uint32_t *pcardstatus)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
SDIO->ARG = (uint32_t) RCA << 16;
|
||
SDIO->CMD = 0x44D;
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SEND_STATUS);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
*pcardstatus = SDIO->RESP1;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/**
|
||
* @brief Returns the current SD card's status.
|
||
* @param psdstatus: pointer to the buffer that will contain the SD card status
|
||
* (SD Status register).
|
||
* @retval SD_Error: SD Card Error code.
|
||
*/
|
||
SD_Error SD_SendSDStatus(uint32_t *psdstatus)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t count = 0;
|
||
|
||
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
|
||
{
|
||
errorstatus = SD_LOCK_UNLOCK_FAILED;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Set block size for card if it is not equal to current block size for card. */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 64;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< CMD55 */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = 64;
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_64b;
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
/*!< Send ACMD13 SD_APP_STAUS with argument as card's RCA.*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_STAUS;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
errorstatus = CmdResp1Error(SD_CMD_SD_APP_STAUS);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))
|
||
{
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)
|
||
{
|
||
for (count = 0; count < 8; count++)
|
||
{
|
||
*(psdstatus + count) = SDIO_ReadData();
|
||
}
|
||
psdstatus += 8;
|
||
}
|
||
}
|
||
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
|
||
errorstatus = SD_DATA_CRC_FAIL;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
|
||
errorstatus = SD_RX_OVERRUN;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
|
||
errorstatus = SD_START_BIT_ERR;
|
||
return(errorstatus);
|
||
}
|
||
|
||
while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
|
||
{
|
||
*psdstatus = SDIO_ReadData();
|
||
psdstatus++;
|
||
}
|
||
|
||
/*!< Clear all the static status flags*/
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
static SD_Error CmdError(void)
|
||
{
|
||
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t timeout;
|
||
|
||
timeout = SDIO_CMD0TIMEOUT; /*!< 10000 */
|
||
|
||
/*check the cmd is send normal or not*/
|
||
while ((timeout > 0) && (SDIO_GetFlagStatus(SDIO_FLAG_CMDSENT) == RESET))
|
||
{
|
||
timeout--;
|
||
}
|
||
|
||
if (timeout == 0)
|
||
{
|
||
KPrintf("\nsdio:2098:timeout\n");
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//clear static flag
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/*
|
||
* Function name:CmdResp7Error
|
||
* Description:check response R7 cmd
|
||
* Input :
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error CmdResp7Error(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t status;
|
||
uint32_t timeout = SDIO_CMD0TIMEOUT;
|
||
|
||
status = SDIO->STA; //read SDIO status register of stm32
|
||
|
||
/* Command response received (CRC check failed) :Command response received (CRC check passed):Command response timeout */
|
||
|
||
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) && (timeout > 0))
|
||
{
|
||
timeout--;
|
||
status = SDIO->STA;
|
||
}
|
||
//not support cmd8
|
||
if ((timeout == 0) || (status & SDIO_FLAG_CTIMEOUT))
|
||
{
|
||
/*!< Card is not V2.0 complient or card does not support the set voltage range */
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
|
||
return(errorstatus);
|
||
}
|
||
|
||
if (status & SDIO_FLAG_CMDREND)
|
||
{
|
||
/*!< Card is SD V2.0 compliant */
|
||
errorstatus = SD_OK;
|
||
SDIO_ClearFlag(SDIO_FLAG_CMDREND);
|
||
return(errorstatus);
|
||
}
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/*
|
||
* Function name:CmdResp1Error
|
||
* Description:check response R1 cmd
|
||
* Input :
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error CmdResp1Error(uint8_t cmd)
|
||
{
|
||
/*wait for these status*/
|
||
while (!(SDIO->STA & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
|
||
{;}
|
||
|
||
SDIO->ICR = SDIO_STATIC_FLAGS; //release interrupt sign
|
||
|
||
return (SD_Error)(SDIO->RESP1 & SD_OCR_ERRORBITS);
|
||
}
|
||
|
||
/*
|
||
* Function name:CmdResp3Error
|
||
* Description:check response R3 cmd
|
||
* Input :
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error CmdResp3Error(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t status;
|
||
|
||
status = SDIO->STA;
|
||
|
||
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
|
||
{
|
||
status = SDIO->STA;
|
||
}
|
||
|
||
if (status & SDIO_FLAG_CTIMEOUT)
|
||
{
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
|
||
return(errorstatus);
|
||
}
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*
|
||
* Function name:CmdResp2Error
|
||
* Description:check response R6 cmd
|
||
* Input :
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error CmdResp2Error(void)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t status;
|
||
|
||
status = SDIO->STA;
|
||
|
||
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND)))
|
||
{
|
||
status = SDIO->STA;
|
||
}
|
||
|
||
if (status & SDIO_FLAG_CTIMEOUT)
|
||
{
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
|
||
return(errorstatus);
|
||
}
|
||
else if (status & SDIO_FLAG_CCRCFAIL)
|
||
{
|
||
errorstatus = SD_CMD_CRC_FAIL;
|
||
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*
|
||
* Function name:CmdResp6Error
|
||
* Description:check response R6 cmd
|
||
* Input :cmd ,
|
||
prca address
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t status;
|
||
uint32_t ResponseR1;
|
||
|
||
status = SDIO->STA;
|
||
|
||
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND)))
|
||
{
|
||
status = SDIO->STA;
|
||
}
|
||
|
||
if (status & SDIO_FLAG_CTIMEOUT)
|
||
{
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
|
||
return(errorstatus);
|
||
}
|
||
else if (status & SDIO_FLAG_CCRCFAIL)
|
||
{
|
||
errorstatus = SD_CMD_CRC_FAIL;
|
||
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Check response received is of desired command */
|
||
if (SDIO_GetCommandResponse() != cmd) //check get cmd successfully
|
||
{
|
||
errorstatus = SD_ILLEGAL_CMD;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
/*!< We have received response, retrieve it. */
|
||
ResponseR1 = SDIO_GetResponse(SDIO_RESP1);
|
||
|
||
/*SD_ALLZERO means get rca successfully*/
|
||
if (SD_ALLZERO == (ResponseR1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
|
||
{
|
||
*prca = (uint16_t) (ResponseR1 >> 16);//>>16 bit, rca
|
||
return(errorstatus);
|
||
}
|
||
|
||
if (ResponseR1 & SD_R6_GENERAL_UNKNOWN_ERROR)
|
||
{
|
||
return(SD_GENERAL_UNKNOWN_ERROR);
|
||
}
|
||
|
||
if (ResponseR1 & SD_R6_ILLEGAL_CMD)
|
||
{
|
||
return(SD_ILLEGAL_CMD);
|
||
}
|
||
|
||
if (ResponseR1 & SD_R6_COM_CRC_FAILED)
|
||
{
|
||
return(SD_COM_CRC_FAILED);
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*
|
||
* Function name:SDEnWideBus
|
||
* Description :enable or disable SDIO 4bit mode
|
||
* Input : ENABLE or DISABLE
|
||
* Output :SD error status
|
||
*/
|
||
static SD_Error SDEnWideBus(FunctionalState NewState)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
|
||
uint32_t scr[2] = {0, 0};
|
||
|
||
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) //check card is locked or not
|
||
{
|
||
errorstatus = SD_LOCK_UNLOCK_FAILED;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Get SCR Register */
|
||
errorstatus = FindSCR(RCA, scr);//get scr register and store to scr[]
|
||
|
||
if (errorstatus != SD_OK) //degug,crc error,scr can not read data
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< If wide bus operation to be enabled */
|
||
if (NewState == ENABLE)
|
||
{
|
||
/*!< If requested card supports wide bus operation */
|
||
if ((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) //check card if support 4 bit
|
||
{
|
||
/*!< Send CMD55 APP_CMD with argument as card's RCA.*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Send ACMD6 APP_CMD with argument as 2 for wide bus mode */
|
||
/*4bit acmd6*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x2;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_SD_SET_BUSWIDTH);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
return(errorstatus);
|
||
}
|
||
else
|
||
{
|
||
errorstatus = SD_REQUEST_NOT_APPLICABLE;
|
||
return(errorstatus);
|
||
}
|
||
} /*!< If wide bus operation to be disabled */
|
||
else
|
||
{
|
||
/*!< If requested card supports 1 bit mode operation */
|
||
if ((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO)
|
||
{
|
||
/*!< Send CMD55 APP_CMD with argument as card's RCA.*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Send ACMD6 APP_CMD with argument as 0 for single bus mode */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_SD_SET_BUSWIDTH);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
else
|
||
{
|
||
errorstatus = SD_REQUEST_NOT_APPLICABLE;
|
||
return(errorstatus);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* Function name:IsCardProgramming
|
||
* Description:check SD card if is writing or reading inside the chip
|
||
* Input:SD state pointer
|
||
* Output:SD error status
|
||
*/
|
||
static SD_Error IsCardProgramming(uint8_t *pstatus)
|
||
{
|
||
SD_Error errorstatus = SD_OK;
|
||
__IO uint32_t respR1 = 0, status = 0;
|
||
|
||
/*cmd13 send card status register, store to sdio_sta register of m3*/
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16; //card address param
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
status = SDIO->STA;
|
||
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
|
||
{
|
||
status = SDIO->STA;
|
||
}
|
||
/*check status*/
|
||
if (status & SDIO_FLAG_CTIMEOUT)
|
||
{
|
||
errorstatus = SD_CMD_RSP_TIMEOUT;
|
||
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
|
||
return(errorstatus);
|
||
}
|
||
else if (status & SDIO_FLAG_CCRCFAIL)
|
||
{
|
||
errorstatus = SD_CMD_CRC_FAIL;
|
||
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
|
||
return(errorstatus);
|
||
}
|
||
|
||
status = (uint32_t)SDIO_GetCommandResponse();
|
||
|
||
/*!< Check response received is of desired command */
|
||
if (status != SD_CMD_SEND_STATUS)
|
||
{
|
||
errorstatus = SD_ILLEGAL_CMD;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
|
||
/*!< We have received response, retrieve it for analysis */
|
||
respR1 = SDIO_GetResponse(SDIO_RESP1);
|
||
|
||
/*!< Find out card status */
|
||
*pstatus = (uint8_t) ((respR1 >> 9) & 0x0000000F); //status[12:9] :cardstate
|
||
|
||
if ((respR1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_ADDR_OUT_OF_RANGE)
|
||
{
|
||
return(SD_ADDR_OUT_OF_RANGE);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_ADDR_MISALIGNED)
|
||
{
|
||
return(SD_ADDR_MISALIGNED);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_BLOCK_LEN_ERR)
|
||
{
|
||
return(SD_BLOCK_LEN_ERR);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_ERASE_SEQ_ERR)
|
||
{
|
||
return(SD_ERASE_SEQ_ERR);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_BAD_ERASE_PARAM)
|
||
{
|
||
return(SD_BAD_ERASE_PARAM);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_WRITE_PROT_VIOLATION)
|
||
{
|
||
return(SD_WRITE_PROT_VIOLATION);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_LOCK_UNLOCK_FAILED)
|
||
{
|
||
return(SD_LOCK_UNLOCK_FAILED);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_COM_CRC_FAILED)
|
||
{
|
||
return(SD_COM_CRC_FAILED);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_ILLEGAL_CMD)
|
||
{
|
||
return(SD_ILLEGAL_CMD);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_CARD_ECC_FAILED)
|
||
{
|
||
return(SD_CARD_ECC_FAILED);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_CC_ERROR)
|
||
{
|
||
return(SD_CC_ERROR);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_GENERAL_UNKNOWN_ERROR)
|
||
{
|
||
return(SD_GENERAL_UNKNOWN_ERROR);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_STREAM_READ_UNDERRUN)
|
||
{
|
||
return(SD_STREAM_READ_UNDERRUN);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_STREAM_WRITE_OVERRUN)
|
||
{
|
||
return(SD_STREAM_WRITE_OVERRUN);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_CID_CSD_OVERWRIETE)
|
||
{
|
||
return(SD_CID_CSD_OVERWRITE);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_WP_ERASE_SKIP)
|
||
{
|
||
return(SD_WP_ERASE_SKIP);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_CARD_ECC_DISABLED)
|
||
{
|
||
return(SD_CARD_ECC_DISABLED);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_ERASE_RESET)
|
||
{
|
||
return(SD_ERASE_RESET);
|
||
}
|
||
|
||
if (respR1 & SD_OCR_AKE_SEQ_ERROR)
|
||
{
|
||
return(SD_AKE_SEQ_ERROR);
|
||
}
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
static SD_Error FindSCR(uint16_t rca, uint32_t *pscr)
|
||
{
|
||
|
||
uint32_t index = 0;
|
||
SD_Error errorstatus = SD_OK;
|
||
uint32_t tempscr[2] = {0, 0};
|
||
|
||
/*!< Set Block Size To 8 Bytes */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)8; //SDHC card not support configure
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN; // cmd16
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Send CMD55 APP_CMD with argument as card's RCA */
|
||
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
/*set recv data register*/
|
||
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
|
||
SDIO_DataInitStructure.SDIO_DataLength = 8; //8byte,64 bit
|
||
SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_8b ; //block size 8 byte
|
||
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
|
||
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
|
||
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
|
||
SDIO_DataConfig(&SDIO_DataInitStructure);
|
||
|
||
/*!< Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
|
||
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
|
||
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_SEND_SCR;
|
||
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
|
||
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
|
||
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
|
||
SDIO_SendCommand(&SDIO_CmdInitStructure);
|
||
|
||
errorstatus = CmdResp1Error(SD_CMD_SD_APP_SEND_SCR);
|
||
|
||
if (errorstatus != SD_OK)
|
||
{
|
||
return(errorstatus);
|
||
}
|
||
|
||
while (!(SDIO->STA & (SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND| SDIO_FLAG_STBITERR)))
|
||
{
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) //check the data
|
||
{
|
||
*(tempscr + index) = SDIO_ReadData();
|
||
index++;
|
||
|
||
//add check
|
||
if(index > 1 )
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
|
||
errorstatus = SD_DATA_TIMEOUT;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
|
||
errorstatus = SD_DATA_CRC_FAIL;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
|
||
errorstatus = SD_RX_OVERRUN;
|
||
return(errorstatus);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
|
||
errorstatus = SD_START_BIT_ERR;
|
||
return(errorstatus);
|
||
}
|
||
|
||
/*!< Clear all the static flags */
|
||
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
|
||
|
||
*(pscr + 1) = ((tempscr[0] & SD_0TO7BITS) << 24) | ((tempscr[0] & SD_8TO15BITS) << 8) | ((tempscr[0] & SD_16TO23BITS) >> 8) | ((tempscr[0] & SD_24TO31BITS) >> 24);
|
||
|
||
*(pscr) = ((tempscr[1] & SD_0TO7BITS) << 24) | ((tempscr[1] & SD_8TO15BITS) << 8) | ((tempscr[1] & SD_16TO23BITS) >> 8) | ((tempscr[1] & SD_24TO31BITS) >> 24);
|
||
|
||
return(errorstatus);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief Converts the number of bytes in power of two and returns the power.
|
||
* @param NumberOfBytes: number of bytes.
|
||
* @retval None
|
||
*/
|
||
uint8_t convert_from_bytes_to_power_of_two(uint16_t NumberOfBytes)
|
||
{
|
||
uint8_t count = 0;
|
||
|
||
while (NumberOfBytes != 1)
|
||
{
|
||
NumberOfBytes >>= 1;
|
||
count++;
|
||
}
|
||
return(count);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
void SD_ProcessDMAIRQ()
|
||
{
|
||
#ifdef SD_SDIO_DMA_STREAM3
|
||
{
|
||
if (DMA2->LISR&SD_SDIO_DMA_FLAG_TCIF)
|
||
{
|
||
DMAEndOfTransfer=0x01;
|
||
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_TCIF | SD_SDIO_DMA_FLAG_FEIF);
|
||
}
|
||
}
|
||
#elif defined SD_SDIO_DMA_STREAM6
|
||
{
|
||
if (DMA2->HISR&SD_SDIO_DMA_FLAG_TCIF)
|
||
{
|
||
DMAEndOfTransfer=0x01;
|
||
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_TCIF | SD_SDIO_DMA_FLAG_FEIF);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
SD_Error SD_ProcessIRQSrc(void)
|
||
{
|
||
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
|
||
TransferError = SD_DATA_TIMEOUT;
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
|
||
TransferError = SD_DATA_CRC_FAIL;
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
|
||
TransferError = SD_RX_OVERRUN;
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
|
||
TransferError = SD_START_BIT_ERR;
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)
|
||
{
|
||
SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
|
||
}
|
||
else if (SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)
|
||
{
|
||
TransferError = SD_OK;
|
||
TransferEnd = 1;
|
||
SDIO_ClearFlag(SDIO_FLAG_DATAEND);
|
||
}
|
||
SDIO_ClearITPendingBit(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR); //清中断
|
||
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND|SDIO_IT_TXUNDERR|SDIO_IT_STBITERR, DISABLE);
|
||
return(TransferError);
|
||
}
|
||
|
||
|
||
/*****************************END OF FILE*****************************/
|
||
|
||
/*******************************************************************************
|
||
* Function Name : SD_GetCapacity
|
||
* Description : get sd card capacity
|
||
* Input : None
|
||
* Output : None
|
||
* Return : u32 capacity
|
||
* 0: error
|
||
*******************************************************************************/
|
||
uint32_t SD_GetCapacity(void)
|
||
{
|
||
return SDCardInfo.CardCapacity;
|
||
}
|
||
|
||
|
||
void SDIO_IRQHandler(int irq_num, void *arg)
|
||
{
|
||
SD_ProcessIRQSrc();
|
||
}
|
||
DECLARE_HW_IRQ(SDIO_IRQn, SDIO_IRQHandler, NONE);
|
||
|
||
void DMA2_Stream3_IRQHandler(int irq_num, void *arg)
|
||
{
|
||
SD_ProcessDMAIRQ();
|
||
}
|
||
DECLARE_HW_IRQ(DMA2_Stream3_IRQn, DMA2_Stream3_IRQHandler, NONE);
|
||
|
||
void DMA2_Stream6_IRQHandler(int irq_num, void *arg)
|
||
{
|
||
SD_ProcessDMAIRQ();
|
||
}
|
||
DECLARE_HW_IRQ(DMA2_Stream6_IRQn, DMA2_Stream6_IRQHandler, NONE);
|
||
|
||
|