📄 spi_msd_driver.c
字号:
/**
******************************************************************************
* @file SDFatFS/source/SPI_SD_Driver.c
* @author deliang_zhu
* @version V1.0.0
* @date 25/12/2009
* @brief
******************************************************************************
* @copy
*
*/
/* Includes ------------------------------------------------------------------*/
//#include "stm32f10x_lib.h"
#include "config.h"
#define PRINT_INFO TRUE
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MSD_CARDINFO CardInfo;
/*******************************************************************************
* Function Name : MSD_SPIConfig
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void MSD_SPIConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// Enable SPI1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
//SPI1模块对应的SCK、MISO、MOSI为AF引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB6 pin: SD_CS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//_card_power_off();
_card_disable();
// SPI1 low speed mode
MSD_SPIHighSpeed(0);
// Enable SPI1
SPI_Cmd(SPI1, ENABLE);
/*
GPIO_InitTypeDef GPIO_InitStructure;
// Enable SPI1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
// SPI1 -> SD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PD9 pin: CS, PD10 : SD power on
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
_card_power_off();
_card_disable();
//PA2: SD detect
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// SPI1 low speed mode
MSD_SPIHighSpeed(0);
// Enable SPI1
SPI_Cmd(SPI1, ENABLE);
*/
}
/*******************************************************************************
* Function Name : MSD_SPIHighSpeed
* Description :
* Input : - b_high : 1 = 18MHz, 0 = 281.25Hz
* Output : None
* Return : None
*******************************************************************************/
void MSD_SPIHighSpeed(u8 b_high)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
// Speed select
if(b_high == FALSE)
{
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
}
else
{
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
}
SPI_Init(SPI1, &SPI_InitStructure);
}
/*******************************************************************************
* Function Name : MSD_Init
* Description :
* Input : None
* Output : None
* Return :
*******************************************************************************/
u8 MSD_Init(void)
{
u8 r1;
u8 buff[6] = {0};
u16 retry;
/*
// Check, if no card insert, return;
if(!_card_insert())
{
#if PRINT_INFO == TRUE
printf("There is no card detected!\r\n");
#endif
// FATFS error flag
return STA_NODISK;
}
*/
// Power on and delay some times
for(retry=0; retry<0x100; retry++)
{
_card_power_on();
}
// Satrt send 74 clocks at least
for(retry=0; retry<10; retry++)
{
_spi_read_write(DUMMY_BYTE);
}
// Start send CMD0 till return 0x01 means in IDLE state
for(retry=0; retry<0xFFF; retry++)
{
r1 = _send_command(CMD0, 0, 0x95);
if(r1 == 0x01)
{
retry = 0;
break;
}
}
// Timeout return
if(retry == 0xFFF)
{
#if PRINT_INFO == TRUE
printf("Reset card into IDLE state failed!\r\n");
#endif
return 1;
}
// Get the card type, version
r1 = _send_command_hold(CMD8, 0x1AA, 0x87);
// r1=0x05 -> V1.0
if(r1 == 0x05)
{
CardInfo.CardType = CARDTYPE_SDV1;
// End of CMD8, chip disable and dummy byte
_card_disable();
_spi_read_write(DUMMY_BYTE);
// SD1.0/MMC start initialize
// Send CMD55+ACMD41, No-response is a MMC card, otherwise is a SD1.0 card
for(retry=0; retry<0xFFF; retry++)
{
r1 = _send_command(CMD55, 0, 0); // should be return 0x01
if(r1 != 0x01)
{
#if PRINT_INFO == TRUE
printf("Send CMD55 should return 0x01, response=0x%02x\r\n", r1);
#endif
return r1;
}
r1 = _send_command(ACMD41, 0, 0); // should be return 0x00
if(r1 == 0x00)
{
retry = 0;
break;
}
}
// MMC card initialize start
if(retry == 0xFFF)
{
for(retry=0; retry<0xFFF; retry++)
{
r1 = _send_command(CMD1, 0, 0); // should be return 0x00
if(r1 == 0x00)
{
retry = 0;
break;
}
}
// Timeout return
if(retry == 0xFFF)
{
#if PRINT_INFO == TRUE
printf("Send CMD1 should return 0x00, response=0x%02x\r\n", r1);
#endif
return 2;
}
CardInfo.CardType = CARDTYPE_MMC;
#if PRINT_INFO == TRUE
printf("Card Type : MMC\r\n");
#endif
}
// SD1.0 card detected, print information
#if PRINT_INFO == TRUE
else
{
printf("Card Type : SD V1\r\n");
}
#endif
// Set spi speed high
MSD_SPIHighSpeed(1);
// CRC disable
r1 = _send_command(CMD59, 0, 0x01);
if(r1 != 0x00)
{
#if PRINT_INFO == TRUE
printf("Send CMD59 should return 0x00, response=0x%02x\r\n", r1);
#endif
return r1; // response error, return r1
}
// Set the block size
r1 = _send_command(CMD16, MSD_BLOCKSIZE, 0xFF);
if(r1 != 0x00)
{
#if PRINT_INFO == TRUE
printf("Send CMD16 should return 0x00, response=0x%02x\r\n", r1);
#endif
return r1; // response error, return r1
}
}
// r1=0x01 -> V2.x, read OCR register, check version
else if(r1 == 0x01)
{
// 4Bytes returned after CMD8 sent
buff[0] = _spi_read_write(DUMMY_BYTE); //should be 0x00
buff[1] = _spi_read_write(DUMMY_BYTE); //should be 0x00
buff[2] = _spi_read_write(DUMMY_BYTE); //should be 0x01
buff[3] = _spi_read_write(DUMMY_BYTE); //should be 0xAA
// End of CMD8, chip disable and dummy byte
_card_disable();
_spi_read_write(DUMMY_BYTE);
// Check voltage range be 2.7-3.6V
if(buff[2]==0x01 && buff[3]==0xAA)
{
for(retry=0; retry<0xFFF; retry++)
{
r1 = _send_command(CMD55, 0, 0); // should be return 0x01
if(r1!=0x01)
{
#if PRINT_INFO == TRUE
printf("Send CMD55 should return 0x01, response=0x%02x\r\n", r1);
#endif
return r1;
}
r1 = _send_command(ACMD41, 0x40000000, 0); // should be return 0x00
if(r1 == 0x00)
{
retry = 0;
break;
}
}
// Timeout return
if(retry == 0xFFF)
{
#if PRINT_INFO == TRUE
printf("Send ACMD41 should return 0x00, response=0x%02x\r\n", r1);
#endif
return 3;
}
// Read OCR by CMD58
r1 = _send_command_hold(CMD58, 0, 0);
if(r1!=0x00)
{
#if PRINT_INFO == TRUE
printf("Send CMD58 should return 0x00, response=0x%02x\r\n", r1);
#endif
return r1; // response error, return r1
}
buff[0] = _spi_read_write(DUMMY_BYTE);
buff[1] = _spi_read_write(DUMMY_BYTE);
buff[2] = _spi_read_write(DUMMY_BYTE);
buff[3] = _spi_read_write(DUMMY_BYTE);
// End of CMD58, chip disable and dummy byte
_card_disable();
_spi_read_write(DUMMY_BYTE);
// OCR -> CCS(bit30)
// 1: SDV2HC
// 0: SDV2
if(buff[0] & 0x40)
{
CardInfo.CardType = CARDTYPE_SDV2HC;
#if PRINT_INFO == TRUE == 1
printf("Card Type : SD V2HC\r\n");
#endif
}
else
{
CardInfo.CardType = CARDTYPE_SDV2;
#if PRINT_INFO == TRUE == 1
printf("Card Type : SD V2\r\n");
#endif
}
// Set spi speed high
MSD_SPIHighSpeed(1);
}
}
return 0;
}
/*******************************************************************************
* Function Name : MSD_GetCardInfo
* Description :
* Input : - *pCID
* Output : None
* Return : 0:NO_ERR; TRUE: Error
*******************************************************************************/
u8 MSD_GetCardInfo(PMSD_CARDINFO cardinfo)
{
u8 r1;
u8 CSD_Tab[16];
u8 CID_Tab[16];
// Send CMD9, Read CSD
r1 = _send_command(CMD9, 0, 0xFF);
if(r1 != 0x00)
{
return r1;
}
if(_read_buffer(CSD_Tab, 16, RELEASE))
{
return 1;
}
// Send CMD10, Read CID
r1 = _send_command(CMD10, 0, 0xFF);
if(r1 != 0x00)
{
return r1;
}
if(_read_buffer(CID_Tab, 16, RELEASE))
{
return 2;
}
/* Byte 0 */
cardinfo->CSD.CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
cardinfo->CSD.SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
cardinfo->CSD.Reserved1 = CSD_Tab[0] & 0x03;
/* Byte 1 */
cardinfo->CSD.TAAC = CSD_Tab[1] ;
/* Byte 2 */
cardinfo->CSD.NSAC = CSD_Tab[2];
/* Byte 3 */
cardinfo->CSD.MaxBusClkFrec = CSD_Tab[3];
/* Byte 4 */
cardinfo->CSD.CardComdClasses = CSD_Tab[4] << 4;
/* Byte 5 */
cardinfo->CSD.CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;
cardinfo->CSD.RdBlockLen = CSD_Tab[5] & 0x0F;
/* Byte 6 */
cardinfo->CSD.PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
cardinfo->CSD.WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
cardinfo->CSD.RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
cardinfo->CSD.DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
cardinfo->CSD.Reserved2 = 0; /* Reserved */
cardinfo->CSD.DeviceSize = (CSD_Tab[6] & 0x03) << 10;
/* Byte 7 */
cardinfo->CSD.DeviceSize |= (CSD_Tab[7]) << 2;
/* Byte 8 */
cardinfo->CSD.DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;
cardinfo->CSD.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
cardinfo->CSD.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
/* Byte 9 */
cardinfo->CSD.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
cardinfo->CSD.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
cardinfo->CSD.DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
/* Byte 10 */
cardinfo->CSD.DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;
cardinfo->CSD.EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;
cardinfo->CSD.EraseGrMul = (CSD_Tab[10] & 0x03) << 3;
/* Byte 11 */
cardinfo->CSD.EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;
cardinfo->CSD.WrProtectGrSize = (CSD_Tab[11] & 0x1F);
/* Byte 12 */
cardinfo->CSD.WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
cardinfo->CSD.ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
cardinfo->CSD.WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
cardinfo->CSD.MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
/* Byte 13 */
cardinfo->CSD.MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;
cardinfo->CSD.WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
cardinfo->CSD.Reserved3 = 0;
cardinfo->CSD.ContentProtectAppli = (CSD_Tab[13] & 0x01);
/* Byte 14 */
cardinfo->CSD.FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
cardinfo->CSD.CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
cardinfo->CSD.PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
cardinfo->CSD.TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
cardinfo->CSD.FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
cardinfo->CSD.ECC = (CSD_Tab[14] & 0x03);
/* Byte 15 */
cardinfo->CSD.CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -