瀏覽代碼

add SPI SD card driver.

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1568 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong 14 年之前
父節點
當前提交
95cb66f269
共有 2 個文件被更改,包括 1124 次插入0 次删除
  1. 951 0
      bsp/stm32f107/msd.c
  2. 173 0
      bsp/stm32f107/msd.h

+ 951 - 0
bsp/stm32f107/msd.c

@@ -0,0 +1,951 @@
+/******************** (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 <stm32f10x_spi.h>
+#include <rtthread.h>
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Select MSD Card: ChipSelect pin low  */
+#define MSD_CS_LOW()    GPIO_ResetBits(GPIOA, GPIO_Pin_4)
+/* Deselect MSD Card: ChipSelect pin high */
+#define MSD_CS_HIGH()   GPIO_SetBits(GPIOA, GPIO_Pin_4)
+#define MSD_SPI         SPI1
+#define MSD_RCC_SPI     RCC_APB2Periph_SPI1
+
+/* 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 < 10; 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 xxx0<status>1
+*                   - 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)
+{
+  int i;
+  /* 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);
+	for (i = 0; i < 0xfff; i++);
+
+    /* MSD chip select low */
+    MSD_CS_LOW();
+	for (i = 0; i < 0xfff; i++);
+
+    /* 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.
+*******************************************************************************/
+u8 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);
+
+  /* Get the received data */
+  Data = SPI_I2S_ReceiveData(MSD_SPI);
+  
+  return 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;
+
+  /* GPIOA and GPIOC Periph clock enable */
+  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
+  /* SPI Periph clock enable */
+  RCC_APB2PeriphClockCmd(MSD_RCC_SPI, ENABLE);
+
+  /* Configure SPI pins: SCK, MISO and MOSI */
+  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);
+
+  /* Configure PA4 pin: CS pin, PC4 : SD Power */
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+  GPIO_Init(GPIOA, &GPIO_InitStructure);
+  
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+  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 */
+  GPIO_ResetBits(GPIOC, GPIO_Pin_4);
+  for (delay = 0; delay < 0xfffff; delay ++);
+}
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
+
+/*
+ * RT-Thread SD Card Driver
+ * 2009-04-17 Bernard first version
+ * 2010-07-15 Modify read/write according new block driver interface 
+ */
+#include <rtthread.h>
+#include <dfs_fs.h>
+
+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; i ++)
+	{
+		status = MSD_ReadBlock((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE),
+			(part.offset + pos + i)* SECTOR_SIZE, 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);
+
+	/* write all sectors */
+	for (i = 0; i < size; i ++)
+	{
+		status = MSD_WriteBuffer((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE),
+			(part.offset + pos + i)* SECTOR_SIZE, 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)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+	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.user_data = 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");
+	}
+}

+ 173 - 0
bsp/stm32f107/msd.h

@@ -0,0 +1,173 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name          : msd.h
+* Author             : MCD Application Team
+* Version            : V2.1
+* Date               : 05/30/2008
+* Description        : Header for msd.c file.
+********************************************************************************
+* 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.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __MSD_H
+#define __MSD_H
+
+/* Includes ------------------------------------------------------------------*/
+#include <stm32f10x.h>
+
+/* Private define ------------------------------------------------------------*/
+/* Block Size */
+#define BLOCK_SIZE    512
+
+/* Dummy byte */
+#define DUMMY   0xFF
+
+/* Start Data tokens  */
+/* Tokens (necessary because at nop/idle (and CS active) only 0xff is on the data/command line) */
+#define MSD_START_DATA_SINGLE_BLOCK_READ 0xFE  /* Data token start byte, Start Single Block Read */
+#define MSD_START_DATA_MULTIPLE_BLOCK_READ  0xFE  /* Data token start byte, Start Multiple Block Read */
+#define MSD_START_DATA_SINGLE_BLOCK_WRITE 0xFE  /* Data token start byte, Start Single Block Write */
+#define MSD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFD  /* Data token start byte, Start Multiple Block Write */
+#define MSD_STOP_DATA_MULTIPLE_BLOCK_WRITE 0xFD  /* Data toke stop byte, Stop Multiple Block Write */
+
+/* MSD functions return */
+#define MSD_SUCCESS       0x00
+#define MSD_FAIL          0xFF
+
+/* MSD reponses and error flags */
+#define MSD_RESPONSE_NO_ERROR      0x00
+#define MSD_IN_IDLE_STATE          0x01
+#define MSD_ERASE_RESET            0x02
+#define MSD_ILLEGAL_COMMAND        0x04
+#define MSD_COM_CRC_ERROR          0x08
+#define MSD_ERASE_SEQUENCE_ERROR   0x10
+#define MSD_ADDRESS_ERROR          0x20
+#define MSD_PARAMETER_ERROR        0x40
+#define MSD_RESPONSE_FAILURE       0xFF
+
+/* Data response error */
+#define MSD_DATA_OK                0x05
+#define MSD_DATA_CRC_ERROR         0x0B
+#define MSD_DATA_WRITE_ERROR       0x0D
+#define MSD_DATA_OTHER_ERROR       0xFF
+
+/* Commands: CMDxx = CMD-number | 0x40 */
+#define MSD_GO_IDLE_STATE          0   /* CMD0=0x40 */
+#define MSD_SEND_OP_COND           1   /* CMD1=0x41 */
+#define MSD_SEND_CSD               9   /* CMD9=0x49 */
+#define MSD_SEND_CID               10  /* CMD10=0x4A */
+#define MSD_STOP_TRANSMISSION      12  /* CMD12=0x4C */
+#define MSD_SEND_STATUS            13  /* CMD13=0x4D */
+#define MSD_SET_BLOCKLEN           16  /* CMD16=0x50 */
+#define MSD_READ_SINGLE_BLOCK      17  /* CMD17=0x51 */
+#define MSD_READ_MULTIPLE_BLOCK    18  /* CMD18=0x52 */
+#define MSD_SET_BLOCK_COUNT        23  /* CMD23=0x57 */
+#define MSD_WRITE_BLOCK            24  /* CMD24=0x58 */
+#define MSD_WRITE_MULTIPLE_BLOCK   25  /* CMD25=0x59 */
+#define MSD_PROGRAM_CSD            27  /* CMD27=0x5B */
+#define MSD_SET_WRITE_PROT         28  /* CMD28=0x5C */
+#define MSD_CLR_WRITE_PROT         29  /* CMD29=0x5D */
+#define MSD_SEND_WRITE_PROT        30  /* CMD30=0x5E */
+#define MSD_TAG_SECTOR_START       32  /* CMD32=0x60 */
+#define MSD_TAG_SECTOR_END         33  /* CMD33=0x61 */
+#define MSD_UNTAG_SECTOR           34  /* CMD34=0x62 */
+#define MSD_TAG_ERASE_GROUP_START  35  /* CMD35=0x63 */
+#define MSD_TAG_ERASE_GROUP_END    36  /* CMD36=0x64 */
+#define MSD_UNTAG_ERASE_GROUP      37  /* CMD37=0x65 */
+#define MSD_ERASE                  38  /* CMD38=0x66 */
+#define MSD_READ_OCR               39  /* CMD39=0x67 */
+#define MSD_CRC_ON_OFF             40  /* CMD40=0x68 */
+
+/* Exported types ------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+typedef struct _MSD_CSD      /*Card Specific Data*/
+{
+  vu8  CSDStruct;            /* CSD structure */
+  vu8  SysSpecVersion;       /* System specification version */
+  vu8  Reserved1;            /* Reserved */
+  vu8  TAAC;                 /* Data read access-time 1 */
+  vu8  NSAC;                 /* Data read access-time 2 in CLK cycles */
+  vu8  MaxBusClkFrec;        /* Max. bus clock frequency */
+  vu16 CardComdClasses;      /* Card command classes */
+  vu8  RdBlockLen;           /* Max. read data block length */
+  vu8  PartBlockRead;        /* Partial blocks for read allowed */
+  vu8  WrBlockMisalign;      /* Write block misalignment */
+  vu8  RdBlockMisalign;      /* Read block misalignment */
+  vu8  DSRImpl;              /* DSR implemented */
+  vu8  Reserved2;            /* Reserved */
+  vu16 DeviceSize;           /* Device Size */
+  vu8  MaxRdCurrentVDDMin;   /* Max. read current @ VDD min */
+  vu8  MaxRdCurrentVDDMax;   /* Max. read current @ VDD max */
+  vu8  MaxWrCurrentVDDMin;   /* Max. write current @ VDD min */
+  vu8  MaxWrCurrentVDDMax;   /* Max. write current @ VDD max */
+  vu8  DeviceSizeMul;        /* Device size multiplier */
+  vu8  EraseGrSize;          /* Erase group size */
+  vu8  EraseGrMul;           /* Erase group size multiplier */
+  vu8  WrProtectGrSize;      /* Write protect group size */
+  vu8  WrProtectGrEnable;    /* Write protect group enable */
+  vu8  ManDeflECC;           /* Manufacturer default ECC */
+  vu8  WrSpeedFact;          /* Write speed factor */
+  vu8  MaxWrBlockLen;        /* Max. write data block length */
+  vu8  WriteBlockPaPartial;  /* Partial blocks for write allowed */
+  vu8  Reserved3;            /* Reserded */
+  vu8  ContentProtectAppli;  /* Content protection application */
+  vu8  FileFormatGrouop;     /* File format group */
+  vu8  CopyFlag;             /* Copy flag (OTP) */
+  vu8  PermWrProtect;        /* Permanent write protection */
+  vu8  TempWrProtect;        /* Temporary write protection */
+  vu8  FileFormat;           /* File Format */
+  vu8  ECC;                  /* ECC code */
+  vu8  msd_CRC;                  /* CRC */
+  vu8  Reserved4;            /* always 1*/
+}
+sMSD_CSD;
+
+typedef struct _MSD_CID      /*Card Identification Data*/
+{
+  vu8  ManufacturerID;       /* ManufacturerID */
+  vu16 OEM_AppliID;          /* OEM/Application ID */
+  vu32 ProdName1;            /* Product Name part1 */
+  vu8  ProdName2;            /* Product Name part2*/
+  vu8  ProdRev;              /* Product Revision */
+  vu32 ProdSN;               /* Product Serial Number */
+  vu8  Reserved1;            /* Reserved1 */
+  vu16 ManufactDate;         /* Manufacturing Date */
+  vu8  msd_CRC;                  /* CRC */
+  vu8  Reserved2;            /* always 1*/
+}
+sMSD_CID;
+
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+/*----- High layer function -----*/
+u8 MSD_Init(void);
+u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
+u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
+u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);
+u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead);
+u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd);
+u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid);
+
+/*----- Medium layer function -----*/
+void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc);
+u8 MSD_GetResponse(u8 Response);
+u8 MSD_GetDataResponse(void);
+u8 MSD_GoIdleState(void);
+u16 MSD_GetStatus(void);
+
+/*----- Low layer function -----*/
+u8 MSD_WriteByte(u8 byte);
+u8 MSD_ReadByte(void);
+
+#endif /* __MSD_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/