SD cards generally support two read and write modes, SPI and SDIO modes. The pin arrangement of SD cards is shown in the figure below.
There are several important operation commands in SPI mode, namely:
The format of SD card R1 response is as follows
The typical initialization process in SPI mode is as follows:
1. Initialize hardware configuration, SPI configuration, IO configuration, etc.
2. Power-on delay. (>74CLK)
3. Reset the card. (CMD0)
4. Activate the card, initialize internally and obtain the card type.
5. Query OCR to obtain power supply status.
6. Whether to use CRC (CMD59).
7. Set the read/write block data length (CMD16).
8. Read CSD and obtain other information of the memory card (CMD9)
9. After sending 8CLK, chip select is disabled.
The typical process of reading data in SPI mode is as follows, which is implemented using CMD17.
1. Send CMD17.
2. The receiving card responds with R1.
3. Receive data start token 0XFE.
4. Receive data.
5. Receive two bytes of CRC. If CRC is not enabled, these two bytes can be discarded after reading.
6. Chip select is prohibited after 8CLK.
The typical process of writing data in SPI mode is as follows, where CMD24 is used to implement it.
1. Send CMD24.
2. The receiving card responds with R1.
3. Receive data start token 0XFE.
4. Receive data.
5. Send two bytes of pseudo CRC.
6. Chip select is prohibited after 8CLK.
The specific code implementation is as follows.
/*******************************************************************************
* Function Name : SPI_FLASH_Init
* Description : Initializes the peripherals used by the SPI FLASH driver.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_SD_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the clock of the corresponding SPI pin Enable the clock of SPI1*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
/* Configure the SPI clock line SCK and the SPI MOSI line and the SPI MISO line*/
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; //Push-pull output of multiplexing function
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*Configure SPI chip select line: CSN */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //Push-pull output
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Pull up the CSN pin to stop enabling SD*/
GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_8);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
// Configure SPI to suit the characteristics of
SDSPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Two-line bidirectional full-
duplexSPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Master deviceSPI_InitStructure.SPI_DataSize
= SPI_DataSize_8b;//8-bit data lengthSPI_InitStructure.SPI_CPOL
= SPI_CPOL_High; //Clock is high when floatingSPI_InitStructure.SPI_CPHA
= SPI_CPHA_2Edge; //Data is captured at the second clock edgeSPI_InitStructure.SPI_NSS
= SPI_NSS_Soft; //NSS signal is managed by external pinSPI_InitStructure.SPI_BaudRatePrescaler
= SPI_BaudRatePrescaler_256;//Baud rate prescaler value is 4
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //The first byte of data transmission is MSB
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC polynomial
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE);
}
/*******************************************************************************
* Function Name : SPI_FLASH_SendByte
* Description : Send a data and receive the data returned from FLASH at the same time
* Input : byte : byte to send.
* Output : None
* Return : The value of the received byte.
*******************************************************************************/
u8 SPIx_ReadWriteByte(u8 byte)
{
/* Wait for the data send register to be cleared*/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* Send one byte of data through SPI*/
SPI_I2S_SendData(SPI1, byte);
/* Waiting for receiving a data (receiving a data is equivalent to sending a data) */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return received data */
return SPI_I2S_ReceiveData(SPI1);
}
/*******************************************************************************
* Function Name : SPI_FLASH_SendHalfWord
* Description : Send and receive a half word of data (16 bits)
* Input : Half Word : Half Word to send.
* Output : None
* Return : The value of the received Half Word.
*******************************************************************************/
u16 SPIx_ReadWriteHalfWord(u16 HalfWord)
{
/* Wait for the data send register to be cleared*/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* Send half word of data through SPI*/
SPI_I2S_SendData(SPI1, HalfWord);
/* Waiting for receiving a half-word of data (receiving a data is equivalent to completing sending a data) */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return received data*/
return SPI_I2S_ReceiveData(SPI1);
}
//SPI speed setting function
//SpeedSet:
//SPI_BaudRatePrescaler_2 2 division (SPI 36M@sys 72M)
//SPI_BaudRatePrescaler_8 8 division (SPI 9M@sys 72M)
//SPI_BaudRatePrescaler_16 16 division (SPI 4.5M@sys 72M)
//SPI_BaudRatePrescaler_256 256 division (SPI 281.25K@sys 72M)
void SPIx_SetSpeed(u8 SpeedSet)
{
SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1,ENABLE);
}
/******************************END OF INIT_SPI*****************************/
/******************************START OF SD_OPERATION***********************/
/*******************************************************************************
* Function name: SD_Select
* Function description: Select SD card and wait for SD card to be ready
* Entry parameter: None.
* Return parameter: 0: Success 1: Failure
* Remarks: SD card is ready and will return 0XFF
*******************************************************************************/
u8 SD_Select(void)
{
uint32_t t=0;
SD_CS(OFF); //Chip select SD, low level enable
do
{
if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
t++;
}while(t<0XFFFFFF);//Wait for
SD_DisSelect(); //Release bus
return 1;//Wait for failure
}
/*******************************************************************************
* Function name: SD_RecvData
* Function description: Read the content of a data packet from the SD card
* Entry parameters: buf: data buffer array len: the length of the data to be read
* Return parameters: 0: success Others: failure
* Remarks: When reading, you need to wait for the SD card to send the data start token 0XFE
***********************************************************************************/
u8 SD_RecvData(u8*buf,u16 len)
{
u16 Count=0xF000;//Wait timeswhile
((SD_SPI_ReadWriteByte(0XFF)!=0xFE)&&Count)Count--;//Wait to get the read data token 0xfe
if (Count==0) return MSD_RESPONSE_FAILURE;//Failed to get the token, return 0XFF
while(len--)//Start receiving data
{
*buf=SPIx_ReadWriteByte(0xFF);
buf++;
}
//Below are 2 dummy CRCs, pretending to receive 2 CRCs
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
return 0;//Read successful
}
/*******************************************************************************
* Function name: SD_SendBlock
* Function description: Write a data packet of 512 bytes to the SD card
* Entry parameters: buf: data buffer cmd: token for data sending
* Return parameters: 0: success Others: failure
* Remarks: When writing data, you need to send the data start token 0XFE/0XFC/0XFD first
*******************************************************************************/
u8 SD_SendBlock(u8*buf,u8 cmd)
{
u32 t,Count=0XFFFFFF;
while ((SD_SPI_ReadWriteByte(0XFF)!=0xFF)&&Count)Count--;//Wait for SD card to be readyif
(Count==0) return MSD_RESPONSE_FAILURE;//SD card is not ready, failed, return
SD_SPI_ReadWriteByte(cmd); //Send data start or stop tokenif
(cmd!=0XFD)//Start sending data when it is not the end token
{
for(t=0;t<512;t++)SPIx_ReadWriteByte(buf[t]);//Increase speed and reduce function parameter transmission
timeSD_SPI_ReadWriteByte(0xFF);//Send 2-byte CRC
SD_SPI_ReadWriteByte(0xFF);
t=SD_SPI_ReadWriteByte(0xFF);//Receive data write status immediately after CRCif
((t&0x1F)!=0x05)return MSD_DATA_WRITE_ERROR; //Write error
}
return 0;//Write successfully
}
/*******************************************************************************
* Function name: SD_SendCmd
* Function description: Write the content of a data packet of 512 bytes to the SD card
* Entry parameters: cmd: command arg: command parameter crc: crc check value and stop bit
* Return parameters: Return value: The response of the corresponding command returned by the SD card
* Remarks: The response is R1-R7, see SD Protocol Manual V2.0 (2006)
*******************************************************************************/
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{
u8 r1;
u8 Retry=0;
SD_DisSelect();//Cancel the last chip select and release the busif
(SD_Select())return 0XFF;//Check if the chip select signal line is selected successfully
//Send
SD_SPI_ReadWriteByte(cmd | 0x40);//Write commands respectively
SD_SPI_ReadWriteByte(arg >> 24);
SD_SPI_ReadWriteByte(arg >> 16);
SD_SPI_ReadWriteByte(arg >> 8);
SD_SPI_ReadWriteByte(arg) ; SD_SPI_ReadWriteByte
(crc);
if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
//Wait for response, or time out and exit
Retry=0X1F;
do //Send a certain number of clock signals, waiting for the SD card to respond with 0X01 (0x01 means the command is sent successfully, and 0XFF means failure)
{
r1=SD_SPI_ReadWriteByte(0xFF);
}while((r1&0X80) && Retry--); //Wait for the return of non-0XFF data
//Return status value
return r1;
}
/*******************************************************************************
* Function name: SD_GetCID
* Function description: Get the CID information of the SD card, including the manufacturer information
* Entry parameter: cid_data (memory to store CID, at least 16Byte
* Return parameter: 0: Success Others: Failure
* Remarks: For details of the CID register, please refer to the SD Protocol Manual V2.0 (2006)
*******************************************************************************/
u8 SD_GetCID(u8 *cid_data)
{
u8 r1;
//Send CMD10 command, read CID
r1=SD_SendCmd(CMD10,0,0x01);
if(r1==0x00)
{
r1=SD_RecvData(cid_data,16);//Receive 16 bytes of data
}
SD_DisSelect();//Cancel chip selectionif
(r1)return 1;
else return 0;
}
/***************************************************************************
* Function name: SD_GetCSD
* Function description: Get the CSD information of the SD card, including capacity and speed information
* Entry parameter: cid_data (memory to store CSD, at least 16Byte
* Return parameter: 0: Success Others: Failure
* Remarks: For details of the CSD register, please refer to the SD Protocol Manual V2.0 (2006)
*******************************************************************************/
u8 SD_GetCSD(u8 *csd_data)
{
u8 r1;
r1=SD_SendCmd(CMD9,0,0x01);//Send CMD9 command, read CSD
if(r1==0)
{
r1=SD_RecvData(csd_data,16);//Receive 16 bytes of data
}
SD_DisSelect();//Cancel chip selection
if(r1)return 1;
else return 0;
}
/********************************************************************************
* Function name: SD_GetSectorCount
* Function description: Get the total number of sectors of the SD card (number of sectors
* Input parameter: cid_data (memory for storing CSD, at least 16Byte
* Return parameter: 0: Error in getting capacity Others: SD card sector number value
* Remarks: Calculation formula for SD card capacity SD Protocol Manual V2.0 (2006)
*******************************************************************************/
u32 SD_GetSectorCount(void)
{
u8 csd[16];
u32 Capacity;
u8 n;
u16 csize;
//Get CSD information, if an error occurs during the process, return 0
if(SD_GetCSD(csd)!=0) return 0; //Failed to get capacity
//If it is an SDHC card, calculate as follows
if((csd[0]&0xC0)==0x40) //V2.00 card
{
csize = csd[9] + ((u16)csd[8] << 8) + 1;
Capacity = (u32)csize << 10; //Get the number of sectors
}
else //V1.XX card
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
Capacity= (u32)csize << (n - 9);//Get the number of sectors
}
return Capacity;
}
/*******************************************************************************
* Function name: SD_ReadDisk
* Function description: Read SD card
* Entry parameters: buf: data buffer sector: address to be read cnt: number of sectors to be read
* Return parameters: 0: success Others: failure
* Remarks: 1. The address to be read must be the beginning of a sector
2. It must be SD2.0 card, other cards are not processed
***************************************************************************/
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(cnt==1)
{
r1=SD_SendCmd(CMD17,sector,0X01);//Read commandif
(r1==0)//Command sent successfully
{
r1=SD_RecvData(buf,512);//receive 512 bytes
}
}
else
{
r1=SD_SendCmd(CMD18,sector,0X01);//continuous read commanddo
{
r1
=SD_RecvData(buf,512);//receive 512 bytesbuf
+=512;
}while(--cnt && r1==0);
SD_SendCmd(CMD12,0,0X01); //send stop command
}
SD_DisSelect();//cancel chip selectreturn
r1;//
}
/***********************************************************************************
* Function name: SD_WriteDisk
* Function description: write SD card
* Entry parameter: buf: data buffer sector: address to be written cnt: number of sectors to be written
* Return parameter: 0: success Others: failure
* Remarks: 1. The address to be written must be the beginning of a sector
2. It must be an SD2.0 card, other cards are not processed
******************************************************************************/
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(cnt==1)
{
r1=SD_SendCmd(CMD24,sector,0X01);//Single sector write command
if(r1==0)//Command sent successfully
{
r1=SD_SendBlock(buf,0xFE);//Write 512 bytes
}
}
else
{
if(SD_Type!=SD_TYPE_MMC)
{
SD_SendCmd(CMD55,0,0X01);
SD_SendCmd(CMD23,cnt,0X01);//Send the number of sectors to be written, this command is used to pre-erase all sectors to be written
}
r1=SD_SendCmd(CMD25,sector,0X01);//Continuous write command, send the starting address
if(r1==0)
{
do
{
r1=SD_SendBlock(buf,0xFC);//Send 512 bytes
buf+=512;
}while(--cnt && r1==0);
r1=SD_SendBlock(0,0xFD);//Send stop bit
}
}
SD_DisSelect();//Cancel chip selectreturn
r1;//
}
/*******************************************************************************
* Function name: SD_Initialize
* Function description: Write SD card
* Entry parameter: None
* Return parameter: 0: Success Others: Failure
* Remarks: 1. The address to be written must be the beginning of a sector
2. It must be an SD2.0 card, other cards are not processed
***************************************************************************/
u8 SD_Initialize(void)
{
u8 r1; // Store the return value of SD cardu16
retry; // Used for timeout counting
u8 buf[4];
u16 i;
SPI_SD_Init(); //Initialize IO
SD_SPI_SpeedLow(); //Set to low speed mode
for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//Send at least 74 pulses, keep the chip select line high at this time
retry=20;
do
{
r1=SD_SendCmd(CMD0,0,0x95);//Enter reset and select SPI mode at the same time (CSN is low when sending CMD0)
}while((r1!=0X01) && retry--);
SD_Type=0;//Default no cardif
(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//Use the V2.0 version SD card special command CMD8 to check whether it is a 2.0 card
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF); //Get trailing return value of R7 resp
if(buf[2]==0X01&&buf[3]==0XAA)//Does the card support 2.7~3.6V
{
retry=0XFFFE;
do
{
SD_SendCmd(CMD55,0,0X01); //Send CMD55
r1=SD_SendCmd(CMD41,0x40000000,0X01);//Send CMD41
}while(r1&&retry--);
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//Identify the SD2.0 card version, read the OCR value
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//get OCR valueif
(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //check CCS (bit 30)
else SD_Type=SD_TYPE_V2;
}
}
}
else//if it is not a 2.0 card, check whether it is a 1.0 card or MMC card
{
SD_SendCmd(CMD55,0,0X01); //send CMD55
r1=SD_SendCmd(CMD41,0,0X01); //send CMD41
if(r1<=1)//send CMD55 and CMD41 successfully, indicating that this is a 1.0 card
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //wait to exit IDLE mode
{
SD_SendCmd(CMD55,0,0X01); //Send CMD55
r1=SD_SendCmd(CMD41,0,0X01); //Send CMD41 for initialization
}while(r1&&retry--);
}
else //If it is not a 1.0 card, consider it to be an MMC card
{
SD_Type=SD_TYPE_MMC; //Assume it is an MMC card first
retry=0XFFFE;
do //Wait to exit IDLE mode
{
r1=SD_SendCmd(CMD1,0,0X01); //Send CMD1 and use the reset function to determine whether it is an MMC card
}while(r1&&retry--); //Send reset command. Reset fails if timeout
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR; //MMC card reset failed
}
}
SD_DisSelect();//Cancel chip selection
SD_SPI_SpeedHigh();//High speed
if(SD_Type)return 0; //Initialization successful
else if(r1)return r1; //Initialization failed
return 0xaa;//Other errors
}
Previous article:STM32 simulates IIC reading and writing AT24CXX
Next article:How to use STM32 firmware library V3.5 in Keil MDK environment
Recommended ReadingLatest update time:2024-11-16 18:09
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Basics | Learn the basics of "amplifier" in 5 minutes
- LC filter circuit parameter design verification
- Fresh and hot, aircraft cabin pressure and temperature data recorded by SensorTile.box
- 2020 TI Cup Analog Electronic System Design Invitational Competition
- Qorvo UWB helps Shenzhentong enter the era of smart travel
- Turning off the general interrupt on M16C doesn't seem to work?
- Gesture recognition device based on FDC2214 sensor (MSP430)
- Quartus_II Official Tutorial-Chinese Version.pdf
- What does the outer diameter of the color ring of MULTI-LAYER mean? The size of the drill hole is the inner diameter, so what does the outer diameter mean?
- What were you doing the day before the college entrance examination? Do you regret choosing this major?