瀏覽代碼

update SD card driver: use RT-Thread SPI driver.

aozima 12 年之前
父節點
當前提交
8421ecfa27

+ 9 - 0
bsp/stm32f107/drivers/SConscript

@@ -4,6 +4,15 @@ from building import *
 
 cwd     = os.path.join(str(Dir('#')), 'drivers')
 src	= Glob('*.c')
+
+# remove no need file.
+if GetDepend('RT_USING_LWIP') == False:
+	SrcRemove(src, 'stm32_eth.c')
+
+if GetDepend('RT_USING_SPI') == False:
+	SrcRemove(src, 'rt_stm32f10x_spi.c')
+	SrcRemove(src, 'msd.c')
+
 CPPPATH = [cwd]
 
 group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)

+ 6 - 7
bsp/stm32f107/drivers/board.c

@@ -14,7 +14,6 @@
 
 #include <rthw.h>
 #include <rtthread.h>
-
 #include "board.h"
 
 /**
@@ -45,15 +44,15 @@ void NVIC_Configuration(void)
  * This is the timer interrupt service routine.
  *
  */
-void rt_hw_timer_handler(void)
+void SysTick_Handler(void)
 {
-    /* enter interrupt */
-    rt_interrupt_enter();
+	/* enter interrupt */
+	rt_interrupt_enter();
 
-    rt_tick_increase();
+	rt_tick_increase();
 
-    /* leave interrupt */
-    rt_interrupt_leave();
+	/* leave interrupt */
+	rt_interrupt_leave();
 }
 
 /**

+ 3 - 0
bsp/stm32f107/drivers/board.h

@@ -40,6 +40,9 @@
 #define STM32_SRAM_SIZE         64
 #define STM32_SRAM_END          (0x20000000 + STM32_SRAM_SIZE * 1024)
 
+#define RT_USING_UART1
+#define RT_USING_SPI1
+
 void rt_hw_board_init(void);
 void rt_hw_usart_init(void);
 

+ 1603 - 863
bsp/stm32f107/drivers/msd.c

@@ -1,951 +1,1691 @@
-/******************** (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 ------------------------------------------------------------------*/
+/*
+ * File      : msd.c
+ * SPI mode SD Card Driver
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2009-04-17     Bernard      first version.
+ * 2010-07-15     aozima       Modify read/write according new block driver interface.
+ * 2012-02-01     aozima       use new RT-Thread SPI drivers.
+ * 2012-04-11     aozima       get max. data transfer rate from CSD[TRAN_SPEED].
+ * 2012-05-21     aozima       update MMC card support.
+ */
+
+#include <string.h>
 #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)
+
+//#define MSD_TRACE
+
+#ifdef MSD_TRACE
+#define MSD_DEBUG(...)         rt_kprintf("[MSD] %d ", rt_tick_get()); rt_kprintf(__VA_ARGS__);
+#else
+#define MSD_DEBUG(...)
+#endif /* #ifdef MSD_TRACE */
+
+#define DUMMY                 0xFF
+
+#define CARD_NCR_MAX          8
+
+#define CARD_NRC              1
+#define CARD_NCR              1
+
+static struct msd_device  _msd_device;
+
+/* function define */
+static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long);
+
+static rt_err_t MSD_take_owner(struct rt_spi_device* spi_device);
+static void MSD_take_cs(struct rt_spi_device* device);
+static void MSD_release_cs(struct rt_spi_device* device);
+
+static rt_err_t _wait_token(struct rt_spi_device* device, uint8_t token);
+static rt_err_t _wait_ready(struct rt_spi_device* device);
+static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
+static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
+static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
+static rt_size_t rt_msd_sdhc_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
+
+static rt_err_t MSD_take_owner(struct rt_spi_device* spi_device)
 {
-  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());
+    rt_err_t result;
+
+    result = rt_mutex_take(&(spi_device->bus->lock), RT_WAITING_FOREVER);
+    if(result == RT_EOK)
+    {
+        if (spi_device->bus->owner != spi_device)
+        {
+            /* not the same owner as current, re-configure SPI bus */
+            result = spi_device->bus->ops->configure(spi_device, &spi_device->config);
+            if (result == RT_EOK)
+            {
+                /* set SPI bus owner */
+                spi_device->bus->owner = spi_device;
+            }
+        }
+    }
+
+    return result;
+}
+
+static void MSD_take_cs(struct rt_spi_device* device)
+{
+    struct rt_spi_message message;
+
+    /* initial message */
+    message.send_buf = RT_NULL;
+    message.recv_buf = RT_NULL;
+    message.length = 0;
+    message.cs_take = 1;
+    message.cs_release = 0;
+
+    /* transfer message */
+    device->bus->ops->xfer(device, &message);
 }
 
-/*******************************************************************************
-* 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)
+static void MSD_release_cs(struct rt_spi_device* device)
 {
-  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++;
+    struct rt_spi_message message;
+
+    /* initial message */
+    message.send_buf = RT_NULL;
+    message.recv_buf = RT_NULL;
+    message.length = 0;
+    message.cs_take = 0;
+    message.cs_release = 1;
+
+    /* transfer message */
+    device->bus->ops->xfer(device, &message);
+}
+
+static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long)
+{
+    rt_tick_t tick_end = tick_start + tick_long;
+    rt_tick_t tick_now = rt_tick_get();
+    rt_bool_t result = RT_FALSE;
+
+    if(tick_end >= tick_start)
+    {
+        if (tick_now >= tick_end)
+        {
+            result = RT_TRUE;
+        }
+        else
+        {
+            result = RT_FALSE;
+        }
     }
-    /* 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)
+    else
     {
-      rvalue = MSD_RESPONSE_NO_ERROR;
+        if ((tick_now < tick_start ) && (tick_now >= tick_end) )
+        {
+            result = RT_TRUE;
+        }
+        else
+        {
+            result = RT_FALSE;
+        }
     }
-  }
-
-  /* MSD chip select high */
-  MSD_CS_HIGH();
-  /* Send dummy byte: 8 Clock pulses of delay */
-  MSD_WriteByte(DUMMY);
-  /* Returns the reponse */
-  return rvalue;
+
+    return result;
 }
 
-/*******************************************************************************
-* 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)
+static uint8_t crc7(const uint8_t *buf, int len)
 {
-  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;
+    unsigned char	i, j, crc, ch, ch2, ch3;
+
+    crc = 0;
+
+    for (i = 0; i < len; i ++)
+    {
+        ch = buf[i];
+
+        for (j = 0; j < 8; j ++, ch <<= 1)
+        {
+            ch2 = (crc & 0x40) ? 1 : 0;
+            ch3 = (ch & 0x80) ? 1 : 0;
+
+            if (ch2 ^ ch3)
+            {
+                crc ^= 0x04;
+                crc <<= 1;
+                crc |= 0x01;
+            }
+            else
+            {
+                crc <<= 1;
+            }
+        }
     }
-  }
-
-  /* MSD chip select high */
-  MSD_CS_HIGH();
-  /* Send dummy byte: 8 Clock pulses of delay */
-  MSD_WriteByte(DUMMY);
-  /* Returns the reponse */
-  return rvalue;
+
+    return crc;
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t _send_cmd(
+    struct rt_spi_device* device,
+    uint8_t cmd,
+    uint32_t arg,
+    uint8_t crc,
+    response_type type,
+    uint8_t * response
+)
 {
-  u32 i = 0, NbrOfBlock = 0, Offset = 0;
-  u8 rvalue = MSD_RESPONSE_FAILURE;
+    struct rt_spi_message message;
+    uint8_t cmd_buffer[8];
+    uint8_t recv_buffer[sizeof(cmd_buffer)];
+    uint32_t i;
+
+    cmd_buffer[0] = DUMMY;
+    cmd_buffer[1] = (cmd | 0x40);
+    cmd_buffer[2] = (uint8_t)(arg >> 24);
+    cmd_buffer[3] = (uint8_t)(arg >> 16);
+    cmd_buffer[4] = (uint8_t)(arg >> 8);
+    cmd_buffer[5] = (uint8_t)(arg);
+
+    if(crc == 0x00)
+    {
+        crc = crc7(&cmd_buffer[1], 5);
+        crc = (crc<<1) | 0x01;
+    }
+    cmd_buffer[6] = (crc);
+
+    cmd_buffer[7] = DUMMY;
 
-  /* Calculate number of blocks to write */
-  NbrOfBlock = NumByteToWrite / BLOCK_SIZE;
-  /* MSD chip select low */
-  MSD_CS_LOW();
+    /* initial message */
+    message.send_buf = cmd_buffer;
+    message.recv_buf = recv_buffer;
+    message.length = sizeof(cmd_buffer);
+    message.cs_take = message.cs_release = 0;
 
-  /* Data transfer */
-  while (NbrOfBlock --)
-  {
-    /* Send CMD24 (MSD_WRITE_BLOCK) to write blocks */
-    MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr + Offset, 0xFF);
+    _wait_ready(device);
 
-    /* Check if the MSD acknowledged the write block command: R1 response (0x00: no errors) */
-    if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
+    /* transfer message */
+    device->bus->ops->xfer(device, &message);
+
+    for(i=CARD_NCR; i<(CARD_NCR_MAX+1); i++)
     {
-      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++;
+        uint8_t send = DUMMY;
+
+        /* initial message */
+        message.send_buf = &send;
+        message.recv_buf = response;
+        message.length = 1;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+
+        if(0 == (response[0] & 0x80))
+        {
+            break;
+        }
+    } /* wait response */
+
+    if((CARD_NCR_MAX+1) == i)
+    {
+        return RT_ERROR;//fail
     }
-    /* 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;
+
+    //recieve other byte
+    if(type == response_r1)
+    {
+        return RT_EOK;
     }
-    else
+    else if(type == response_r1b)
     {
-      /* Set response value to failure */
-      rvalue = MSD_RESPONSE_FAILURE;
+        rt_tick_t tick_start = rt_tick_get();
+        uint8_t recv;
+
+        while(1)
+        {
+            /* initial message */
+            message.send_buf = RT_NULL;
+            message.recv_buf = &recv;
+            message.length = 1;
+            message.cs_take = message.cs_release = 0;
+
+            /* transfer message */
+            device->bus->ops->xfer(device, &message);
+
+            if(recv == DUMMY)
+            {
+                return RT_EOK;
+            }
+
+            if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(2000)))
+            {
+                return RT_ETIMEOUT;
+            }
+        }
     }
-  }
-
-  /* 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;
+    else if(type == response_r2)
+    {
+        /* initial message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = response+1;
+        message.length = 1;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
     }
-    /* 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 if((type == response_r3) || (type == response_r7))
+    {
+        /* initial message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = response+1;
+        message.length = 4;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
     }
     else
     {
-      /* Set response value to failure */
-      rvalue = MSD_RESPONSE_FAILURE;
+        return RT_ERROR; // unknow type?
     }
-  }
-
-  /* MSD chip select high */
-  MSD_CS_HIGH();
-  /* Send dummy byte: 8 Clock pulses of delay */
-  MSD_WriteByte(DUMMY);
-  /* Returns the reponse */
-  return rvalue;
+
+    return RT_EOK;
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t _wait_token(struct rt_spi_device* device, uint8_t token)
 {
-  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;
+    struct rt_spi_message message;
+    rt_tick_t tick_start;
+    uint8_t send, recv;
+
+    tick_start = rt_tick_get();
+
+    /* wati token */
+    /* initial message */
+    send = DUMMY;
+    message.send_buf = &send;
+    message.recv_buf = &recv;
+    message.length = 1;
+    message.cs_take = message.cs_release = 0;
+
+    while(1)
+    {
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+
+        if(recv == token)
+        {
+            return RT_EOK;
+        }
+
+        if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_WAIT_TOKEN_TIMES)))
+        {
+            MSD_DEBUG("[err] wait data start token timeout!\r\n");
+            return RT_ETIMEOUT;
+        }
+    } /* wati token */
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t _wait_ready(struct rt_spi_device* device)
 {
-  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();
-      }
+    struct rt_spi_message message;
+    rt_tick_t tick_start;
+    uint8_t send, recv;
+
+    tick_start = rt_tick_get();
+
+    send = DUMMY;
+    /* initial message */
+    message.send_buf = &send;
+    message.recv_buf = &recv;
+    message.length = 1;
+    message.cs_take = message.cs_release = 0;
+
+    while(1)
+    {
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+
+        if(recv == DUMMY)
+        {
+            return RT_EOK;
+        }
+
+        if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(1000)))
+        {
+            MSD_DEBUG("[err] wait ready timeout!\r\n");
+            return RT_ETIMEOUT;
+        }
     }
-    /* 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)
+static rt_err_t _read_block(struct rt_spi_device* device, void * buffer, uint32_t block_size)
 {
-  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]);
-  }
-}
+    struct rt_spi_message message;
+    rt_err_t result;
 
-/*******************************************************************************
-* 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;
-      }
+    /* wati token */
+    result = _wait_token(device, MSD_TOKEN_READ_START);
+    if(result != RT_EOK)
+    {
+        return result;
     }
-    /* 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;
+
+    /* read data */
+    {
+        /* initial message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = buffer;
+        message.length = block_size;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+    } /* read data */
+
+    /* get crc */
+    {
+        uint8_t recv_buffer[2];
+
+        /* initial message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = recv_buffer;
+        message.length = 2;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+    } /* get crc */
+
+    return RT_EOK;
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t _write_block(struct rt_spi_device* device, const void * buffer, uint32_t block_size, uint8_t token)
 {
-  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;
-  }
+    struct rt_spi_message message;
+    uint8_t send_buffer[16];
+
+    rt_memset(send_buffer, DUMMY, sizeof(send_buffer));
+    send_buffer[sizeof(send_buffer) - 1] = token;
+
+    /* send start block token */
+    {
+        /* initial message */
+        message.send_buf = send_buffer;
+        message.recv_buf = RT_NULL;
+        message.length = sizeof(send_buffer);
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+    }
+
+    /* send data */
+    {
+        /* initial message */
+        message.send_buf = buffer;
+        message.recv_buf = RT_NULL;
+        message.length = block_size;
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+    }
+
+    /* put crc and get data response */
+    {
+        uint8_t recv_buffer[3];
+        uint8_t response;
+
+        /* initial message */
+        message.send_buf = send_buffer;
+        message.recv_buf = recv_buffer;
+        message.length = sizeof(recv_buffer);
+        message.cs_take = message.cs_release = 0;
+
+        /* transfer message */
+        device->bus->ops->xfer(device, &message);
+
+//        response = 0x0E & recv_buffer[2];
+        response = MSD_GET_DATA_RESPONSE(recv_buffer[2]);
+        if(response != MSD_DATA_OK)
+        {
+            MSD_DEBUG("[err] write block fail! data response : 0x%02X\r\n", response);
+            return RT_ERROR;
+        }
+    }
+
+    /* wati ready */
+    return _wait_ready(device);
 }
 
-/*******************************************************************************
-* Function Name  : MSD_GetStatus
-* Description    : Returns the MSD status.
-* Input          : None
-* Output         : None
-* Return         : The MSD status.
-*******************************************************************************/
-u16 MSD_GetStatus(void)
+/* RT-Thread Device Driver Interface */
+static rt_err_t rt_msd_init(rt_device_t dev)
 {
-  u16 Status = 0;
+    struct msd_device * msd = (struct msd_device *)dev;
+    uint8_t response[MSD_RESPONSE_MAX_LEN];
+    rt_err_t result = RT_EOK;
+    rt_tick_t tick_start;
+    uint32_t OCR;
 
-  /* MSD chip select low */
-  MSD_CS_LOW();
-  /* Send CMD13 (MSD_SEND_STATUS) to get MSD status */
-  MSD_SendCmd(MSD_SEND_STATUS, 0, 0xFF);
+    if(msd->spi_device == RT_NULL)
+    {
+        MSD_DEBUG("[err] the SPI SD device has no SPI!\r\n");
+        return RT_EIO;
+    }
 
-  Status = MSD_ReadByte();
-  Status |= (u16)(MSD_ReadByte() << 8);
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = 1000*400; /* 400kbit/s */
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
+
+    /* init SD card */
+    {
+        struct rt_spi_message message;
+
+        result = MSD_take_owner(msd->spi_device);
+
+        if (result != RT_EOK)
+        {
+            goto _exit;
+        }
+
+        MSD_release_cs(msd->spi_device);
+
+        /* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and
+           start to supply at least 74 SD clocks to the SD card with keeping CMD line to high.
+           In case of SPI mode, CS shall be held to high during 74 clock cycles. */
+        {
+            uint8_t send_buffer[100]; /* 100byte > 74 clock */
+
+            /* initial message */
+            memset(send_buffer, DUMMY, sizeof(send_buffer));
+            message.send_buf = send_buffer;
+            message.recv_buf = RT_NULL;
+            message.length = sizeof(send_buffer);
+            message.cs_take = message.cs_release = 0;
+
+            /* transfer message */
+            msd->spi_device->bus->ops->xfer(msd->spi_device, &message);
+        } /* send 74 clock */
+
+        /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */
+        {
+            tick_start = rt_tick_get();
+
+            while(1)
+            {
+                MSD_take_cs(msd->spi_device);
+                result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
+                MSD_release_cs(msd->spi_device);
+
+                if((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
+                {
+                    break;
+                }
+
+                if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES)))
+                {
+                    MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n");
+                    result = RT_ETIMEOUT;
+                    goto _exit;
+                }
+            }
+
+            MSD_DEBUG("[info] SD card goto IDLE mode OK!\r\n");
+        } /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */
+
+        /* CMD8 */
+        {
+            tick_start = rt_tick_get();
+
+            do
+            {
+                MSD_take_cs(msd->spi_device);
+                result = _send_cmd(msd->spi_device, SEND_IF_COND, 0x01AA, 0x87, response_r7, response);
+                MSD_release_cs(msd->spi_device);
+
+                if(result == RT_EOK)
+                {
+                    MSD_DEBUG("[info] CMD8 response : 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
+                              response[0], response[1], response[2], response[3], response[4]);
+
+                    if(response[0] & (1<<2))
+                    {
+                        /* illegal command, SD V1.x or MMC card */
+                        MSD_DEBUG("[info] CMD8 is illegal command.\r\n");
+                        MSD_DEBUG("[info] maybe Ver1.X SD Memory Card or MMC card!\r\n");
+                        msd->card_type = MSD_CARD_TYPE_SD_V1_X;
+                        break;
+                    }
+                    else
+                    {
+                        /* SD V2.0 or later or SDHC or SDXC memory card! */
+                        MSD_DEBUG("[info] Ver2.00 or later or SDHC or SDXC memory card!\r\n");
+                        msd->card_type = MSD_CARD_TYPE_SD_V2_X;
+                    }
+
+                    if((0xAA == response[4]) && (0x00 == response[3]))
+                    {
+                        /* SD2.0 not support current voltage */
+                        MSD_DEBUG("[err] VCA = 0, SD2.0 not surpport current operation voltage range\r\n");
+                        result = RT_ERROR;
+                        goto _exit;
+                    }
+                }
+                else
+                {
+                    if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(200)))
+                    {
+                        MSD_DEBUG("[err] CMD8 SEND_IF_COND timeout!\r\n");
+                        result = RT_ETIMEOUT;
+                        goto _exit;
+                    }
+                }
+            }
+            while(0xAA != response[4]);
+        } /* CMD8 */
+
+        /* Ver1.X SD Memory Card or MMC card */
+        if(msd->card_type == MSD_CARD_TYPE_SD_V1_X)
+        {
+            rt_bool_t is_sd_v1_x = RT_FALSE;
+            rt_tick_t tick_start;
+
+            /* try SD Ver1.x */
+            while(1)
+            {
+                MSD_take_cs(msd->spi_device);
+
+                result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
+                if(result != RT_EOK)
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n");
+                    goto _exit;
+                }
+
+                if(0 != (response[0]&0xFE))
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n");
+                    break;
+                }
+                MSD_release_cs(msd->spi_device);
+
+                OCR = response[1];
+                OCR = (OCR<<8) + response[2];
+                OCR = (OCR<<8) + response[3];
+                OCR = (OCR<<8) + response[4];
+                MSD_DEBUG("[info] OCR is 0x%08X\r\n", OCR);
+
+                if( 0 == (OCR & (0x1 << 15)))
+                {
+                    MSD_DEBUG(("[err] SD 1.x But not surpport current voltage\r\n"));
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+
+                /* --Send ACMD41 to make card ready */
+                tick_start = rt_tick_get();
+
+                /* try CMD55 + ACMD41 */
+                while(1)
+                {
+                    if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n");
+                        break;
+                    }
+
+                    MSD_take_cs(msd->spi_device);
+
+                    /* CMD55 APP_CMD */
+                    result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
+                    if(result != RT_EOK)
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        continue;
+                    }
+
+                    if(0 != (response[0]&0xFE))
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n");
+                        break;
+                    }
+
+                    /* ACMD41 SD_SEND_OP_COND */
+                    result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response);
+                    if(result != RT_EOK)
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        continue;
+                    }
+
+                    if(0 != (response[0]&0xFE))
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n");
+                        break;
+                    }
+
+                    if(0 == (response[0]&0xFF))
+                    {
+                        MSD_release_cs(msd->spi_device);
+                        is_sd_v1_x = RT_TRUE;
+                        MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n");
+                        break;
+                    }
+                } /* try CMD55 + ACMD41 */
+
+                break;
+            } /* try SD Ver1.x */
+
+            /* try MMC */
+            if(is_sd_v1_x != RT_TRUE)
+            {
+                uint32_t i;
+
+                MSD_DEBUG("[info] try MMC card!\r\n");
+                MSD_release_cs(msd->spi_device);
+
+                /* send dummy clock */
+                {
+                    uint8_t send_buffer[100];
+
+                    /* initial message */
+                    memset(send_buffer, DUMMY, sizeof(send_buffer));
+                    message.send_buf = send_buffer;
+                    message.recv_buf = RT_NULL;
+                    message.length = sizeof(send_buffer);
+                    message.cs_take = message.cs_release = 0;
+
+                    for(i=0; i<10; i++)
+                    {
+                        /* transfer message */
+                        msd->spi_device->bus->ops->xfer(msd->spi_device, &message);
+                    }
+                } /* send dummy clock */
+
+                /* send CMD0 goto IDLE state */
+                tick_start = rt_tick_get();
+                while(1)
+                {
+                    MSD_take_cs(msd->spi_device);
+                    result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
+                    MSD_release_cs(msd->spi_device);
+
+                    if((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
+                    {
+                        break;
+                    }
+
+                    if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES)))
+                    {
+                        MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n");
+                        result = RT_ETIMEOUT;
+                        goto _exit;
+                    }
+                } /* send CMD0 goto IDLE stat */
+
+                /* send CMD1 */
+                tick_start = rt_tick_get();
+                while(1)
+                {
+                    MSD_take_cs(msd->spi_device);
+                    result = _send_cmd(msd->spi_device, SEND_OP_COND, 0x00, 0x00, response_r1, response);
+                    MSD_release_cs(msd->spi_device);
+
+                    if((result == RT_EOK) && (response[0] == MSD_RESPONSE_NO_ERROR))
+                    {
+                        MSD_DEBUG("[info] It is MMC card!!!\r\n");
+                        msd->card_type = MSD_CARD_TYPE_MMC;
+                        break;
+                    }
+
+                    if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES)))
+                    {
+                        MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n");
+                        result = RT_ETIMEOUT;
+                        goto _exit;
+                    }
+                } /* send CMD1 */
+            } /* try MMC */
+        }
+        else if(msd->card_type == MSD_CARD_TYPE_SD_V2_X)
+        {
+            MSD_take_cs(msd->spi_device);
+
+            result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
+            if(result != RT_EOK)
+            {
+                MSD_release_cs(msd->spi_device);
+                MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n");
+                goto _exit;
+            }
+
+            if((response[0] & 0xFE) != 0)
+            {
+                MSD_release_cs(msd->spi_device);
+                MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n");
+                result = RT_ERROR;
+                goto _exit;
+            }
+
+            MSD_release_cs(msd->spi_device);
+
+            OCR = response[1];
+            OCR = (OCR<<8) + response[2];
+            OCR = (OCR<<8) + response[3];
+            OCR = (OCR<<8) + response[4];
+            MSD_DEBUG("[info] OCR is 0x%08X\r\n", OCR);
+
+            if( 0 == (OCR & (0x1 << 15)))
+            {
+                MSD_DEBUG(("[err] SD 1.x But not surpport current voltage\r\n"));
+                result = RT_ERROR;
+                goto _exit;
+            }
+
+            /* --Send ACMD41 to make card ready */
+            tick_start = rt_tick_get();
+
+            /* try CMD55 + ACMD41 */
+            do
+            {
+                MSD_take_cs(msd->spi_device);
+                if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n");
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+
+                /* CMD55 APP_CMD */
+                result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x65, response_r1, response);
+//                if((result != RT_EOK) || (response[0] == 0x01))
+                if(result != RT_EOK)
+                {
+                    MSD_release_cs(msd->spi_device);
+                    continue;
+                }
+
+                if((response[0] & 0xFE) != 0)
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[err] Not SD ready!\r\n");
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+
+                /* ACMD41 SD_SEND_OP_COND */
+                result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response);
+                if(result != RT_EOK)
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[err] ACMD41 fail!\r\n");
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+
+                if((response[0] & 0xFE) != 0)
+                {
+                    MSD_release_cs(msd->spi_device);
+                    MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]);
+//                    break;
+                }
+            }
+            while(response[0] != MSD_RESPONSE_NO_ERROR);
+            MSD_release_cs(msd->spi_device);
+            /* try CMD55 + ACMD41 */
+
+            /* --Read OCR again */
+            MSD_take_cs(msd->spi_device);
+            result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
+            if(result != RT_EOK)
+            {
+                MSD_release_cs(msd->spi_device);
+                MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n");
+                goto _exit;
+            }
+
+            if((response[0] & 0xFE) != 0)
+            {
+                MSD_release_cs(msd->spi_device);
+                MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n");
+                result = RT_ERROR;
+                goto _exit;
+            }
+            MSD_release_cs(msd->spi_device);
+
+            OCR = response[1];
+            OCR = (OCR<<8) + response[2];
+            OCR = (OCR<<8) + response[3];
+            OCR = (OCR<<8) + response[4];
+            MSD_DEBUG("[info] OCR 2nd read is 0x%08X\r\n", OCR);
+
+            if((OCR & 0x40000000) != 0)
+            {
+                MSD_DEBUG("[info] It is SD2.0 SDHC Card!!!\r\n");
+                msd->card_type = MSD_CARD_TYPE_SD_SDHC;
+            }
+            else
+            {
+                MSD_DEBUG("[info] It is SD2.0 standard capacity Card!!!\r\n");
+            }
+        } /* MSD_CARD_TYPE_SD_V2_X */
+        else
+        {
+            MSD_DEBUG("[err] SD card type unkonw!\r\n");
+            result = RT_ERROR;
+            goto _exit;
+        }
+    } /* init SD card */
+
+    if(msd->card_type == MSD_CARD_TYPE_SD_SDHC)
+    {
+        dev->read  = rt_msd_sdhc_read;
+        dev->write = rt_msd_sdhc_write;
+    }
+    else
+    {
+        dev->read  = rt_msd_read;
+        dev->write = rt_msd_write;
+    }
 
-  /* MSD chip select high */
-  MSD_CS_HIGH();
-  /* Send dummy byte 0xFF */
-  MSD_WriteByte(DUMMY);
+    /* set CRC */
+    {
+        MSD_release_cs(msd->spi_device);
+        MSD_take_cs(msd->spi_device);
+#ifdef MSD_USE_CRC
+        result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response);
+#else
+        result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response);
+#endif
+        MSD_release_cs(msd->spi_device);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD59 CRC_ON_OFF fail! response : 0x%02X\r\n", response[0]);
+            result = RT_ERROR;
+            goto _exit;
+        }
+    } /* set CRC */
+
+    /* CMD16 SET_BLOCKLEN */
+    {
+        MSD_release_cs(msd->spi_device);
+        MSD_take_cs(msd->spi_device);
+        result = _send_cmd(msd->spi_device, SET_BLOCKLEN, SECTOR_SIZE, 0x00, response_r1, response);
+        MSD_release_cs(msd->spi_device);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]);
+            result = RT_ERROR;
+            goto _exit;
+        }
+        msd->geometry.block_size = SECTOR_SIZE;
+        msd->geometry.bytes_per_sector = SECTOR_SIZE;
+    }
 
-  return Status;
+    /* read CSD */
+    {
+        uint8_t CSD_buffer[MSD_CSD_LEN];
+
+        MSD_take_cs(msd->spi_device);
+//        result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0xAF, response_r1, response);
+        result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response);
+
+        if(result != RT_EOK)
+        {
+            MSD_release_cs(msd->spi_device);
+            MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n");
+            goto _exit;
+        }
+
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_release_cs(msd->spi_device);
+            MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]);
+            result = RT_ERROR;
+            goto _exit;
+        }
+
+        result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN);
+        MSD_release_cs(msd->spi_device);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] read CSD fail!\r\n");
+            goto _exit;
+        }
+
+        /* Analyze CSD */
+        {
+            uint8_t  CSD_STRUCTURE;
+            uint32_t C_SIZE;
+            uint32_t card_capacity;
+
+            uint8_t  tmp8;
+            uint16_t tmp16;
+            uint32_t tmp32;
+
+            /* get CSD_STRUCTURE */
+            tmp8 = CSD_buffer[0] & 0xC0; /* 0b11000000 */
+            CSD_STRUCTURE = tmp8 >> 6;
+
+            /* MMC CSD Analyze. */
+            if(msd->card_type == MSD_CARD_TYPE_MMC)
+            {
+                uint8_t C_SIZE_MULT;
+                uint8_t READ_BL_LEN;
+
+                if(CSD_STRUCTURE > 2)
+                {
+                    MSD_DEBUG("[err] bad CSD Version : %d\r\n", CSD_STRUCTURE);
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+
+                if(CSD_STRUCTURE == 0)
+                {
+                    MSD_DEBUG("[info] CSD version No. 1.0\r\n");
+                }
+                else if(CSD_STRUCTURE == 1)
+                {
+                    MSD_DEBUG("[info] CSD version No. 1.1\r\n");
+                }
+                else if(CSD_STRUCTURE == 2)
+                {
+                    MSD_DEBUG("[info] CSD version No. 1.2\r\n");
+                }
+
+                /* get TRAN_SPEED 8bit [103:96] */
+                tmp8 = CSD_buffer[3];
+                tmp8 &= 0x03; /* [2:0] transfer rate unit.*/
+                if(tmp8 == 0)
+                {
+                    msd->max_clock = 100 * 1000; /* 0=100kbit/s. */
+                }
+                else if(tmp8 == 1)
+                {
+                    msd->max_clock = 1 * 1000 * 1000; /* 1=1Mbit/s. */
+                }
+                else if(tmp8 == 2)
+                {
+                    msd->max_clock = 10 * 1000 * 1000; /* 2=10Mbit/s. */
+                }
+                else if(tmp8 == 3)
+                {
+                    msd->max_clock = 100 * 1000 * 1000; /* 3=100Mbit/s. */
+                }
+                if(tmp8 == 0)
+                {
+                    MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dkbit/s.\r\n", tmp8, msd->max_clock/1000);
+                }
+                else
+                {
+                    MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000);
+                }
+
+                /* get READ_BL_LEN 4bit [83:80] */
+                tmp8 = CSD_buffer[5] & 0x0F; /* 0b00001111; */
+                READ_BL_LEN = tmp8;		     /* 4 bit */
+                MSD_DEBUG("[info] CSD : READ_BL_LEN : %d %dbyte\r\n", READ_BL_LEN, (1 << READ_BL_LEN));
+
+                /* get C_SIZE 12bit [73:62] */
+                tmp16 = CSD_buffer[6] & 0x03; /* get [73:72] 0b00000011 */
+                tmp16 = tmp16<<8;
+                tmp16 += CSD_buffer[7];       /* get [71:64] */
+                tmp16 = tmp16<<2;
+                tmp8 = CSD_buffer[8] & 0xC0;  /* get [63:62] 0b11000000 */
+                tmp8 = tmp8>>6;
+                tmp16 = tmp16 + tmp8;
+                C_SIZE = tmp16;				//12 bit
+                MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE);
+
+                /* get C_SIZE_MULT 3bit [49:47] */
+                tmp8 = CSD_buffer[9] & 0x03;//0b00000011;
+                tmp8 = tmp8<<1;
+                tmp8 = tmp8 + ((CSD_buffer[10] & 0x80/*0b10000000*/)>>7);
+                C_SIZE_MULT = tmp8;			// 3 bit
+                MSD_DEBUG("[info] CSD : C_SIZE_MULT : %d\r\n", C_SIZE_MULT);
+
+                /* memory capacity = BLOCKNR * BLOCK_LEN */
+                /* BLOCKNR = (C_SIZE+1) * MULT */
+                /* MULT = 2^(C_SIZE_MULT+2) */
+                /* BLOCK_LEN = 2^READ_BL_LEN */
+                card_capacity = (1 << READ_BL_LEN) * ((C_SIZE + 1) * (1 << (C_SIZE_MULT+2)));
+                msd->geometry.sector_count = card_capacity / msd->geometry.bytes_per_sector;
+                MSD_DEBUG("[info] card capacity : %d Mbyte\r\n", card_capacity/(1024*1024));
+            }
+            else /* SD CSD Analyze. */
+            {
+                if(CSD_STRUCTURE == 0)
+                {
+                    uint8_t C_SIZE_MULT;
+                    uint8_t READ_BL_LEN;
+
+                    MSD_DEBUG("[info] CSD Version 1.0\r\n");
+
+                    /* get TRAN_SPEED 8bit [103:96] */
+                    tmp8 = CSD_buffer[3];
+                    if(tmp8 == 0x32)
+                    {
+                        msd->max_clock = 1000 * 1000 * 10; /* 10Mbit/s. */
+                    }
+                    else if(tmp8 == 0x5A)
+                    {
+                        msd->max_clock = 1000 * 1000 * 50; /* 50Mbit/s. */
+                    }
+                    else
+                    {
+                        msd->max_clock = 1000 * 1000 * 1; /* 1Mbit/s default. */
+                    }
+                    MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000);
+
+                    /* get READ_BL_LEN 4bit [83:80] */
+                    tmp8 = CSD_buffer[5] & 0x0F; /* 0b00001111; */
+                    READ_BL_LEN = tmp8;		     /* 4 bit */
+                    MSD_DEBUG("[info] CSD : READ_BL_LEN : %d %dbyte\r\n", READ_BL_LEN, (1 << READ_BL_LEN));
+
+                    /* get C_SIZE 12bit [73:62] */
+                    tmp16 = CSD_buffer[6] & 0x03; /* get [73:72] 0b00000011 */
+                    tmp16 = tmp16<<8;
+                    tmp16 += CSD_buffer[7];       /* get [71:64] */
+                    tmp16 = tmp16<<2;
+                    tmp8 = CSD_buffer[8] & 0xC0;  /* get [63:62] 0b11000000 */
+                    tmp8 = tmp8>>6;
+                    tmp16 = tmp16 + tmp8;
+                    C_SIZE = tmp16;				//12 bit
+                    MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE);
+
+                    /* get C_SIZE_MULT 3bit [49:47] */
+                    tmp8 = CSD_buffer[9] & 0x03;//0b00000011;
+                    tmp8 = tmp8<<1;
+                    tmp8 = tmp8 + ((CSD_buffer[10] & 0x80/*0b10000000*/)>>7);
+                    C_SIZE_MULT = tmp8;			// 3 bit
+                    MSD_DEBUG("[info] CSD : C_SIZE_MULT : %d\r\n", C_SIZE_MULT);
+
+                    /* memory capacity = BLOCKNR * BLOCK_LEN */
+                    /* BLOCKNR = (C_SIZE+1) * MULT */
+                    /* MULT = 2^(C_SIZE_MULT+2) */
+                    /* BLOCK_LEN = 2^READ_BL_LEN */
+                    card_capacity = (1 << READ_BL_LEN) * ((C_SIZE + 1) * (1 << (C_SIZE_MULT+2)));
+                    msd->geometry.sector_count = card_capacity / msd->geometry.bytes_per_sector;
+                    MSD_DEBUG("[info] card capacity : %d Mbyte\r\n", card_capacity/(1024*1024));
+                }
+                else if(CSD_STRUCTURE == 1)
+                {
+                    MSD_DEBUG("[info] CSD Version 2.0\r\n");
+
+                    /* get TRAN_SPEED 8bit [103:96] */
+                    tmp8 = CSD_buffer[3];
+                    if(tmp8 == 0x32)
+                    {
+                        msd->max_clock = 1000 * 1000 * 10; /* 10Mbit/s. */
+                    }
+                    else if(tmp8 == 0x5A)
+                    {
+                        msd->max_clock = 1000 * 1000 * 50; /* 50Mbit/s. */
+                    }
+                    else if(tmp8 == 0x0B)
+                    {
+                        msd->max_clock = 1000 * 1000 * 100; /* 100Mbit/s. */
+                        /* UHS50 Card sets TRAN_SPEED to 0Bh (100Mbit/sec), */
+                        /* for both SDR50 and DDR50 modes. */
+                    }
+                    else if(tmp8 == 0x2B)
+                    {
+                        msd->max_clock = 1000 * 1000 * 200; /* 200Mbit/s. */
+                        /* UHS104 Card sets TRAN_SPEED to 2Bh (200Mbit/sec). */
+                    }
+                    else
+                    {
+                        msd->max_clock = 1000 * 1000 * 1; /* 1Mbit/s default. */
+                    }
+                    MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000);
+
+                    /* get C_SIZE 22bit [69:48] */
+                    tmp32 = CSD_buffer[7] & 0x3F; /* 0b00111111 */
+                    tmp32 = tmp32<<8;
+                    tmp32 += CSD_buffer[8];
+                    tmp32 = tmp32<<8;
+                    tmp32 += CSD_buffer[9];
+                    C_SIZE = tmp32;
+                    MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE);
+
+                    /* memory capacity = (C_SIZE+1) * 512K byte */
+                    card_capacity = (C_SIZE + 1) / 2; /* unit : Mbyte */
+                    msd->geometry.sector_count = card_capacity * 1024; /* 1 Mbyte = 512 byte X 2048 */
+                    MSD_DEBUG("[info] card capacity : %d.%d Gbyte\r\n", card_capacity/1024, (card_capacity%1024)*100/1024);
+                }
+                else
+                {
+                    MSD_DEBUG("[err] bad CSD Version : %d\r\n", CSD_STRUCTURE);
+                    result = RT_ERROR;
+                    goto _exit;
+                }
+            } /* SD CSD Analyze. */
+        } /* Analyze CSD */
+
+    } /* read CSD */
+
+    /* config spi to high speed */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = msd->max_clock;
+
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
+
+_exit:
+    MSD_release_cs(msd->spi_device);
+    rt_mutex_release(&(msd->spi_device->bus->lock));
+    return result;
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t rt_msd_open(rt_device_t dev, rt_uint16_t oflag)
 {
-  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;
+//    struct msd_device * msd = (struct msd_device *)dev;
+    return RT_EOK;
 }
 
-/*******************************************************************************
-* 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)
+static rt_err_t rt_msd_close(rt_device_t dev)
 {
-  /* 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;
+//    struct msd_device * msd = (struct msd_device *)dev;
+    return RT_EOK;
 }
 
-/*******************************************************************************
-* Function Name  : MSD_ReadByte
-* Description    : Read a byte from the MSD.
-* Input          : None.
-* Output         : None
-* Return         : The received byte.
-*******************************************************************************/
-u8 MSD_ReadByte(void)
+static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
 {
-  u8 Data = 0;
+    struct msd_device * msd = (struct msd_device *)dev;
+    uint8_t response[MSD_RESPONSE_MAX_LEN];
+    rt_err_t result = RT_EOK;
+
+    result = MSD_take_owner(msd->spi_device);
+
+    if (result != RT_EOK)
+    {
+        goto _exit;
+    }
 
-  /* 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);
+    /* config spi to high speed */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = msd->max_clock;
 
-  /* 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);
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
 
-  /* Return the shifted data */
-  return Data;
+    /* SINGLE_BLOCK? */
+    if(size == 1)
+    {
+        MSD_take_cs(msd->spi_device);
+
+        result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+            goto _exit;
+        }
+
+        result = _read_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+        }
+    }
+    else if(size > 1)
+    {
+        uint32_t i;
+
+        MSD_take_cs(msd->spi_device);
+
+        result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+            goto _exit;
+        }
+
+        for(i=0; i<size; i++)
+        {
+            result = _read_block(msd->spi_device,
+                                 (uint8_t *)buffer + msd->geometry.bytes_per_sector * i,
+                                 msd->geometry.bytes_per_sector);
+            if(result != RT_EOK)
+            {
+                MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos);
+                size = i;
+                break;
+            }
+        }
+
+        /* send CMD12 stop transfer */
+        result = _send_cmd(msd->spi_device, STOP_TRANSMISSION, 0x00, 0x00, response_r1b, response);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK, send stop token fail!\r\n");
+        }
+    } /* READ_MULTIPLE_BLOCK */
+
+_exit:
+    /* release and exit */
+    MSD_release_cs(msd->spi_device);
+    rt_mutex_release(&(msd->spi_device->bus->lock));
+
+    return size;
 }
 
-/*******************************************************************************
-* Function Name  : SPI_Config
-* Description    : Initializes the SPI and CS pins.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void SPI_Config(void)
+static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
 {
-  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 ++);
-}
+    struct msd_device * msd = (struct msd_device *)dev;
+    uint8_t response[MSD_RESPONSE_MAX_LEN];
+    rt_err_t result = RT_EOK;
 
-/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
+    result = MSD_take_owner(msd->spi_device);
 
-/*
- * 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;
+    if (result != RT_EOK)
+    {
+        goto _exit;
+    }
 
-#define SECTOR_SIZE 512
+    /* config spi to high speed */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = msd->max_clock;
 
-/* RT-Thread Device Driver Interface */
-static rt_err_t rt_msd_init(rt_device_t dev)
-{
-	sMSD_CSD MSD_csd;
-	MSD_GetCSDRegister(&MSD_csd);
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
 
-	return RT_EOK;
+    /* SINGLE_BLOCK? */
+    if(size == 1)
+    {
+        MSD_take_cs(msd->spi_device);
+
+        result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+            goto _exit;
+        }
+
+        result = _read_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+        }
+    }
+    else if(size > 1)
+    {
+        uint32_t i;
+
+        MSD_take_cs(msd->spi_device);
+
+        result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+            goto _exit;
+        }
+
+        for(i=0; i<size; i++)
+        {
+            result = _read_block(msd->spi_device,
+                                 (uint8_t *)buffer + msd->geometry.bytes_per_sector * i,
+                                 msd->geometry.bytes_per_sector);
+            if(result != RT_EOK)
+            {
+                MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos);
+                size = i;
+                break;
+            }
+        }
+
+        /* send CMD12 stop transfer */
+        result = _send_cmd(msd->spi_device, STOP_TRANSMISSION, 0x00, 0x00, response_r1b, response);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK, send stop token fail!\r\n");
+        }
+    } /* READ_MULTIPLE_BLOCK */
+
+_exit:
+    /* release and exit */
+    MSD_release_cs(msd->spi_device);
+    rt_mutex_release(&(msd->spi_device->bus->lock));
+
+    return size;
 }
 
-static rt_err_t rt_msd_open(rt_device_t dev, rt_uint16_t oflag)
+static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
 {
-	return RT_EOK;
-}
+    struct msd_device * msd = (struct msd_device *)dev;
+    uint8_t response[MSD_RESPONSE_MAX_LEN];
+    rt_err_t result;
 
-static rt_err_t rt_msd_close(rt_device_t dev)
-{
-	return RT_EOK;
-}
+    result = MSD_take_owner(msd->spi_device);
 
-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;
+    if (result != RT_EOK)
+    {
+        MSD_DEBUG("[err] get SPI owner fail!\r\n");
+        goto _exit;
+    }
+
+    /* config spi to high speed */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = msd->max_clock;
+
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
+
+    /* SINGLE_BLOCK? */
+    if(size == 1)
+    {
+        MSD_take_cs(msd->spi_device);
+        result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD WRITE_BLOCK fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+
+        result = _write_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector, MSD_TOKEN_WRITE_SINGLE_START);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+        }
+    }
+    else if(size > 1)
+    {
+        struct rt_spi_message message;
+        uint32_t i;
+
+        MSD_take_cs(msd->spi_device);
+
+#ifdef MSD_USE_PRE_ERASED
+        if(msd->card_type != MSD_CARD_TYPE_MMC)
+        {
+            /* CMD55 APP_CMD */
+            result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
+            if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+            {
+                MSD_DEBUG("[err] CMD55 APP_CMD fail!\r\n");
+                size = 0;
+                goto _exit;
+            }
+
+            /* ACMD23 Pre-erased */
+            result = _send_cmd(msd->spi_device, SET_WR_BLK_ERASE_COUNT, size, 0x00, response_r1, response);
+            if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+            {
+                MSD_DEBUG("[err] ACMD23 SET_BLOCK_COUNT fail!\r\n");
+                size = 0;
+                goto _exit;
+            }
+        }
+#endif
+
+        result = _send_cmd(msd->spi_device, WRITE_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD WRITE_MULTIPLE_BLOCK fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+
+        /* write all block */
+        for(i=0; i<size; i++)
+        {
+            result = _write_block(msd->spi_device,
+                                  (const uint8_t *)buffer + msd->geometry.bytes_per_sector * i,
+                                  msd->geometry.bytes_per_sector,
+                                  MSD_TOKEN_WRITE_MULTIPLE_START);
+            if(result != RT_EOK)
+            {
+                MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos);
+                size = i;
+                break;
+            }
+        } /* write all block */
+
+        /* send stop token */
+        {
+            uint8_t send_buffer[18];
+
+            rt_memset(send_buffer, DUMMY, sizeof(send_buffer));
+            send_buffer[sizeof(send_buffer) - 1] = MSD_TOKEN_WRITE_MULTIPLE_STOP;
+
+            /* initial message */
+            message.send_buf = send_buffer;
+            message.recv_buf = RT_NULL;
+            message.length = sizeof(send_buffer);
+            message.cs_take = message.cs_release = 0;
+
+            /* transfer message */
+            msd->spi_device->bus->ops->xfer(msd->spi_device, &message);
+        }
+
+        /* wait ready */
+        result = _wait_ready(msd->spi_device);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[warning] wait WRITE_MULTIPLE_BLOCK stop token ready timeout!\r\n");
+        }
+    } /* size > 1 */
+
+_exit:
+    /* release and exit */
+    MSD_release_cs(msd->spi_device);
+    rt_mutex_release(&(msd->spi_device->bus->lock));
+
+    return size;
 }
 
-static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+static rt_size_t rt_msd_sdhc_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;
+    struct msd_device * msd = (struct msd_device *)dev;
+    uint8_t response[MSD_RESPONSE_MAX_LEN];
+    rt_err_t result;
+
+    result = MSD_take_owner(msd->spi_device);
+
+    if (result != RT_EOK)
+    {
+        goto _exit;
+    }
+
+    /* config spi to high speed */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = msd->max_clock;
+
+        rt_spi_configure(msd->spi_device, &cfg);
+    } /* config spi */
+
+    /* SINGLE_BLOCK? */
+    if(size == 1)
+    {
+        MSD_take_cs(msd->spi_device);
+        result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD WRITE_BLOCK fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+
+        result = _write_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector, MSD_TOKEN_WRITE_SINGLE_START);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos);
+            size = 0;
+        }
+    }
+    else if(size > 1)
+    {
+        struct rt_spi_message message;
+        uint32_t i;
+
+        MSD_take_cs(msd->spi_device);
+
+#ifdef MSD_USE_PRE_ERASED
+        /* CMD55 APP_CMD */
+        result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD55 APP_CMD fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+
+        /* ACMD23 Pre-erased */
+        result = _send_cmd(msd->spi_device, SET_WR_BLK_ERASE_COUNT, size, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] ACMD23 SET_BLOCK_COUNT fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+#endif
+
+        result = _send_cmd(msd->spi_device, WRITE_MULTIPLE_BLOCK, pos, 0x00, response_r1, response);
+        if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
+        {
+            MSD_DEBUG("[err] CMD WRITE_MULTIPLE_BLOCK fail!\r\n");
+            size = 0;
+            goto _exit;
+        }
+
+        /* write all block */
+        for(i=0; i<size; i++)
+        {
+            result = _write_block(msd->spi_device,
+                                  (const uint8_t *)buffer + msd->geometry.bytes_per_sector * i,
+                                  msd->geometry.bytes_per_sector,
+                                  MSD_TOKEN_WRITE_MULTIPLE_START);
+            if(result != RT_EOK)
+            {
+                MSD_DEBUG("[err] write MULTIPLE_BLOCK #%d fail!\r\n", pos);
+                size = i;
+                break;
+            }
+        } /* write all block */
+
+        /* send stop token */
+        {
+            uint8_t send_buffer[18];
+
+            rt_memset(send_buffer, DUMMY, sizeof(send_buffer));
+            send_buffer[sizeof(send_buffer) - 1] = MSD_TOKEN_WRITE_MULTIPLE_STOP;
+
+            /* initial message */
+            message.send_buf = send_buffer;
+            message.recv_buf = RT_NULL;
+            message.length = sizeof(send_buffer);
+            message.cs_take = message.cs_release = 0;
+
+            /* transfer message */
+            msd->spi_device->bus->ops->xfer(msd->spi_device, &message);
+        }
+
+        result = _wait_ready(msd->spi_device);
+        if(result != RT_EOK)
+        {
+            MSD_DEBUG("[warning] wait WRITE_MULTIPLE_BLOCK stop token ready timeout!\r\n");
+        }
+    } /* size > 1 */
+
+_exit:
+    /* release and exit */
+    MSD_release_cs(msd->spi_device);
+    rt_mutex_release(&(msd->spi_device->bus->lock));
+
+    return size;
 }
 
 static rt_err_t rt_msd_control(rt_device_t dev, rt_uint8_t cmd, void *args)
 {
+    struct msd_device * msd = (struct msd_device *)dev;
+
     RT_ASSERT(dev != RT_NULL);
 
-	return RT_EOK;
+    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+    {
+        struct rt_device_blk_geometry *geometry;
+
+        geometry = (struct rt_device_blk_geometry *)args;
+        if (geometry == RT_NULL) return -RT_ERROR;
+
+        geometry->bytes_per_sector = msd->geometry.bytes_per_sector;
+        geometry->block_size = msd->geometry.block_size;
+        geometry->sector_count = msd->geometry.sector_count;
+    }
+
+    return RT_EOK;
 }
 
-void rt_hw_msd_init()
+rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name)
 {
-	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");
-	}
+    rt_err_t result = RT_EOK;
+    struct rt_spi_device * spi_device;
+
+    spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(spi_device == RT_NULL)
+    {
+        MSD_DEBUG("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+    rt_memset(&_msd_device, 0, sizeof(_msd_device));
+    _msd_device.spi_device = spi_device;
+
+    /* register sdcard device */
+    _msd_device.parent.type    = RT_Device_Class_Block;
+
+    _msd_device.geometry.bytes_per_sector = 0;
+    _msd_device.geometry.sector_count = 0;
+    _msd_device.geometry.block_size = 0;
+
+    _msd_device.parent.init    = rt_msd_init;
+    _msd_device.parent.open    = rt_msd_open;
+    _msd_device.parent.close   = rt_msd_close;
+    _msd_device.parent.read    = RT_NULL;
+    _msd_device.parent.write   = RT_NULL;
+    _msd_device.parent.control = rt_msd_control;
+
+    /* no private, no callback */
+    _msd_device.parent.user_data = RT_NULL;
+    _msd_device.parent.rx_indicate = RT_NULL;
+    _msd_device.parent.tx_complete = RT_NULL;
+
+    result = rt_device_register(&_msd_device.parent, sd_device_name,
+                                RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
+
+    return result;
 }

+ 122 - 163
bsp/stm32f107/drivers/msd.h

@@ -1,173 +1,132 @@
-/******************** (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
+/*
+ * File      : msd.h
+ * SPI mode SD Card Driver
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2009-04-17     Bernard      first version.
+ */
+
+#ifndef MSD_H_INCLUDED
+#define MSD_H_INCLUDED
+
+#include <stdint.h>
+#include <drivers/spi.h>
+
+/* SD command (SPI mode) */
+#define GO_IDLE_STATE                       0   /* CMD0  R1  */
+#define SEND_OP_COND                        1   /* CMD1  R1  */
+#define SWITCH_FUNC                         6   /* CMD6  R1  */
+#define SEND_IF_COND                        8   /* CMD8  R7  */
+#define SEND_CSD                            9   /* CMD9  R1  */
+#define SEND_CID                            10  /* CMD10 R1  */
+#define STOP_TRANSMISSION                   12  /* CMD12 R1B */
+#define SEND_STATUS                         13  /* CMD13 R2  */
+#define SET_BLOCKLEN                        16  /* CMD16 R1  */
+#define READ_SINGLE_BLOCK                   17  /* CMD17 R1  */
+#define READ_MULTIPLE_BLOCK                 18  /* CMD18 R1  */
+#define WRITE_BLOCK                         24  /* CMD24 R1  */
+#define WRITE_MULTIPLE_BLOCK                25  /* CMD25 R1  */
+#define PROGRAM_CSD                         27  /* CMD27 R1  */
+#define SET_WRITE_PROT                      28  /* CMD28 R1B */
+#define CLR_WRITE_PROT                      29  /* CMD29 R1B */
+#define SEND_WRITE_PROT                     30  /* CMD30 R1  */
+#define ERASE_WR_BLK_START_ADDR             32  /* CMD32 R1  */
+#define ERASE_WR_BLK_END_ADDR               33  /* CMD33 R1  */
+#define ERASE                               38  /* CMD38 R1B */
+#define LOCK_UNLOCK                         42  /* CMD42 R1  */
+#define APP_CMD                             55  /* CMD55 R1  */
+#define GEN_CMD                             56  /* CMD56 R1  */
+#define READ_OCR                            58  /* CMD58 R3  */
+#define CRC_ON_OFF                          59  /* CMD59 R1  */
+
+/* Application-Specific Command */
+#define SD_STATUS                           13  /* ACMD13 R2 */
+#define SEND_NUM_WR_BLOCKS                  22  /* ACMD22 R1 */
+#define SET_WR_BLK_ERASE_COUNT              23  /* ACMD23 R1 */
+#define SD_SEND_OP_COND                     41  /* ACMD41 R1 */
+#define SET_CLR_CARD_DETECT                 42  /* ACMD42 R1 */
+#define SEND_SCR                            51  /* ACMD51 R1 */
 
 /* 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 */
+#define MSD_TOKEN_READ_START                0xFE  /* Data token start byte, Start Single Block Read */
+#define MSD_TOKEN_WRITE_SINGLE_START        0xFE  /* Data token start byte, Start Single Block Write */
 
-/* MSD functions return */
-#define MSD_SUCCESS       0x00
-#define MSD_FAIL          0xFF
+#define MSD_TOKEN_WRITE_MULTIPLE_START      0xFC  /* Data token start byte, Start Multiple Block Write */
+#define MSD_TOKEN_WRITE_MULTIPLE_STOP       0xFD  /* Data toke stop byte, Stop Multiple Block Write */
 
 /* 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
+#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*/
+#define MSD_DATA_OK                         0x05
+#define MSD_DATA_CRC_ERROR                  0x0B
+#define MSD_DATA_WRITE_ERROR                0x0D
+#define MSD_DATA_OTHER_ERROR                0xFF
+#define MSD_DATA_RESPONSE_MASK              0x1F
+#define MSD_GET_DATA_RESPONSE(res)          (res & MSD_DATA_RESPONSE_MASK)
+
+#define MSD_CMD_LEN                         6           /**< command, arg and crc. */
+#define MSD_RESPONSE_MAX_LEN                5           /**< response max len  */
+#define MSD_CSD_LEN                         16          /**< SD crad CSD register len */
+#define SECTOR_SIZE                         512         /**< sector size, default 512byte */
+
+/* card try timeout, unit: ms */
+#define CARD_TRY_TIMES                      3000
+#define CARD_TRY_TIMES_ACMD41               800
+#define CARD_WAIT_TOKEN_TIMES               800
+
+#define MSD_USE_PRE_ERASED                              /**< id define MSD_USE_PRE_ERASED, before CMD25, send ACMD23 */
+
+/**
+ * SD/MMC card type
+ */
+typedef enum
 {
-  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*/
+	MSD_CARD_TYPE_UNKNOWN = 0,                      /**< unknown */
+	MSD_CARD_TYPE_MMC,                              /**< MultiMedia Card */
+	MSD_CARD_TYPE_SD_V1_X,                          /**< Ver 1.X  Standard Capacity SD Memory Card */
+	MSD_CARD_TYPE_SD_V2_X,                          /**< Ver 2.00 or later Standard Capacity SD Memory Card */
+	MSD_CARD_TYPE_SD_SDHC,                          /**< High Capacity SD Memory Card */
+	MSD_CARD_TYPE_SD_SDXC,                          /**< later Extended Capacity SD Memory Card */
+}msd_card_type;
+
+typedef enum
 {
-  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****/
+    response_type_unknown = 0,
+    response_r1,
+    response_r1b,
+    response_r2,
+    response_r3,
+    response_r4,
+    response_r5,
+    response_r7,
+}response_type;
+
+struct msd_device
+{
+    struct rt_device                parent;      /**< RT-Thread device struct */
+    struct rt_device_blk_geometry   geometry;    /**< sector size, sector count */
+    struct rt_spi_device *          spi_device;  /**< SPI interface */
+    msd_card_type                   card_type;   /**< card type: MMC SD1.x SD2.0 SDHC SDXC */
+    uint32_t                        max_clock;   /**< MAX SPI clock */
+};
+
+extern rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name);
+
+#endif // MSD_H_INCLUDED

+ 85 - 5
bsp/stm32f107/drivers/platform.c

@@ -5,18 +5,98 @@
 #include "stm32_eth.h"
 #endif /* RT_USING_LWIP */
 
+#ifdef RT_USING_SPI
+#include "rt_stm32f10x_spi.h"
+
+#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)
+#include "msd.h"
+#endif /* RT_USING_DFS */
+
+/*
+ * SPI1_MOSI: PA7
+ * SPI1_MISO: PA6
+ * SPI1_SCK : PA5
+ *
+ * CS0: PA4  SD card.
+*/
+static void rt_hw_spi_init(void)
+{
+#ifdef RT_USING_SPI1
+    /* register spi bus */
+    {
+        static struct stm32_spi_bus stm32_spi;
+        GPIO_InitTypeDef GPIO_InitStructure;
+
+        /* Enable GPIO clock */
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,
+        ENABLE);
+
+        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);
+
+        stm32_spi_register(SPI1, &stm32_spi, "spi1");
+    }
+
+    /* attach cs */
+    {
+        static struct rt_spi_device spi_device;
+        static struct stm32_spi_cs  spi_cs;
+
+        GPIO_InitTypeDef GPIO_InitStructure;
+
+        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+
+        /* spi21: PG10 */
+        spi_cs.GPIOx = GPIOA;
+        spi_cs.GPIO_Pin = GPIO_Pin_4;
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+
+        GPIO_InitStructure.GPIO_Pin = spi_cs.GPIO_Pin;
+        GPIO_SetBits(spi_cs.GPIOx, spi_cs.GPIO_Pin);
+        GPIO_Init(spi_cs.GPIOx, &GPIO_InitStructure);
+
+        rt_spi_bus_attach_device(&spi_device, "spi10", "spi1", (void*)&spi_cs);
+    }
+#endif /* RT_USING_SPI1 */
+}
+#endif /* RT_USING_SPI */
+
+
 void rt_platform_init(void)
 {
-#ifdef RT_USING_LWIP
-    /* initialize eth interface */
-    rt_hw_stm32_eth_init();
-#endif /* RT_USING_LWIP */
+#ifdef RT_USING_SPI
+    rt_hw_spi_init();
 
 #if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)
     /* init sdcard driver */
     {
         extern void rt_hw_msd_init(void);
-        rt_hw_msd_init();
+        GPIO_InitTypeDef  GPIO_InitStructure;
+
+        /* PC4 : SD Power */
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+
+        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;
+        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
+        GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+        /* SD card power on. */
+        GPIO_ResetBits(GPIOC, GPIO_Pin_4);
+        rt_thread_delay(2);
+
+        msd_init("sd0", "spi10");
     }
 #endif /* RT_USING_DFS && RT_USING_DFS_ELMFAT */
+
+#endif // RT_USING_SPI
+
+#ifdef RT_USING_LWIP
+    /* initialize eth interface */
+    rt_hw_stm32_eth_init();
+#endif /* RT_USING_LWIP */
+
 }

+ 372 - 0
bsp/stm32f107/drivers/rt_stm32f10x_spi.c

@@ -0,0 +1,372 @@
+#include "rt_stm32f10x_spi.h"
+
+static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
+static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);
+
+static struct rt_spi_ops stm32_spi_ops =
+{
+    configure,
+    xfer
+};
+
+#ifdef USING_SPI1
+static struct stm32_spi_bus stm32_spi_bus_1;
+#endif /* #ifdef USING_SPI1 */
+
+#ifdef USING_SPI2
+static struct stm32_spi_bus stm32_spi_bus_2;
+#endif /* #ifdef USING_SPI2 */
+
+#ifdef USING_SPI3
+static struct stm32_spi_bus stm32_spi_bus_3;
+#endif /* #ifdef USING_SPI3 */
+
+//------------------ DMA ------------------
+#ifdef SPI_USE_DMA
+static uint8_t dummy = 0xFF;
+#endif
+
+#ifdef SPI_USE_DMA
+static void DMA_Configuration(struct stm32_spi_bus * stm32_spi_bus, const void * send_addr, void * recv_addr, rt_size_t size)
+{
+    DMA_InitTypeDef DMA_InitStructure;
+
+    DMA_ClearFlag(stm32_spi_bus->DMA_Channel_RX_FLAG_TC
+                  | stm32_spi_bus->DMA_Channel_RX_FLAG_TE
+                  | stm32_spi_bus->DMA_Channel_TX_FLAG_TC
+                  | stm32_spi_bus->DMA_Channel_TX_FLAG_TE);
+
+    /* RX channel configuration */
+    DMA_Cmd(stm32_spi_bus->DMA_Channel_RX, DISABLE);
+    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(stm32_spi_bus->SPI->DR));
+    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
+    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
+    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+
+    DMA_InitStructure.DMA_BufferSize = size;
+
+    if(recv_addr != RT_NULL)
+    {
+        DMA_InitStructure.DMA_MemoryBaseAddr = (u32) recv_addr;
+        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+    }
+    else
+    {
+        DMA_InitStructure.DMA_MemoryBaseAddr = (u32) (&dummy);
+        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
+    }
+
+    DMA_Init(stm32_spi_bus->DMA_Channel_RX, &DMA_InitStructure);
+
+    DMA_Cmd(stm32_spi_bus->DMA_Channel_RX, ENABLE);
+
+    /* TX channel configuration */
+    DMA_Cmd(stm32_spi_bus->DMA_Channel_TX, DISABLE);
+    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(stm32_spi_bus->SPI->DR));
+    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
+    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+
+    DMA_InitStructure.DMA_BufferSize = size;
+
+    if(send_addr != RT_NULL)
+    {
+        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)send_addr;
+        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+    }
+    else
+    {
+        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)(&dummy);;
+        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
+    }
+
+    DMA_Init(stm32_spi_bus->DMA_Channel_TX, &DMA_InitStructure);
+
+    DMA_Cmd(stm32_spi_bus->DMA_Channel_TX, ENABLE);
+}
+#endif
+
+rt_inline uint16_t get_spi_BaudRatePrescaler(rt_uint32_t max_hz)
+{
+    uint16_t SPI_BaudRatePrescaler;
+
+    /* STM32F10x SPI MAX 18Mhz */
+    if(max_hz >= SystemCoreClock/2 && SystemCoreClock/2 <= 18000000)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
+    }
+    else if(max_hz >= SystemCoreClock/4)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
+    }
+    else if(max_hz >= SystemCoreClock/8)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
+    }
+    else if(max_hz >= SystemCoreClock/16)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
+    }
+    else if(max_hz >= SystemCoreClock/32)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
+    }
+    else if(max_hz >= SystemCoreClock/64)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
+    }
+    else if(max_hz >= SystemCoreClock/128)
+    {
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
+    }
+    else
+    {
+        /* min prescaler 256 */
+        SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
+    }
+
+    return SPI_BaudRatePrescaler;
+}
+
+static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration)
+{
+    struct stm32_spi_bus * stm32_spi_bus = (struct stm32_spi_bus *)device->bus;
+    SPI_InitTypeDef SPI_InitStructure;
+
+    SPI_StructInit(&SPI_InitStructure);
+
+    /* data_width */
+    if(configuration->data_width <= 8)
+    {
+        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
+    }
+    else if(configuration->data_width <= 16)
+    {
+        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
+    }
+    else
+    {
+        return RT_EIO;
+    }
+    /* baudrate */
+    SPI_InitStructure.SPI_BaudRatePrescaler = get_spi_BaudRatePrescaler(configuration->max_hz);
+    /* CPOL */
+    if(configuration->mode & RT_SPI_CPOL)
+    {
+        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
+    }
+    else
+    {
+        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
+    }
+    /* CPHA */
+    if(configuration->mode & RT_SPI_CPHA)
+    {
+        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
+    }
+    else
+    {
+        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
+    }
+    /* MSB or LSB */
+    if(configuration->mode & RT_SPI_MSB)
+    {
+        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
+    }
+    else
+    {
+        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
+    }
+    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
+    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
+    SPI_InitStructure.SPI_NSS  = SPI_NSS_Soft;
+
+    /* init SPI */
+    SPI_I2S_DeInit(stm32_spi_bus->SPI);
+    SPI_Init(stm32_spi_bus->SPI, &SPI_InitStructure);
+    /* Enable SPI_MASTER */
+    SPI_Cmd(stm32_spi_bus->SPI, ENABLE);
+    SPI_CalculateCRC(stm32_spi_bus->SPI, DISABLE);
+
+    return RT_EOK;
+};
+
+static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)
+{
+    struct stm32_spi_bus * stm32_spi_bus = (struct stm32_spi_bus *)device->bus;
+    struct rt_spi_configuration * config = &device->config;
+    SPI_TypeDef * SPI = stm32_spi_bus->SPI;
+    struct stm32_spi_cs * stm32_spi_cs = device->parent.user_data;
+    rt_uint32_t size = message->length;
+
+    /* take CS */
+    if(message->cs_take)
+    {
+        GPIO_ResetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin);
+    }
+
+#ifdef SPI_USE_DMA
+    if(message->length > 32)
+    {
+        if(config->data_width <= 8)
+        {
+            DMA_Configuration(stm32_spi_bus, message->send_buf, message->recv_buf, message->length);
+            SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
+            while (DMA_GetFlagStatus(stm32_spi_bus->DMA_Channel_RX_FLAG_TC) == RESET
+                    || DMA_GetFlagStatus(stm32_spi_bus->DMA_Channel_TX_FLAG_TC) == RESET);
+            SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE);
+        }
+//        rt_memcpy(buffer,_spi_flash_buffer,DMA_BUFFER_SIZE);
+//        buffer += DMA_BUFFER_SIZE;
+    }
+    else
+#endif
+    {
+        if(config->data_width <= 8)
+        {
+            const rt_uint8_t * send_ptr = message->send_buf;
+            rt_uint8_t * recv_ptr = message->recv_buf;
+
+            while(size--)
+            {
+                rt_uint8_t data = 0xFF;
+
+                if(send_ptr != RT_NULL)
+                {
+                    data = *send_ptr++;
+                }
+
+                //Wait until the transmit buffer is empty
+                while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET);
+                // Send the byte
+                SPI_I2S_SendData(SPI, data);
+
+                //Wait until a data is received
+                while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET);
+                // Get the received data
+                data = SPI_I2S_ReceiveData(SPI);
+
+                if(recv_ptr != RT_NULL)
+                {
+                    *recv_ptr++ = data;
+                }
+            }
+        }
+        else if(config->data_width <= 16)
+        {
+            const rt_uint16_t * send_ptr = message->send_buf;
+            rt_uint16_t * recv_ptr = message->recv_buf;
+
+            while(size--)
+            {
+                rt_uint16_t data = 0xFF;
+
+                if(send_ptr != RT_NULL)
+                {
+                    data = *send_ptr++;
+                }
+
+                //Wait until the transmit buffer is empty
+                while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET);
+                // Send the byte
+                SPI_I2S_SendData(SPI, data);
+
+                //Wait until a data is received
+                while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET);
+                // Get the received data
+                data = SPI_I2S_ReceiveData(SPI);
+
+                if(recv_ptr != RT_NULL)
+                {
+                    *recv_ptr++ = data;
+                }
+            }
+        }
+    }
+
+    /* release CS */
+    if(message->cs_release)
+    {
+        GPIO_SetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin);
+    }
+
+    return message->length;
+};
+
+/** \brief init and register stm32 spi bus.
+ *
+ * \param SPI: STM32 SPI, e.g: SPI1,SPI2,SPI3.
+ * \param stm32_spi: stm32 spi bus struct.
+ * \param spi_bus_name: spi bus name, e.g: "spi1"
+ * \return
+ *
+ */
+rt_err_t stm32_spi_register(SPI_TypeDef * SPI,
+                            struct stm32_spi_bus * stm32_spi,
+                            const char * spi_bus_name)
+{
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
+
+    if(SPI == SPI1)
+    {
+    	stm32_spi->SPI = SPI1;
+#ifdef SPI_USE_DMA
+        /* Enable the DMA1 Clock */
+        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
+
+        stm32_spi->DMA_Channel_RX = DMA1_Channel2;
+        stm32_spi->DMA_Channel_TX = DMA1_Channel3;
+        stm32_spi->DMA_Channel_RX_FLAG_TC = DMA1_FLAG_TC2;
+        stm32_spi->DMA_Channel_RX_FLAG_TE = DMA1_FLAG_TE2;
+        stm32_spi->DMA_Channel_TX_FLAG_TC = DMA1_FLAG_TC3;
+        stm32_spi->DMA_Channel_TX_FLAG_TE = DMA1_FLAG_TE3;
+#endif
+        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
+    }
+    else if(SPI == SPI2)
+    {
+        stm32_spi->SPI = SPI2;
+#ifdef SPI_USE_DMA
+        /* Enable the DMA1 Clock */
+        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
+
+        stm32_spi->DMA_Channel_RX = DMA1_Channel4;
+        stm32_spi->DMA_Channel_TX = DMA1_Channel5;
+        stm32_spi->DMA_Channel_RX_FLAG_TC = DMA1_FLAG_TC4;
+        stm32_spi->DMA_Channel_RX_FLAG_TE = DMA1_FLAG_TE4;
+        stm32_spi->DMA_Channel_TX_FLAG_TC = DMA1_FLAG_TC5;
+        stm32_spi->DMA_Channel_TX_FLAG_TE = DMA1_FLAG_TE5;
+#endif
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
+    }
+    else if(SPI == SPI3)
+    {
+    	stm32_spi->SPI = SPI3;
+#ifdef SPI_USE_DMA
+        /* Enable the DMA2 Clock */
+        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
+
+        stm32_spi->DMA_Channel_RX = DMA2_Channel1;
+        stm32_spi->DMA_Channel_TX = DMA2_Channel2;
+        stm32_spi->DMA_Channel_RX_FLAG_TC = DMA2_FLAG_TC1;
+        stm32_spi->DMA_Channel_RX_FLAG_TE = DMA2_FLAG_TE1;
+        stm32_spi->DMA_Channel_TX_FLAG_TC = DMA2_FLAG_TC2;
+        stm32_spi->DMA_Channel_TX_FLAG_TE = DMA2_FLAG_TE2;
+#endif
+        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+    }
+    else
+    {
+        return RT_ENOSYS;
+    }
+
+    return rt_spi_bus_register(&stm32_spi->parent, spi_bus_name, &stm32_spi_ops);
+}

+ 38 - 0
bsp/stm32f107/drivers/rt_stm32f10x_spi.h

@@ -0,0 +1,38 @@
+#ifndef STM32_SPI_H_INCLUDED
+#define STM32_SPI_H_INCLUDED
+
+#include <rtdevice.h>
+
+#include "stm32f10x.h"
+#include "stm32f10x_spi.h"
+
+#include "board.h"
+
+//#define SPI_USE_DMA
+
+struct stm32_spi_bus
+{
+    struct rt_spi_bus parent;
+    SPI_TypeDef * SPI;
+#ifdef SPI_USE_DMA
+    DMA_Channel_TypeDef * DMA_Channel_TX;
+    DMA_Channel_TypeDef * DMA_Channel_RX;
+    uint32_t DMA_Channel_TX_FLAG_TC;
+    uint32_t DMA_Channel_TX_FLAG_TE;
+    uint32_t DMA_Channel_RX_FLAG_TC;
+    uint32_t DMA_Channel_RX_FLAG_TE;
+#endif /* SPI_USE_DMA */
+};
+
+struct stm32_spi_cs
+{
+    GPIO_TypeDef * GPIOx;
+    uint16_t GPIO_Pin;
+};
+
+/* public function list */
+rt_err_t stm32_spi_register(SPI_TypeDef * SPI,
+                            struct stm32_spi_bus * stm32_spi,
+                            const char * spi_bus_name);
+
+#endif // STM32_SPI_H_INCLUDED

+ 4 - 10
bsp/stm32f107/drivers/stm32f10x_it.c

@@ -5,7 +5,7 @@
   * @version V3.5.0
   * @date    08-April-2011
   * @brief   Main Interrupt Service Routines.
-  *          This file provides template for all exceptions handler and 
+  *          This file provides template for all exceptions handler and
   *          peripherals interrupt service routine.
   ******************************************************************************
   * @attention
@@ -19,7 +19,7 @@
   *
   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
   ******************************************************************************
-  */ 
+  */
 
 /* Includes ------------------------------------------------------------------*/
 #include "stm32f10x_it.h"
@@ -107,12 +107,6 @@ void DebugMon_Handler(void)
 {
 }
 
-void SysTick_Handler(void)
-{
-    extern void rt_hw_timer_handler(void);
-    rt_hw_timer_handler();
-}
-
 /******************************************************************************/
 /*                 STM32F10x Peripherals Interrupt Handlers                   */
 /*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
@@ -132,7 +126,7 @@ void USART1_IRQHandler(void)
 #ifdef RT_USING_UART1
     extern struct rt_device uart1_device;
 	extern void rt_hw_serial_isr(struct rt_device *device);
-	
+
     /* enter interrupt */
     rt_interrupt_enter();
 
@@ -191,7 +185,7 @@ void USART3_IRQHandler(void)
 
 /**
   * @}
-  */ 
+  */
 
 
 /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

+ 1 - 0
bsp/stm32f107/drivers/usart.c

@@ -13,6 +13,7 @@
  * 2010-03-29     Bernard      remove interrupt Tx and DMA Rx mode
  */
 
+#include <board.h>
 #include "usart.h"
 #include <serial.h>
 #include <stm32f10x_dma.h>

+ 78 - 243
bsp/stm32f107/project.uvproj

@@ -1,7 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
 <Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
+
   <SchemaVersion>1.1</SchemaVersion>
+
   <Header>### uVision Project, (C) Keil Software</Header>
+
   <Targets>
     <Target>
       <TargetName>RT-Thread STM32</TargetName>
@@ -12,25 +15,25 @@
           <Device>STM32F107VC</Device>
           <Vendor>STMicroelectronics</Vendor>
           <Cpu>IRAM(0x20000000-0x2000FFFF) IROM(0x8000000-0x803FFFF) CLOCK(25000000) CPUTYPE("Cortex-M3")</Cpu>
-          <FlashUtilSpec />
+          <FlashUtilSpec></FlashUtilSpec>
           <StartupFile>"STARTUP\ST\STM32F10x.s" ("STM32 Startup Code")</StartupFile>
           <FlashDriverDll>UL2CM3(-O14 -S0 -C0 -N00("ARM Cortex-M3") -D00(1BA00477) -L00(4) -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_CL -FS08000000 -FL040000)</FlashDriverDll>
           <DeviceId>4889</DeviceId>
           <RegisterFile>stm32f10x_lib.h</RegisterFile>
-          <MemoryEnv />
-          <Cmp />
-          <Asm />
-          <Linker />
-          <OHString />
-          <InfinionOptionDll />
-          <SLE66CMisc />
-          <SLE66AMisc />
-          <SLE66LinkerMisc />
+          <MemoryEnv></MemoryEnv>
+          <Cmp></Cmp>
+          <Asm></Asm>
+          <Linker></Linker>
+          <OHString></OHString>
+          <InfinionOptionDll></InfinionOptionDll>
+          <SLE66CMisc></SLE66CMisc>
+          <SLE66AMisc></SLE66AMisc>
+          <SLE66LinkerMisc></SLE66LinkerMisc>
           <SFDFile>SFD\ST\STM32F107x\STM32F107.sfr</SFDFile>
           <UseEnv>0</UseEnv>
-          <BinPath />
-          <IncludePath />
-          <LibPath />
+          <BinPath></BinPath>
+          <IncludePath></IncludePath>
+          <LibPath></LibPath>
           <RegisterFilePath>ST\STM32F10x\</RegisterFilePath>
           <DBRegisterFilePath>ST\STM32F10x\</DBRegisterFilePath>
           <TargetStatus>
@@ -54,16 +57,18 @@
           <BeforeCompile>
             <RunUserProg1>0</RunUserProg1>
             <RunUserProg2>0</RunUserProg2>
-            <UserProg1Name />
-            <UserProg2Name />
+            <UserProg1Name></UserProg1Name>
+            <UserProg2Name></UserProg2Name>
             <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
             <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+            <nStopU1X>0</nStopU1X>
+            <nStopU2X>0</nStopU2X>
           </BeforeCompile>
           <BeforeMake>
             <RunUserProg1>0</RunUserProg1>
             <RunUserProg2>0</RunUserProg2>
-            <UserProg1Name />
-            <UserProg2Name />
+            <UserProg1Name></UserProg1Name>
+            <UserProg2Name></UserProg2Name>
             <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
             <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
           </BeforeMake>
@@ -71,12 +76,12 @@
             <RunUserProg1>1</RunUserProg1>
             <RunUserProg2>0</RunUserProg2>
             <UserProg1Name>fromelf --bin !L --output rtthread.bin</UserProg1Name>
-            <UserProg2Name />
+            <UserProg2Name></UserProg2Name>
             <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
             <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
           </AfterMake>
           <SelectedForBatchBuild>0</SelectedForBatchBuild>
-          <SVCSIdString />
+          <SVCSIdString></SVCSIdString>
         </TargetCommonOption>
         <CommonProperty>
           <UseCPPCompiler>0</UseCPPCompiler>
@@ -90,16 +95,16 @@
           <AssembleAssemblyFile>0</AssembleAssemblyFile>
           <PublicsOnly>0</PublicsOnly>
           <StopOnExitCode>3</StopOnExitCode>
-          <CustomArgument />
-          <IncludeLibraryModules />
+          <CustomArgument></CustomArgument>
+          <IncludeLibraryModules></IncludeLibraryModules>
         </CommonProperty>
         <DllOption>
           <SimDllName>SARMCM3.DLL</SimDllName>
-          <SimDllArguments />
+          <SimDllArguments></SimDllArguments>
           <SimDlgDll>DARMSTM.DLL</SimDlgDll>
           <SimDlgDllArguments>-pSTM32F107VC</SimDlgDllArguments>
           <TargetDllName>SARMCM3.DLL</TargetDllName>
-          <TargetDllArguments />
+          <TargetDllArguments></TargetDllArguments>
           <TargetDlgDll>TARMSTM.DLL</TargetDlgDll>
           <TargetDlgDllArguments>-pSTM32F107VC</TargetDlgDllArguments>
         </DllOption>
@@ -131,22 +136,23 @@
             <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
             <RestoreFunctions>0</RestoreFunctions>
             <RestoreToolbox>1</RestoreToolbox>
+            <RestoreTracepoints>0</RestoreTracepoints>
           </Target>
           <RunDebugAfterBuild>0</RunDebugAfterBuild>
           <TargetSelection>7</TargetSelection>
           <SimDlls>
-            <CpuDll />
-            <CpuDllArguments />
-            <PeripheralDll />
-            <PeripheralDllArguments />
-            <InitializationFile />
+            <CpuDll></CpuDll>
+            <CpuDllArguments></CpuDllArguments>
+            <PeripheralDll></PeripheralDll>
+            <PeripheralDllArguments></PeripheralDllArguments>
+            <InitializationFile></InitializationFile>
           </SimDlls>
           <TargetDlls>
-            <CpuDll />
-            <CpuDllArguments />
-            <PeripheralDll />
-            <PeripheralDllArguments />
-            <InitializationFile />
+            <CpuDll></CpuDll>
+            <CpuDllArguments></CpuDllArguments>
+            <PeripheralDll></PeripheralDll>
+            <PeripheralDllArguments></PeripheralDllArguments>
+            <InitializationFile></InitializationFile>
             <Driver>Segger\JL2CM3.dll</Driver>
           </TargetDlls>
         </DebugOption>
@@ -160,8 +166,8 @@
             <DriverSelection>4099</DriverSelection>
           </Flash1>
           <Flash2>Segger\JL2CM3.dll</Flash2>
-          <Flash3 />
-          <Flash4 />
+          <Flash3>"" ()</Flash3>
+          <Flash4></Flash4>
         </Utilities>
         <TargetArmAds>
           <ArmAdsMisc>
@@ -193,7 +199,7 @@
             <RvctClst>0</RvctClst>
             <GenPPlst>0</GenPPlst>
             <AdsCpuType>"Cortex-M3"</AdsCpuType>
-            <RvctDeviceName />
+            <RvctDeviceName></RvctDeviceName>
             <mOS>0</mOS>
             <uocRom>0</uocRom>
             <uocRam>0</uocRam>
@@ -324,7 +330,7 @@
                 <Size>0x0</Size>
               </OCR_RVCT10>
             </OnChipMemories>
-            <RvctStartVector />
+            <RvctStartVector></RvctStartVector>
           </ArmAdsMisc>
           <Cads>
             <interw>1</interw>
@@ -339,11 +345,12 @@
             <Rwpi>0</Rwpi>
             <wLevel>0</wLevel>
             <uThumb>0</uThumb>
+            <uSurpInc>0</uSurpInc>
             <VariousControls>
-              <MiscControls />
+              <MiscControls></MiscControls>
               <Define>STM32F10X_CL, USE_STDPERIPH_DRIVER</Define>
-              <Undefine />
-              <IncludePath>.;..\..\components\CMSIS\Include;..\..\components\dfs;..\..\components\dfs\include;..\..\components\finsh;..\..\components\init;..\..\components\net\lwip\src;..\..\components\net\lwip\src\arch\include;..\..\components\net\lwip\src\include;..\..\components\net\lwip\src\include\ipv4;..\..\components\net\lwip\src\include\netif;..\..\include;..\..\libcpu\arm\common;..\..\libcpu\arm\cortex-m3;Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;Libraries\STM32F10x_StdPeriph_Driver\inc;applications;drivers</IncludePath>
+              <Undefine></Undefine>
+              <IncludePath>.;..\..\components\CMSIS\Include;..\..\components\dfs;..\..\components\dfs\include;..\..\components\drivers\include;..\..\components\finsh;..\..\components\init;..\..\components\net\lwip\src;..\..\components\net\lwip\src\arch\include;..\..\components\net\lwip\src\include;..\..\components\net\lwip\src\include\ipv4;..\..\components\net\lwip\src\include\netif;..\..\include;..\..\libcpu\arm\common;..\..\libcpu\arm\cortex-m3;Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;Libraries\STM32F10x_StdPeriph_Driver\inc;applications;drivers</IncludePath>
             </VariousControls>
           </Cads>
           <Aads>
@@ -354,11 +361,12 @@
             <SplitLS>0</SplitLS>
             <SwStkChk>0</SwStkChk>
             <NoWarn>0</NoWarn>
+            <uSurpInc>0</uSurpInc>
             <VariousControls>
-              <MiscControls />
-              <Define />
-              <Undefine />
-              <IncludePath />
+              <MiscControls></MiscControls>
+              <Define></Define>
+              <Undefine></Undefine>
+              <IncludePath></IncludePath>
             </VariousControls>
           </Aads>
           <LDads>
@@ -370,12 +378,12 @@
             <useFile>0</useFile>
             <TextAddressRange>0x08000000</TextAddressRange>
             <DataAddressRange>0x20000000</DataAddressRange>
-            <ScatterFile />
-            <IncludeLibs />
-            <IncludeLibsPath />
+            <ScatterFile></ScatterFile>
+            <IncludeLibs></IncludeLibs>
+            <IncludeLibsPath></IncludeLibsPath>
             <Misc> --keep __fsym_* --keep __vsym_* </Misc>
-            <LinkerInputFile />
-            <DisabledWarnings />
+            <LinkerInputFile></LinkerInputFile>
+            <DisabledWarnings></DisabledWarnings>
           </LDads>
         </TargetArmAds>
       </TargetOption>
@@ -388,8 +396,6 @@
               <FileType>1</FileType>
               <FilePath>applications\application.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>startup.c</FileName>
               <FileType>1</FileType>
@@ -405,43 +411,36 @@
               <FileType>1</FileType>
               <FilePath>drivers\board.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>msd.c</FileName>
               <FileType>1</FileType>
               <FilePath>drivers\msd.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>platform.c</FileName>
               <FileType>1</FileType>
               <FilePath>drivers\platform.c</FilePath>
             </File>
-          </Files>
-          <Files>
+            <File>
+              <FileName>rt_stm32f10x_spi.c</FileName>
+              <FileType>1</FileType>
+              <FilePath>drivers\rt_stm32f10x_spi.c</FilePath>
+            </File>
             <File>
               <FileName>serial.c</FileName>
               <FileType>1</FileType>
               <FilePath>drivers\serial.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32_eth.c</FileName>
               <FileType>1</FileType>
               <FilePath>drivers\stm32_eth.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_it.c</FileName>
               <FileType>1</FileType>
               <FilePath>drivers\stm32f10x_it.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>usart.c</FileName>
               <FileType>1</FileType>
@@ -457,169 +456,121 @@
               <FileType>1</FileType>
               <FilePath>Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_crc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_crc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_rcc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_wwdg.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_pwr.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_exti.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_bkp.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_i2c.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_adc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_dac.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dac.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_rtc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_fsmc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_fsmc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_tim.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_iwdg.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_spi.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_flash.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_sdio.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_sdio.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_gpio.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_usart.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_dbgmcu.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dbgmcu.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_dma.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_can.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_can.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stm32f10x_cec.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_cec.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>misc.c</FileName>
               <FileType>1</FileType>
               <FilePath>Libraries\STM32F10x_StdPeriph_Driver\src\misc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>startup_stm32f10x_cl.s</FileName>
               <FileType>2</FileType>
@@ -635,78 +586,56 @@
               <FileType>1</FileType>
               <FilePath>..\..\src\clock.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>device.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\device.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>idle.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\idle.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ipc.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\ipc.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>irq.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\irq.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>kservice.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\kservice.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>mem.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\mem.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>mempool.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\mempool.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>object.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\object.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>scheduler.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\scheduler.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>thread.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\src\thread.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>timer.c</FileName>
               <FileType>1</FileType>
@@ -722,29 +651,21 @@
               <FileType>1</FileType>
               <FilePath>..\..\libcpu\arm\cortex-m3\cpuport.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>context_rvds.S</FileName>
               <FileType>2</FileType>
               <FilePath>..\..\libcpu\arm\cortex-m3\context_rvds.S</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>backtrace.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\libcpu\arm\common\backtrace.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>div0.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\libcpu\arm\common\div0.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>showmem.c</FileName>
               <FileType>1</FileType>
@@ -760,36 +681,26 @@
               <FileType>1</FileType>
               <FilePath>..\..\components\dfs\src\dfs.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dfs_fs.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\dfs\src\dfs_fs.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dfs_file.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\dfs\src\dfs_file.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dfs_posix.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\dfs\src\dfs_posix.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dfs_elm.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\dfs\filesystems\elmfat\dfs_elm.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ff.c</FileName>
               <FileType>1</FileType>
@@ -797,6 +708,21 @@
             </File>
           </Files>
         </Group>
+        <Group>
+          <GroupName>DeviceDrivers</GroupName>
+          <Files>
+            <File>
+              <FileName>spi_core.c</FileName>
+              <FileType>1</FileType>
+              <FilePath>..\..\components\drivers\spi\spi_core.c</FilePath>
+            </File>
+            <File>
+              <FileName>spi_dev.c</FileName>
+              <FileType>1</FileType>
+              <FilePath>..\..\components\drivers\spi\spi_dev.c</FilePath>
+            </File>
+          </Files>
+        </Group>
         <Group>
           <GroupName>finsh</GroupName>
           <Files>
@@ -805,85 +731,61 @@
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\cmd.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_compiler.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_compiler.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_error.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_error.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_heap.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_heap.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_init.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_init.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_node.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_node.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_ops.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_ops.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_parser.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_parser.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_token.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_token.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_var.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_var.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>finsh_vm.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\finsh_vm.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>shell.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\finsh\shell.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>symbol.c</FileName>
               <FileType>1</FileType>
@@ -909,239 +811,171 @@
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\api_lib.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>api_msg.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\api_msg.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>err.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\err.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>netbuf.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\netbuf.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>netdb.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\netdb.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>netifapi.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\netifapi.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>sockets.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\sockets.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>tcpip.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\api\tcpip.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>sys_arch.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\arch\sys_arch.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>def.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\def.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dhcp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\dhcp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>dns.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\dns.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>init.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\init.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>memp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\memp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>netif.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\netif.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>pbuf.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\pbuf.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>raw.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\raw.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>stats.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\stats.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>sys.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\sys.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>tcp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\tcp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>tcp_in.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\tcp_in.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>tcp_out.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\tcp_out.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>timers.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\timers.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>udp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\udp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>autoip.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\autoip.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>icmp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\icmp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>igmp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\igmp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>inet.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\inet.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>inet_chksum.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\inet_chksum.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ip.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\ip.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ip_addr.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\ip_addr.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ip_frag.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\core\ipv4\ip_frag.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>etharp.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\netif\etharp.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>ethernetif.c</FileName>
               <FileType>1</FileType>
               <FilePath>..\..\components\net\lwip\src\netif\ethernetif.c</FilePath>
             </File>
-          </Files>
-          <Files>
             <File>
               <FileName>slipif.c</FileName>
               <FileType>1</FileType>
@@ -1152,4 +986,5 @@
       </Groups>
     </Target>
   </Targets>
+
 </Project>

+ 1 - 1
bsp/stm32f107/readme.txt

@@ -2,4 +2,4 @@
 # GoldBull debug board
    - 10M/100M ethernet
    - SPI SD Card
-   - LCD
+     SPI: SPI1 (PA5,PA6,PA7). CS:PA4

+ 1 - 1
bsp/stm32f107/rtconfig.h

@@ -58,7 +58,7 @@
 /* SECTION: Device System */
 /* Using Device System */
 #define RT_USING_DEVICE
-#define RT_USING_UART1
+#define RT_USING_SPI
 
 /* SECTION: Console options */
 #define RT_USING_CONSOLE