/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** * File Name : msd.c * Author : MCD Application Team * Version : V2.1 * Date : 05/30/2008 * Description : MSD card driver source file. * Pin assignment: * ---------------------------------------------- * | STM32F10x | MSD Pin | * ---------------------------------------------- * | P0.4 | ChipSelect 1 | * | P0.1 / MOSI | DataIn 2 | * | | GND 3 (0 V) | * | | VDD 4 (3.3 V) | * | P0.2 / SCLK | Clock 5 | * | | GND 6 (0 V) | * | P0.0 / MISO | DataOut 7 | * ----------------------------------------------- ******************************************************************************** * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED * IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE. *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "msd.h" #include /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Select MSD Card: ChipSelect pin low */ #define MSD_CS_LOW() GPIO_ResetBits(GPIOC, GPIO_Pin_7) /* Deselect MSD Card: ChipSelect pin high */ #define MSD_CS_HIGH() GPIO_SetBits(GPIOC, GPIO_Pin_7) /* MSD Card SPI */ #define MSD_SPI SPI3 #define MSD_RCC_SPI RCC_APB2Periph_SPI3 /* Private function prototypes -----------------------------------------------*/ static void SPI_Config(void); /* Private functions ---------------------------------------------------------*/ /******************************************************************************* * Function Name : MSD_Init * Description : Initializes the MSD/SD communication. * Input : None * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_Init(void) { u32 i = 0; /* Initialize SPI */ SPI_Config(); /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte 0xFF, 10 times with CS high*/ /* rise CS and MOSI for 80 clocks cycles */ for (i = 0; i <= 9; i++) { /* Send dummy byte 0xFF */ MSD_WriteByte(DUMMY); } /*------------Put MSD in SPI mode--------------*/ /* MSD initialized and set to SPI mode properly */ return (MSD_GoIdleState()); } /******************************************************************************* * Function Name : MSD_WriteBlock * Description : Writes a block on the MSD * Input : - pBuffer : pointer to the buffer containing the data to be * written on the MSD. * - WriteAddr : address to write on. * - NumByteToWrite: number of data to write * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) { u32 i = 0; u8 rvalue = MSD_RESPONSE_FAILURE; /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD24 (MSD_WRITE_BLOCK) to write multiple block */ MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr, 0xFF); /* Check if the MSD acknowledged the write block command: R1 response (0x00: no errors) */ if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { /* Send a dummy byte */ MSD_WriteByte(DUMMY); /* Send the data token to signify the start of the data */ MSD_WriteByte(0xFE); /* Write the block data to MSD : write count data by block */ for (i = 0; i < NumByteToWrite; i++) { /* Send the pointed byte */ MSD_WriteByte(*pBuffer); /* Point to the next location where the byte read will be saved */ pBuffer++; } /* Put CRC bytes (not really needed by us, but required by MSD) */ MSD_ReadByte(); MSD_ReadByte(); /* Read data response */ if (MSD_GetDataResponse() == MSD_DATA_OK) { rvalue = MSD_RESPONSE_NO_ERROR; } } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Returns the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_ReadBlock * Description : Reads a block of data from the MSD. * Input : - pBuffer : pointer to the buffer that receives the data read * from the MSD. * - ReadAddr : MSD's internal address to read from. * - NumByteToRead : number of bytes to read from the MSD. * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead) { u32 i = 0; u8 rvalue = MSD_RESPONSE_FAILURE; /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD17 (MSD_READ_SINGLE_BLOCK) to read one block */ MSD_SendCmd(MSD_READ_SINGLE_BLOCK, ReadAddr, 0xFF); /* Check if the MSD acknowledged the read block command: R1 response (0x00: no errors) */ if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { /* Now look for the data token to signify the start of the data */ if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) { /* Read the MSD block data : read NumByteToRead data */ for (i = 0; i < NumByteToRead; i++) { /* Save the received data */ *pBuffer = MSD_ReadByte(); /* Point to the next location where the byte read will be saved */ pBuffer++; } /* Get CRC bytes (not really needed by us, but required by MSD) */ MSD_ReadByte(); MSD_ReadByte(); /* Set response value to success */ rvalue = MSD_RESPONSE_NO_ERROR; } } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Returns the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_WriteBuffer * Description : Writes many blocks on the MSD * Input : - pBuffer : pointer to the buffer containing the data to be * written on the MSD. * - WriteAddr : address to write on. * - NumByteToWrite: number of data to write * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite) { u32 i = 0, NbrOfBlock = 0, Offset = 0; u8 rvalue = MSD_RESPONSE_FAILURE; /* Calculate number of blocks to write */ NbrOfBlock = NumByteToWrite / BLOCK_SIZE; /* MSD chip select low */ MSD_CS_LOW(); /* Data transfer */ while (NbrOfBlock --) { /* Send CMD24 (MSD_WRITE_BLOCK) to write blocks */ MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr + Offset, 0xFF); /* Check if the MSD acknowledged the write block command: R1 response (0x00: no errors) */ if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { return MSD_RESPONSE_FAILURE; } /* Send dummy byte */ MSD_WriteByte(DUMMY); /* Send the data token to signify the start of the data */ MSD_WriteByte(MSD_START_DATA_SINGLE_BLOCK_WRITE); /* Write the block data to MSD : write count data by block */ for (i = 0; i < BLOCK_SIZE; i++) { /* Send the pointed byte */ MSD_WriteByte(*pBuffer); /* Point to the next location where the byte read will be saved */ pBuffer++; } /* Set next write address */ Offset += 512; /* Put CRC bytes (not really needed by us, but required by MSD) */ MSD_ReadByte(); MSD_ReadByte(); /* Read data response */ if (MSD_GetDataResponse() == MSD_DATA_OK) { /* Set response value to success */ rvalue = MSD_RESPONSE_NO_ERROR; } else { /* Set response value to failure */ rvalue = MSD_RESPONSE_FAILURE; } } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Returns the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_ReadBuffer * Description : Reads multiple block of data from the MSD. * Input : - pBuffer : pointer to the buffer that receives the data read * from the MSD. * - ReadAddr : MSD's internal address to read from. * - NumByteToRead : number of bytes to read from the MSD. * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead) { u32 i = 0, NbrOfBlock = 0, Offset = 0; u8 rvalue = MSD_RESPONSE_FAILURE; /* Calculate number of blocks to read */ NbrOfBlock = NumByteToRead / BLOCK_SIZE; /* MSD chip select low */ MSD_CS_LOW(); /* Data transfer */ while (NbrOfBlock --) { /* Send CMD17 (MSD_READ_SINGLE_BLOCK) to read one block */ MSD_SendCmd (MSD_READ_SINGLE_BLOCK, ReadAddr + Offset, 0xFF); /* Check if the MSD acknowledged the read block command: R1 response (0x00: no errors) */ if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { return MSD_RESPONSE_FAILURE; } /* Now look for the data token to signify the start of the data */ if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) { /* Read the MSD block data : read NumByteToRead data */ for (i = 0; i < BLOCK_SIZE; i++) { /* Read the pointed data */ *pBuffer = MSD_ReadByte(); /* Point to the next location where the byte read will be saved */ pBuffer++; } /* Set next read address*/ Offset += 512; /* get CRC bytes (not really needed by us, but required by MSD) */ MSD_ReadByte(); MSD_ReadByte(); /* Set response value to success */ rvalue = MSD_RESPONSE_NO_ERROR; } else { /* Set response value to failure */ rvalue = MSD_RESPONSE_FAILURE; } } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Returns the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_GetCSDRegister * Description : Read the CSD card register. * Reading the contents of the CSD register in SPI mode * is a simple read-block transaction. * Input : - MSD_csd: pointer on an SCD register structure * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd) { u32 i = 0; u8 rvalue = MSD_RESPONSE_FAILURE; u8 CSD_Tab[16]; /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD9 (CSD register) or CMD10(CSD register) */ MSD_SendCmd(MSD_SEND_CSD, 0, 0xFF); /* Wait for response in the R1 format (0x00 is no errors) */ if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) { for (i = 0; i < 16; i++) { /* Store CSD register value on CSD_Tab */ CSD_Tab[i] = MSD_ReadByte(); } } /* Get CRC bytes (not really needed by us, but required by MSD) */ MSD_WriteByte(DUMMY); MSD_WriteByte(DUMMY); /* Set response value to success */ rvalue = MSD_RESPONSE_NO_ERROR; } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Byte 0 */ MSD_csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; MSD_csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2; MSD_csd->Reserved1 = CSD_Tab[0] & 0x03; /* Byte 1 */ MSD_csd->TAAC = CSD_Tab[1] ; /* Byte 2 */ MSD_csd->NSAC = CSD_Tab[2]; /* Byte 3 */ MSD_csd->MaxBusClkFrec = CSD_Tab[3]; /* Byte 4 */ MSD_csd->CardComdClasses = CSD_Tab[4] << 4; /* Byte 5 */ MSD_csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4; MSD_csd->RdBlockLen = CSD_Tab[5] & 0x0F; /* Byte 6 */ MSD_csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; MSD_csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; MSD_csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; MSD_csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; MSD_csd->Reserved2 = 0; /* Reserved */ MSD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10; /* Byte 7 */ MSD_csd->DeviceSize |= (CSD_Tab[7]) << 2; /* Byte 8 */ MSD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6; MSD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; MSD_csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); /* Byte 9 */ MSD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; MSD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; MSD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1; /* Byte 10 */ MSD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7; MSD_csd->EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2; MSD_csd->EraseGrMul = (CSD_Tab[10] & 0x03) << 3; /* Byte 11 */ MSD_csd->EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5; MSD_csd->WrProtectGrSize = (CSD_Tab[11] & 0x1F); /* Byte 12 */ MSD_csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; MSD_csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5; MSD_csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; MSD_csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2; /* Byte 13 */ MSD_csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6; MSD_csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5; MSD_csd->Reserved3 = 0; MSD_csd->ContentProtectAppli = (CSD_Tab[13] & 0x01); /* Byte 14 */ MSD_csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; MSD_csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; MSD_csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; MSD_csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; MSD_csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; MSD_csd->ECC = (CSD_Tab[14] & 0x03); /* Byte 15 */ MSD_csd->msd_CRC = (CSD_Tab[15] & 0xFE) >> 1; MSD_csd->Reserved4 = 1; /* Return the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_GetCIDRegister * Description : Read the CID card register. * Reading the contents of the CID register in SPI mode * is a simple read-block transaction. * Input : - MSD_cid: pointer on an CID register structure * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid) { u32 i = 0; u8 rvalue = MSD_RESPONSE_FAILURE; u8 CID_Tab[16]; /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD10 (CID register) */ MSD_SendCmd(MSD_SEND_CID, 0, 0xFF); /* Wait for response in the R1 format (0x00 is no errors) */ if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) { if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) { /* Store CID register value on CID_Tab */ for (i = 0; i < 16; i++) { CID_Tab[i] = MSD_ReadByte(); } } /* Get CRC bytes (not really needed by us, but required by MSD) */ MSD_WriteByte(DUMMY); MSD_WriteByte(DUMMY); /* Set response value to success */ rvalue = MSD_RESPONSE_NO_ERROR; } /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte: 8 Clock pulses of delay */ MSD_WriteByte(DUMMY); /* Byte 0 */ MSD_cid->ManufacturerID = CID_Tab[0]; /* Byte 1 */ MSD_cid->OEM_AppliID = CID_Tab[1] << 8; /* Byte 2 */ MSD_cid->OEM_AppliID |= CID_Tab[2]; /* Byte 3 */ MSD_cid->ProdName1 = CID_Tab[3] << 24; /* Byte 4 */ MSD_cid->ProdName1 |= CID_Tab[4] << 16; /* Byte 5 */ MSD_cid->ProdName1 |= CID_Tab[5] << 8; /* Byte 6 */ MSD_cid->ProdName1 |= CID_Tab[6]; /* Byte 7 */ MSD_cid->ProdName2 = CID_Tab[7]; /* Byte 8 */ MSD_cid->ProdRev = CID_Tab[8]; /* Byte 9 */ MSD_cid->ProdSN = CID_Tab[9] << 24; /* Byte 10 */ MSD_cid->ProdSN |= CID_Tab[10] << 16; /* Byte 11 */ MSD_cid->ProdSN |= CID_Tab[11] << 8; /* Byte 12 */ MSD_cid->ProdSN |= CID_Tab[12]; /* Byte 13 */ MSD_cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; /* Byte 14 */ MSD_cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; /* Byte 15 */ MSD_cid->ManufactDate |= CID_Tab[14]; /* Byte 16 */ MSD_cid->msd_CRC = (CID_Tab[15] & 0xFE) >> 1; MSD_cid->Reserved2 = 1; /* Return the reponse */ return rvalue; } /******************************************************************************* * Function Name : MSD_SendCmd * Description : Send 5 bytes command to the MSD card. * Input : - Cmd: the user expected command to send to MSD card * - Arg: the command argument * - Crc: the CRC * Output : None * Return : None *******************************************************************************/ void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc) { u32 i = 0x00; u8 Frame[6]; /* Construct byte1 */ Frame[0] = (Cmd | 0x40); /* Construct byte2 */ Frame[1] = (u8)(Arg >> 24); /* Construct byte3 */ Frame[2] = (u8)(Arg >> 16); /* Construct byte4 */ Frame[3] = (u8)(Arg >> 8); /* Construct byte5 */ Frame[4] = (u8)(Arg); /* Construct CRC: byte6 */ Frame[5] = (Crc); /* Send the Cmd bytes */ for (i = 0; i < 6; i++) { MSD_WriteByte(Frame[i]); } } /******************************************************************************* * Function Name : MSD_GetDataResponse * Description : Get MSD card data response. * Input : None * Output : None * Return : The MSD status: Read data response xxx01 * - status 010: Data accecpted * - status 101: Data rejected due to a crc error * - status 110: Data rejected due to a Write error. * - status 111: Data rejected due to other error. *******************************************************************************/ u8 MSD_GetDataResponse(void) { u32 i = 0; u8 response, rvalue; while (i <= 64) { /* Read resonse */ response = MSD_ReadByte(); /* Mask unused bits */ response &= 0x1F; switch (response) { case MSD_DATA_OK: { rvalue = MSD_DATA_OK; break; } case MSD_DATA_CRC_ERROR: return MSD_DATA_CRC_ERROR; case MSD_DATA_WRITE_ERROR: return MSD_DATA_WRITE_ERROR; default: { rvalue = MSD_DATA_OTHER_ERROR; break; } } /* Exit loop in case of data ok */ if (rvalue == MSD_DATA_OK) break; /* Increment loop counter */ i++; } /* Wait null data */ while (MSD_ReadByte() == 0); /* Return response */ return response; } /******************************************************************************* * Function Name : MSD_GetResponse * Description : Returns the MSD response. * Input : None * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_GetResponse(u8 Response) { u32 Count = 0xFFF; /* Check if response is got or a timeout is happen */ while ((MSD_ReadByte() != Response) && Count) { Count--; } if (Count == 0) { /* After time out */ return MSD_RESPONSE_FAILURE; } else { /* Right response got */ return MSD_RESPONSE_NO_ERROR; } } /******************************************************************************* * Function Name : MSD_GetStatus * Description : Returns the MSD status. * Input : None * Output : None * Return : The MSD status. *******************************************************************************/ u16 MSD_GetStatus(void) { u16 Status = 0; /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD13 (MSD_SEND_STATUS) to get MSD status */ MSD_SendCmd(MSD_SEND_STATUS, 0, 0xFF); Status = MSD_ReadByte(); Status |= (u16)(MSD_ReadByte() << 8); /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte 0xFF */ MSD_WriteByte(DUMMY); return Status; } /******************************************************************************* * Function Name : MSD_GoIdleState * Description : Put MSD in Idle state. * Input : None * Output : None * Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed * - MSD_RESPONSE_NO_ERROR: Sequence succeed *******************************************************************************/ u8 MSD_GoIdleState(void) { /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */ MSD_SendCmd(MSD_GO_IDLE_STATE, 0, 0x95); /* Wait for In Idle State Response (R1 Format) equal to 0x01 */ if (MSD_GetResponse(MSD_IN_IDLE_STATE)) { /* No Idle State Response: return response failue */ return MSD_RESPONSE_FAILURE; } /*----------Activates the card initialization process-----------*/ do { /* MSD chip select high */ MSD_CS_HIGH(); /* Send Dummy byte 0xFF */ MSD_WriteByte(DUMMY); /* MSD chip select low */ MSD_CS_LOW(); /* Send CMD1 (Activates the card process) until response equal to 0x0 */ MSD_SendCmd(MSD_SEND_OP_COND, 0, 0xFF); /* Wait for no error Response (R1 Format) equal to 0x00 */ } while (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)); /* MSD chip select high */ MSD_CS_HIGH(); /* Send dummy byte 0xFF */ MSD_WriteByte(DUMMY); return MSD_RESPONSE_NO_ERROR; } /******************************************************************************* * Function Name : MSD_WriteByte * Description : Write a byte on the MSD. * Input : Data: byte to send. * Output : None * Return : None. *******************************************************************************/ void MSD_WriteByte(u8 Data) { /* Wait until the transmit buffer is empty */ while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_TXE) == RESET); /* Send the byte */ SPI_I2S_SendData(MSD_SPI, Data); } /******************************************************************************* * Function Name : MSD_ReadByte * Description : Read a byte from the MSD. * Input : None. * Output : None * Return : The received byte. *******************************************************************************/ u8 MSD_ReadByte(void) { u8 Data = 0; /* Wait until the transmit buffer is empty */ while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_TXE) == RESET); /* Send the byte */ SPI_I2S_SendData(MSD_SPI, DUMMY); /* Wait until a data is received */ while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_RXNE) == RESET); /* Get the received data */ Data = SPI_I2S_ReceiveData(MSD_SPI); /* Return the shifted data */ return Data; } /******************************************************************************* * Function Name : SPI_Config * Description : Initializes the SPI and CS pins. * Input : None * Output : None * Return : None *******************************************************************************/ void SPI_Config(void) { uint32_t delay; GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; /* GPIOC Periph clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); /* remap SPI3 */ GPIO_PinRemapConfig(GPIO_Remap_SPI3, ENABLE); /* SPI Periph clock enable */ RCC_APB2PeriphClockCmd(MSD_RCC_SPI, ENABLE); /* Configure SPI pins: SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); /* Configure PC7 pin: CS pin */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); /* SPI Config */ 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_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(MSD_SPI, &SPI_InitStructure); /* SPI enable */ SPI_Cmd(MSD_SPI, ENABLE); /* active SD card */ for (delay = 0; delay < 0xfffff; delay ++); } /******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ /* * RT-Thread SD Card Driver * 20090417 Bernard */ #include #include static struct rt_device sdcard_device; static struct dfs_partition part; #define SECTOR_SIZE 512 /* RT-Thread Device Driver Interface */ static rt_err_t rt_msd_init(rt_device_t dev) { sMSD_CSD MSD_csd; MSD_GetCSDRegister(&MSD_csd); return RT_EOK; } static rt_err_t rt_msd_open(rt_device_t dev, rt_uint16_t oflag) { return RT_EOK; } static rt_err_t rt_msd_close(rt_device_t dev) { return RT_EOK; } static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) { rt_uint8_t status; rt_uint32_t i; status = MSD_RESPONSE_NO_ERROR; // rt_kprintf("read: 0x%x, size %d\n", pos, size); /* read all sectors */ for (i = 0; i < size / SECTOR_SIZE; i ++) { status = MSD_ReadBlock((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE), (part.offset + i)* SECTOR_SIZE + pos, SECTOR_SIZE); if (status != MSD_RESPONSE_NO_ERROR) { rt_kprintf("sd card read failed\n"); return 0; } } if (status == MSD_RESPONSE_NO_ERROR) return size; rt_kprintf("read failed: %d\n", status); return 0; } static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { rt_uint8_t status; rt_uint32_t i; status = MSD_RESPONSE_NO_ERROR; // rt_kprintf("write: 0x%x, size %d\n", pos, size); /* read all sectors */ for (i = 0; i < size / SECTOR_SIZE; i ++) { status = MSD_WriteBuffer((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE), (part.offset + i)* SECTOR_SIZE + pos, SECTOR_SIZE); if (status != MSD_RESPONSE_NO_ERROR) { rt_kprintf("sd card write failed\n"); return 0; } } if (status == MSD_RESPONSE_NO_ERROR) return size; rt_kprintf("write failed: %d\n", status); return 0; } static rt_err_t rt_msd_control(rt_device_t dev, rt_uint8_t cmd, void *args) { return RT_EOK; } void rt_hw_msd_init() { if (MSD_Init() == MSD_RESPONSE_NO_ERROR) { rt_uint8_t status; rt_uint8_t *sector; /* register sdcard device */ sdcard_device.init = rt_msd_init; sdcard_device.open = rt_msd_open; sdcard_device.close = rt_msd_close; sdcard_device.read = rt_msd_read; sdcard_device.write = rt_msd_write; sdcard_device.control = rt_msd_control; /* no private */ sdcard_device.private = RT_NULL; /* get the first sector to read partition table */ sector = (rt_uint8_t*) rt_malloc (512); if (sector == RT_NULL) { rt_kprintf("allocate partition sector buffer failed\n"); return; } status = MSD_ReadBlock(sector, 0, 512); if (status == MSD_RESPONSE_NO_ERROR) { /* get the first partition */ status = dfs_filesystem_get_partition(&part, sector, 0); if (status != RT_EOK) { /* there is no partition table */ part.offset = 0; part.size = 0; } } else { /* there is no partition table */ part.offset = 0; part.size = 0; } /* release sector buffer */ rt_free(sector); rt_device_register(&sdcard_device, "sd0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); } else { rt_kprintf("sdcard init failed\n"); } }