AnsweredAssumed Answered

A question about FATFS_LinkDriver(&USER_Driver, USER_Path); ?

Question asked by H.Rick on Feb 2, 2016
Guys,

I tried already for a few days to initialized SDcard with SPI2 using STM32CubeMX generated code, but no luck...

Can anyone give me a hint ?

Thanks,

Here's the code I tried to comprehend

main.c
/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  *
  * COPYRIGHT(c) 2016 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "fatfs.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
 
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
FATFS mynewdiskFatFs; /* File system object for User logical drive */
FIL MyFile; /* File object */
char mynewdiskPath[4]; /* User logical drive path */
uint32_t wbytes; /* File write counts */
uint8_t wtext[] = "text to write logical disk"; /* File write buffer */
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
 
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
 
/* USER CODE END PFP */
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
void reading_file()
{
    UINT bw,size;
    FRESULT fr;    /* FatFs return code */
    char line[82]; /* Line buffer */
   
    /*TESTING READING FILE BEGIN*/
    //FATFS_LinkDriver(&USER_Driver, mynewdiskPath);
if(FATFS_LinkDriver(&USER_Driver, mynewdiskPath) == 0)
    {
        f_mount(&mynewdiskFatFs, (TCHAR const*)mynewdiskPath, 0);
        /* Open a text file */
        //fr = f_open(&Fil, "hello.mp3", FA_READ);
        fr = f_open(&MyFile, "test.txt", FA_READ);
 
 
         
        /* Read all lines and display it */
        while (f_gets(line, sizeof line, &MyFile))
            //sprintf(line,100);
              
             HAL_UART_Transmit(&huart1, "READING test.txt! \r\n", 32, 1); // Debug
        /* Close the file */
             
 
        f_close(&MyFile);
        /*TESTING READING FILE END*/
    }
    else
    {
        HAL_UART_Transmit(&huart1, "LinkDriver Fail! \r\n", 16, 1); // Debug
    }      
         
}
 
int main(void)
{
 
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration----------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI2_Init();
  MX_USART1_UART_Init();
  MX_FATFS_Init();
 
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
                /*
                    if(FATFS_LinkDriver(&USER_Driver, mynewdiskPath) == 0)
                    {
                        HAL_UART_Transmit(&huart1, "LinkDriver OK! \r\n", 32, 1); // Debug
                            if(f_mount(&mynewdiskFatFs, (TCHAR const*)mynewdiskPath, 0) == FR_OK)
                            {
                                HAL_UART_Transmit(&huart1, "FMOUNT OK! \r\n", 10, 1); // Debug
 
                                if(f_open(&MyFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
                                    {
                                        HAL_UART_Transmit(&huart1, "FOPEN OK! \r\n", 32, 1); // Debug
 
                                        if(f_write(&MyFile, wtext, sizeof(wtext), (void *)&wbytes) == FR_OK);
                                        {
                                            HAL_UART_Transmit(&huart1, "Finished writing file STM32.TXT! \r\n", 32, 1); // Debug
                                            f_close(&MyFile);
                                        }
                                }
                            }
                    }
                    FATFS_UnLinkDriver(mynewdiskPath);
                    */
                      reading_file();
                    }
  /* USER CODE BEGIN 3 */
 
  }
  /* USER CODE END 3 */
 
 
 
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
 
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);
 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
 
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
  __HAL_RCC_PLLI2S_ENABLE();
 
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
#ifdef USE_FULL_ASSERT
 
/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
 
}
 
#endif
 
/**
  * @}
  */
 
/**
  * @}
*/
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

fatfs.c
/**
  ******************************************************************************
  * @file   fatfs.c
  * @brief  Code for fatfs applications
  ******************************************************************************
  *
  * COPYRIGHT(c) 2016 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
 
#include "fatfs.h"
 
uint8_t retUSER;    /* Return value for USER */
char USER_Path[4];  /* USER logical drive path */
 
/* USER CODE BEGIN Variables */
 
/* USER CODE END Variables */   
 
void MX_FATFS_Init(void)
{
  /*## FatFS: Link the USER driver ###########################*/
  retUSER = FATFS_LinkDriver(&USER_Driver, USER_Path);
 
  /* USER CODE BEGIN Init */
  /* additional user code for init */    
  /* USER CODE END Init */
}
 
/* USER CODE BEGIN Application */
      
/* USER CODE END Application */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
ff_gen_drv.c
/**
  ******************************************************************************
  * @file    ff_gen_drv.c
  * @author  MCD Application Team
  * @version V1.2.1
  * @date    20-November-2014
  * @brief   FatFs generic low level driver.
  ******************************************************************************
  * @attention
  *
  * <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */
 
/* Includes ------------------------------------------------------------------*/
#include "ff_gen_drv.h"
 
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
Disk_drvTypeDef disk = {{0},{0},0};
 
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
 
/**
  * @brief  Links a compatible diskio driver and increments the number of active
  *         linked drivers.         
  * @note   The number of linked drivers (volumes) is up to 10 due to FatFs limits
  * @param  drv: pointer to the disk IO Driver structure
  * @param  path: pointer to the logical drive path
  * @retval Returns 0 in case of success, otherwise 1.
  */
uint8_t FATFS_LinkDriver(Diskio_drvTypeDef *drv, char *path)
{
  uint8_t ret = 1;
  uint8_t DiskNum = 0;
   
  if(disk.nbr <= _VOLUMES)
  {
    disk.is_initialized[disk.nbr] = 0;
    disk.drv[disk.nbr] = drv; 
    DiskNum = disk.nbr++;
    path[0] = DiskNum + '0';
    path[1] = ':';
    path[2] = '/';
    path[3] = 0;
    ret = 0;
  }
   
  return ret;
}
 
/**
  * @brief  Unlinks a diskio driver and decrements the number of active linked
  *         drivers.
  * @param  path: pointer to the logical drive path 
  * @retval Returns 0 in case of success, otherwise 1.
  */
uint8_t FATFS_UnLinkDriver(char *path)
{
  uint8_t DiskNum = 0;
  uint8_t ret = 1;
   
  if(disk.nbr >= 1)
  {   
    DiskNum = path[0] - '0';
    if(DiskNum <= disk.nbr)
    {
      disk.drv[disk.nbr--] = 0;
      ret = 0;
    }
  }
   
  return ret;
}
 
/**
  * @brief  Gets number of linked drivers to the FatFs module.
  * @param  None
  * @retval Number of attached drivers.
  */
uint8_t FATFS_GetAttachedDriversNbr(void)
{
  return disk.nbr;
}
  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
user_diskio.c
/**
 ******************************************************************************
  * @file    user_diskio.c
  * @brief   This file includes a diskio driver skeleton to be completed by the user.
  ******************************************************************************
  *
  * COPYRIGHT(c) 2016 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
 
/* USER CODE BEGIN 0 */
 
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"
#include "usart.h"
#include "spi.h"
 
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define CS_LOW()        { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10 , 0 ); }         /* CS=low */
#define CS_HIGH()     { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10 , 1 ); }           /* CS=high */
#define SOCKINS     {HAL_GPIO_ReadPin(GPIOB, 11);}  /* Card detected.   yes:true, no:false, default:true */
#define SOCKWP      {HAL_GPIO_ReadPin(GPIOB, 12);}      /* Write protected. yes:true, no:false, default:false */
#define FCLK_SLOW() MX_SPI2_Init_Low();
#define FCLK_FAST() MX_SPI2_Init();
 
/* Definitions for MMC/SDC command */
#define CMD0    (0)         /* GO_IDLE_STATE */
#define CMD1    (1)         /* SEND_OP_COND (MMC) */
#define ACMD41  (0x80+41)   /* SEND_OP_COND (SDC) */
#define CMD8    (8)         /* SEND_IF_COND */
#define CMD9    (9)         /* SEND_CSD */
#define CMD10   (10)        /* SEND_CID */
#define CMD12   (12)        /* STOP_TRANSMISSION */
#define ACMD13  (0x80+13)   /* SD_STATUS (SDC) */
#define CMD16   (16)        /* SET_BLOCKLEN */
#define CMD17   (17)        /* READ_SINGLE_BLOCK */
#define CMD18   (18)        /* READ_MULTIPLE_BLOCK */
#define CMD23   (23)        /* SET_BLOCK_COUNT (MMC) */
#define ACMD23  (0x80+23)   /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24   (24)        /* WRITE_BLOCK */
#define CMD25   (25)        /* WRITE_MULTIPLE_BLOCK */
#define CMD32   (32)        /* ERASE_ER_BLK_START */
#define CMD33   (33)        /* ERASE_ER_BLK_END */
#define CMD38   (38)        /* ERASE */
#define CMD55   (55)        /* APP_CMD */
#define CMD58   (58)        /* READ_OCR */
#define CTRL_POWER          5   /* Get/Set power status */
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC      0x01        /* MMC ver 3 */
#define CT_SD1      0x02        /* SD ver 1 */
#define CT_SD2      0x04        /* SD ver 2 */
#define CT_SDC      (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK    0x08        /* Block addressing */
/* Private variables ---------------------------------------------------------*/
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;
static volatile BYTE Timer1, Timer2;    /* 100Hz decrement timer */
static BYTE CardType;           /* Card type flags */
 
/* Private function prototypes -----------------------------------------------*/
 
DSTATUS USER_initialize (void);
DSTATUS USER_status (void);
DRESULT USER_read (BYTE*, DWORD, UINT);
#if _USE_WRITE == 1
  DRESULT USER_write (/*const*/ BYTE*, DWORD, UINT);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
  DRESULT USER_ioctl (BYTE, void*);
#endif /* _USE_IOCTL == 1 */
 
Diskio_drvTypeDef  USER_Driver =
{
  USER_initialize,
  USER_status,
  USER_read,
#if  _USE_WRITE
  USER_write,
#endif  /* _USE_WRITE == 1 */ 
#if  _USE_IOCTL == 1
  USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};
 
/* Private functions ---------------------------------------------------------*/
//written by Riko Ho Start here
static
void power_on (void)
{
 
    FCLK_SLOW();
}
 
static
void power_off (void)
{
    FCLK_FAST();
 
}
 
 
/* Exchange a byte */
static
BYTE xchg_spi (     /* Returns received data */
    BYTE dat        /* Data to be sent */
)
{
    uint8_t result = 0;
    while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
    //HAL_SPI_Receive(&hspi2,&dat,1,100);
    HAL_SPI_TransmitReceive(&hspi2,&dat,&result,1,1000);
    return result;
}
 
/* Send a data block fast */
 
static
void xmit_spi_multi (
      BYTE *p,  /* Data block to be sent */
    UINT cnt       
)
 
//test only
//void xmit_spi_multi (
//    BYTE *p,  /* Data block to be sent */
//  UINT cnt       
//)
{
     
    while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
    HAL_SPI_Transmit(&hspi2,p,cnt,100);
}
 
/* Receive a data block fast */
static
void rcvr_spi_multi (
    BYTE *p,    /* Data buffer */
    UINT cnt    /* Size of data block (must be multiple of 2) */
)
{
    while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
    HAL_SPI_Receive(&hspi2,p,cnt,100);
}
 
/*-----------------------------------------------------------------------*/
/* Wait for card ready                                                   */
/*-----------------------------------------------------------------------*/
 
static
int wait_ready (    /* 1:Ready, 0:Timeout */
    UINT wt         /* Timeout [ms] */
)
{
    BYTE d;
 
 
    Timer2 = wt / 10;
    do
        d = xchg_spi(0xFF);
    while (d != 0xFF && Timer2);
 
    return (d == 0xFF) ? 1 : 0;
}
 
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus                                 */
/*-----------------------------------------------------------------------*/
 
static
void deselect (void)
{
    CS_HIGH();
    xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
}
 
 
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready                                    */
/*-----------------------------------------------------------------------*/
 
static
int select (void)   /* 1:Successful, 0:Timeout */
{
    CS_LOW();
    xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
 
    if (wait_ready(500)) return 1;  /* OK */
    deselect();
    return 0;   /* Timeout */
}
 
/*-----------------------------------------------------------------------*/
/* Receive a data packet from MMC                                        */
/*-----------------------------------------------------------------------*/
 
static
int rcvr_datablock (
    BYTE *buff,         /* Data buffer to store received data */
    UINT btr            /* Byte count (must be multiple of 4) */
)
{
    BYTE token;
 
 
    Timer1 = 20;
    do {                            /* Wait for data packet in timeout of 200ms */
        token = xchg_spi(0xFF);
    } while ((token == 0xFF) && Timer1);
    if (token != 0xFE) return 0;    /* If not valid data token, retutn with error */
 
    rcvr_spi_multi(buff, btr);      /* Receive the data block into buffer */
    xchg_spi(0xFF);                 /* Discard CRC */
    xchg_spi(0xFF);
 
    return 1;                       /* Return with success */
}
 
/*-----------------------------------------------------------------------*/
/* Send a data packet to MMC                                             */
/*-----------------------------------------------------------------------*/
 
//#if   _USE_WRITE
//static
int xmit_datablock (
       BYTE *buff,  /* 512 byte data block to be transmitted */
    BYTE token          /* Data/Stop token */
)
{
    BYTE resp;
 
 
    if (!wait_ready(500)) return 0;
 
    xchg_spi(token);                    /* Xmit data token */
    if (token != 0xFD) {    /* Is data token */
        xmit_spi_multi(buff, 512);      /* Xmit the data block to the MMC */
        xchg_spi(0xFF);                 /* CRC (Dummy) */
        xchg_spi(0xFF);
        resp = xchg_spi(0xFF);          /* Reveive data response */
        if ((resp & 0x1F) != 0x05)      /* If not accepted, return with error */
            return 0;
    }
 
    return 1;
}
//#endif
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC                                          */
/*-----------------------------------------------------------------------*/
 
static
BYTE send_cmd (     /* Returns R1 resp (bit7==1:Send failed) */
    BYTE cmd,       /* Command index */
    DWORD arg       /* Argument */
)
{
    BYTE n, res;
 
 
    if (cmd & 0x80) {   /* ACMD<n> is the command sequense of CMD55-CMD<n> */
        cmd &= 0x7F;
        res = send_cmd(CMD55, 0);
        if (res > 1) return res;
    }
 
    /* Select the card and wait for ready except to stop multiple block read */
    if (cmd != CMD12) {
        deselect();
        if (!select()) return 0xFF;
    }
 
    /* Send command packet */
    xchg_spi(0x40 | cmd);               /* Start + Command index */
    xchg_spi((BYTE)(arg >> 24));        /* Argument[31..24] */
    xchg_spi((BYTE)(arg >> 16));        /* Argument[23..16] */
    xchg_spi((BYTE)(arg >> 8));         /* Argument[15..8] */
    xchg_spi((BYTE)arg);                /* Argument[7..0] */
    n = 0x01;                           /* Dummy CRC + Stop */
    if (cmd == CMD0) n = 0x95;          /* Valid CRC for CMD0(0) + Stop */
    if (cmd == CMD8) n = 0x87;          /* Valid CRC for CMD8(0x1AA) Stop */
    xchg_spi(n);
 
    /* Receive command response */
    if (cmd == CMD12) xchg_spi(0xFF);       /* Skip a stuff byte when stop reading */
    n = 10;                             /* Wait for a valid response in timeout of 10 attempts */
    do
        res = xchg_spi(0xFF);
    while ((res & 0x80) && --n);
    return res;         /* Return with the response value */
}
 
//written by Riko Ho End here
/**
  * @brief  Initializes a Drive
  * @param  None
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_initialize(void)
{
  Stat = STA_NOINIT;
    Stat &= ~STA_NOINIT;
  //================
   
    /* USER CODE HERE */
    BYTE pdrv;
  HAL_UART_Transmit(&huart1, "USER INITIALIZE START! \r\n", 100, 1000); //debug message
     
     DSTATUS Stat = RES_OK;
     
    BYTE n, cmd, ty, ocr[4];
  //; 
 
    if (pdrv) return STA_NOINIT;        /* Supports only single drive */
    power_off();                        /* Turn off the socket power to reset the card */
     
    if (Stat & STA_NODISK) return Stat; /* No card in the socket */;
    power_on();                         /* Turn on the socket power */
     
    FCLK_SLOW();
    for (n = 10; n; n--) xchg_spi(0xFF);    /* 80 dummy clocks */
 
    ty = 0;
    if (send_cmd(CMD0, 0) == 1) {           /* Enter Idle state */
        Timer1 = 100;                       /* Initialization timeout of 1000 msec */
        if (send_cmd(CMD8, 0x1AA) == 1) {   /* SDv2? */
            for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);        /* Get trailing return value of R7 resp */
            if (ocr[2] == 0x01 && ocr[3] == 0xAA) {             /* The card can work at vdd range of 2.7-3.6V */
                while (Timer1 && send_cmd(ACMD41, 1UL << 30));  /* Wait for leaving idle state (ACMD41 with HCS bit) */
                if (Timer1 && send_cmd(CMD58, 0) == 0) {        /* Check CCS bit in the OCR */
                    for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
                    ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;  /* SDv2 */
                }
            }
        } else {                            /* SDv1 or MMCv3 */
            if (send_cmd(ACMD41, 0) <= 1)   {
                ty = CT_SD1; cmd = ACMD41;  /* SDv1 */
            } else {
                ty = CT_MMC; cmd = CMD1;    /* MMCv3 */
            }
            while (Timer1 && send_cmd(cmd, 0));         /* Wait for leaving idle state */
            if (!Timer1 || send_cmd(CMD16, 512) != 0)   /* Set R/W block length to 512 */
                ty = 0;
        }
    }
    CardType = ty;
    deselect();
 
    if (ty) {           /* Initialization succeded */
        Stat &= ~STA_NOINIT;        /* Clear STA_NOINIT */
        FCLK_FAST();
 
         HAL_UART_Transmit(&huart1, "USER INITIALIZE SUCCEDED! \r\n", 100, 1000);
    } else {            /* Initialization failed */
        power_off();
         HAL_UART_Transmit(&huart1, "USER INITIALIZE FAILED! \r\n", 100, 1000);
    }
      HAL_UART_Transmit(&huart1, "USER INITIALIZE FINISHED! \n \n", 100, 1000);
 
   
    //================
   
  return Stat;
}
 
/**
  * @brief  Gets Disk Status
  * @param  None
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status(void)
{
  Stat = STA_NOINIT;
   
  Stat &= ~STA_NOINIT;
 
  return Stat;
}
 
/**
  * @brief  Reads Sector(s)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_read(BYTE *buff, DWORD sector, UINT count)
{
  /* USER CODE HERE */
    DRESULT res;
    DSTATUS stat;
  //;
  //res = disk.drv[pdrv]->disk_read(buff, sector, count);
    BYTE pdrv;
    if (pdrv || !count) return RES_PARERR;
    if (stat & STA_NOINIT) return RES_NOTRDY;
 
    if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
 
    if (count == 1) {   /* Single block read */
        if ((send_cmd(CMD17, sector) == 0)  /* READ_SINGLE_BLOCK */
            && rcvr_datablock(buff, 512))
            count = 0;
    }
    else {              /* Multiple block read */
        if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
            do {
                if (!rcvr_datablock(buff, 512)) break;
                buff += 512;
            } while (--count);
            send_cmd(CMD12, 0);             /* STOP_TRANSMISSION */
        }
    }
    deselect();
   
  return RES_OK;
}
 
/**
  * @brief  Writes Sector(s)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT USER_write(/*const*/ BYTE *buff, DWORD sector, UINT count)
{
  /* USER CODE HERE */
  BYTE pdrv;
if (pdrv || !count) return RES_PARERR;
    if (Stat & STA_NOINIT) return RES_NOTRDY;
    if (Stat & STA_PROTECT) return RES_WRPRT;
 
    if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
 
    if (count == 1) {   /* Single block write */
        if ((send_cmd(CMD24, sector) == 0)  /* WRITE_BLOCK */
            && xmit_datablock(buff, 0xFE))
            count = 0;
    }
    else {              /* Multiple block write */
        if (CardType & CT_SDC) send_cmd(ACMD23, count);
        if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
            do {
                if (!xmit_datablock(buff, 0xFC)) break;
                buff += 512;
            } while (--count);
            if (!xmit_datablock(0, 0xFD))   /* STOP_TRAN token */
                count = 1;
        }
    }
    deselect();
  return RES_OK;
}
#endif /* _USE_WRITE == 1 */
 
/**
  * @brief  I/O control operation
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl(BYTE cmd, void *buff)
{
  DRESULT res = RES_ERROR;
   
  /* USER CODE HERE */
 
  return res;
}
#endif /* _USE_IOCTL == 1 */
 
/* USER CODE END 0 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
ff_gen_drv.h
/**
  ******************************************************************************
  * @file    ff_gen_drv.h
  * @author  MCD Application Team
  * @version V1.2.1
  * @date    20-November-2014
  * @brief   Header for ff_gen_drv.c module.
  ******************************************************************************
  * @attention
  *
  * <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */
 
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FF_GEN_DRV_H
#define __FF_GEN_DRV_H
 
#ifdef __cplusplus
 extern "C" {
#endif
 
/* Includes ------------------------------------------------------------------*/
#include "diskio.h"
#include "ff.h"
 
/* Exported types ------------------------------------------------------------*/
 
/**
  * @brief  Disk IO Driver structure definition 
  */
typedef struct
{
  DSTATUS (*disk_initialize) (void);                     /*!< Initialize Disk Drive                     */
  DSTATUS (*disk_status)     (void);                     /*!< Get Disk Status                           */
  DRESULT (*disk_read)       (BYTE*, DWORD, UINT);       /*!< Read Sector(s)                            */
#if _USE_WRITE == 1
  //DRESULT (*disk_write)      (const BYTE*, DWORD, UINT); /*!< Write Sector(s) when _USE_WRITE = 0       */
    DRESULT (*disk_write)      (BYTE*, DWORD, UINT); /*!< Write Sector(s) when _USE_WRITE = 0       */
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1 
  DRESULT (*disk_ioctl)      (BYTE, void*);              /*!< I/O control operation when _USE_IOCTL = 1 */
#endif /* _USE_IOCTL == 1 */
 
}Diskio_drvTypeDef;
 
/**
  * @brief  Global Disk IO Drivers structure definition 
  */
typedef struct
{
  uint8_t                 is_initialized[_VOLUMES];
  Diskio_drvTypeDef       *drv[_VOLUMES];
  __IO uint8_t            nbr;
 
}Disk_drvTypeDef;
 
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
uint8_t FATFS_LinkDriver(Diskio_drvTypeDef *drv, char *path);
uint8_t FATFS_UnLinkDriver(char *path);
uint8_t FATFS_GetAttachedDriversNbr(void);
 
#ifdef __cplusplus
}
#endif
 
#endif /* __FF_GEN_DRV_H */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Anything I missed here ??
Any helps ? thanks

Outcomes