2017-10-31 3 views
0

SPI를 사용하여 STM32L152-DISCOVERY 보드 (STM32L152RCT6 ARM Cortex-M3)로 microSD 카드를 인터페이스하려고합니다. 최종 목표는 FatFs (http://elm-chan.org/fsw/ff/00index_e.html)을 사용하여 Decktop PC에서도 읽을 수있는 SD 카드에 센서 데이터를 저장하는 것입니다. Chan의 웹 사이트에는 초기화 프로세스 (http://elm-chan.org/docs/mmc/im/sdinit.png)를 설명하는 매우 유용한 순서도가 있습니다.SPI 모드에서 microSD 카드 초기화. ACMD41은 항상 0x01을 반환합니다.

불행히도 SDCard가 초기화되지 못하게하는 코드에 문제가 있습니다. 특히 ACMD41 (CMD55 + CMD41) 명령을 보내면 SD 카드는 항상 0x01을 반환합니다.

스택 오버플로 및 특히 SDHC microSD card and SPI initialization에서 일부 게시물을 따라 여러 번 코드를 수정했지만 문제가 여전히 발생합니다. 다음

내 시스템의 HW 및 SW 설정은 다음과 같습니다

하드웨어 설치 마이크로의 SD 카드는 SD 카드 어댑터가에 인터페이스 UHS-I, 용량 16기가바이트

  • 연결되어있다

    • 검색 보드의 SPI2 포트
    • MISO, MOSI, CLK 핀의 경우 풀업 저항을 활성화했습니다. MCU 데이터 시트에 따르면, 내부 풀업 저항은 약 45 Kohm이어야합니다.
    • microSD 카드의 전원은 arduino 보드에서 5V 핀을 사용하여 제공됩니다. (미친 소리가 들리 겠지만 다른 전원 공급 장치가 지금은 없습니다. 5V 핀을 읽었습니다. arduino의 GND는 5mA, 최대 출력은 400mA입니다.
    • arduino GND, 디스커버리 GND 및 SDcard 어댑터 GND가 모두 연결되어 있습니다.

    소프트웨어 설치 - SPI 초기화 SPI의 주파수는 처음에 125 kHz에서 설정

    는 (- 400 kHz에서 나는 그 범위 100 kHz에서 여야 읽은).

    /* SPI2 init function */ 
    void MX_SPI2_Init(void) 
    { 
    
        hspi2.Instance = SPI2; 
        hspi2.Init.Mode = SPI_MODE_MASTER; 
        hspi2.Init.Direction = SPI_DIRECTION_2LINES; 
        hspi2.Init.DataSize = SPI_DATASIZE_8BIT; 
        hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; 
        hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; 
        hspi2.Init.NSS = SPI_NSS_SOFT; 
        hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; 
        hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; 
        hspi2.Init.TIMode = SPI_TIMODE_DISABLE; 
        hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; 
        hspi2.Init.CRCPolynomial = 10; 
        if (HAL_SPI_Init(&hspi2) != HAL_OK) 
        { 
        _Error_Handler(__FILE__, __LINE__); 
        } 
    
    } 
    
    void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) 
    { 
    
        GPIO_InitTypeDef GPIO_InitStruct; 
        if(spiHandle->Instance==SPI2) 
        { 
        /* SPI2 clock enable */ 
        __HAL_RCC_SPI2_CLK_ENABLE(); 
    
        /**SPI2 GPIO Configuration  
        PB13  ------> SPI2_SCK 
        PB14  ------> SPI2_MISO 
        PB15  ------> SPI2_MOSI 
        */ 
        GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; 
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
        GPIO_InitStruct.Pull = GPIO_PULLUP; 
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; 
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 
        } 
    } 
    

    소프트웨어 설치 - SDCARD 초기화

    #include <string.h> 
    #include "ff_gen_drv.h" 
    
    #define CS_HIGH() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET); 
    #define CS_LOW() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET); 
    
    #define DEFAULT_TIMEOUT 10 
    
    uint8_t dummy_clocks[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 
    
    /* Definitions for MMC/SDC command */ 
    #define CMD0  (0)  /* GO_IDLE_STATE */ 
    #define CMD1  (1)  /* SEND_OP_COND (MMC) */ 
    #define ACMD41 (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 (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 (23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ 
    #define CMD24  (24) /* WRITE_BLOCK */ 
    #define CMD25  (25) /* WRITE_MULTIPLE_BLOCK */ 
    #define CMD55  (55) /* APP_CMD */ 
    #define CMD58  (58) /* READ_OCR */ 
    
    static volatile DSTATUS Stat = STA_NOINIT; 
    extern SPI_HandleTypeDef hspi2; 
    
    DSTATUS USER_initialize (BYTE pdrv); 
    DSTATUS USER_status (BYTE pdrv); 
    DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count); 
    #if _USE_WRITE == 1 
    DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count); 
    #endif /* _USE_WRITE == 1 */ 
    #if _USE_IOCTL == 1 
    DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff); 
    #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 */ 
    }; 
    
    void spi_init(void); 
    uint8_t send_cmd(BYTE cmd, DWORD arg); 
    
    DSTATUS USER_initialize (BYTE pdrv) 
    { 
        /* USER CODE BEGIN INIT */ 
        Stat = STA_NOINIT; 
    
        enum initialization_state 
        { 
        SD_POWER_CYCLE = 0, 
        SD_SEND_CMD0, 
        SD_WAIT_CMD0_ANSWER, 
        SD_SEND_CMD8, 
        SD_SEND_CMD55, 
        SD_SEND_ACMD41, 
        SD_SEND_CMD1, 
        SD_SEND_CMD58, 
        SD_SEND_CMD16, 
        SD_SUCCESS, 
        SD_ERROR, 
        } init_phase; 
    
        uint8_t response = 0x00; 
        DWORD arg = 0; 
        init_phase = SD_POWER_CYCLE; 
    
        spi_init(); 
    
        while(init_phase < SD_SUCCESS) 
        { 
        switch(init_phase) 
        { 
         case SD_POWER_CYCLE: 
         // Wait 1 ms 
         HAL_Delay(1); 
         HAL_SPI_Transmit(&hspi2, dummy_clocks, sizeof(dummy_clocks), 10); 
         init_phase = SD_SEND_CMD0; 
         break; 
    
         case SD_SEND_CMD0: 
         CS_LOW(); 
         response = send_cmd(CMD0,arg); 
         if(response == 0x01) 
          init_phase = SD_SEND_CMD8; 
         else 
          init_phase = SD_ERROR; 
         break; 
    
         case SD_SEND_CMD8: 
         arg = 0x000001AA; 
         response = send_cmd(CMD8,arg); 
         if(response == 0x01) 
          init_phase = SD_SEND_CMD55; 
         else 
          init_phase = SD_ERROR; 
         break; 
    
         case SD_SEND_CMD55: 
         arg = 0x00000000; 
         response = send_cmd(CMD55,arg); 
         if(response == 0x01) 
          init_phase = SD_SEND_ACMD41; 
         else 
          init_phase = SD_ERROR; 
         break; 
    
         case SD_SEND_ACMD41: 
         arg = 0x40000000; 
         response = send_cmd(ACMD41,arg); 
         if(response == 0x00) 
          init_phase = SD_SEND_CMD58; 
         else 
         { 
          // HAL_Delay(1000); 
          init_phase = SD_SEND_CMD55; 
         } 
         break; 
    
         case SD_SEND_CMD58: 
         arg = 0x00000000; 
         response = send_cmd(CMD58,arg); 
         break; 
    
         case SD_ERROR: 
         CS_HIGH(); 
         Stat = STA_NODISK; 
         break; 
    
         default: 
         // Something went wrong - Try to re-init 
         init_phase = SD_POWER_CYCLE; 
         spi_init(); 
         break; 
    
        } 
        } 
    
        return Stat; 
        /* USER CODE END INIT */ 
    } 
    
    ... 
    ... 
    
    void spi_init(void) 
    { 
        CS_HIGH(); 
        HAL_Delay(10); 
    } 
    
    uint8_t send_cmd(BYTE cmd, DWORD arg) 
    { 
        // cmd packet is of fixed lenght 
        uint8_t cmd_packet[6] = {0}; 
    
        // Response 
        uint8_t cmd_response = 0xFF; 
        // R1 is 1 byte only and it is used for most commands 
        uint8_t r1 = 0xFF; 
        // Commands R3 and R7 are 5 bytes long, (R1 + trailing 32-bit data) 
        uint8_t r3_7[5] = {0}; 
    
        // First byte is the command 
        // The cmd_packet must start with 01, therefore we add 0x40 to the cmd byte 
        cmd_packet[0] = 0x40 | cmd; 
    
        // Four bytes for the argument 
        for(uint8_t i = 1; i<=4; i++) 
        cmd_packet[i] = (uint8_t)(arg >> (4-i)*8); 
    
        // Add crc: it must be correct for CMD0 and CMD 8 only; for other commands, we use a dummy crc (0x01) 
        if(cmd == CMD0) 
        cmd_packet[5] = 0x95; 
        else if(cmd == CMD8) 
        cmd_packet[5] = 0x87; 
        else if(cmd == ACMD41) 
        cmd_packet[5] = 0x95; 
        else 
        cmd_packet[5] = 0x01; 
    
        // Send the command 
        HAL_SPI_Transmit(&hspi2, cmd_packet, sizeof(cmd_packet), DEFAULT_TIMEOUT); 
    
        // Receive the answer from SDcard 
    
        switch(cmd) 
        { 
        case CMD0: 
         // Try 3 times to get the answer 
         for(uint8_t j = 0; j<3; j++) 
         { 
         HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT); 
         HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT); 
         if(r1 != 0xFF) 
          return r1; 
         } 
        break; 
    
        case CMD8: 
         HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT); 
         HAL_SPI_Receive(&hspi2,r3_7,sizeof(r3_7),DEFAULT_TIMEOUT); 
         if(r3_7[3] == 0x01 && r3_7[4] == 0xAA) 
         return 0x01; 
        break; 
    
        case CMD55: 
         HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT); 
         HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT); 
         if(r1 != 0xFF) 
         return r1; 
        break; 
    
        case ACMD41:   
         for(int i = 0; i<150; i++) 
         { 
         HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT); 
         HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT); 
         if(r1 == 0x00) 
          return r1; 
         else 
          HAL_Delay(10); 
         } 
         return 0xFF; 
        break; 
    
        case CMD58: 
         HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT); 
         HAL_SPI_Receive(&hspi2,r3_7,sizeof(r3_7),DEFAULT_TIMEOUT); 
         if(r3_7[1] & (1<<7)) 
         return 0x01; 
         else 
         return 0x00; 
         break; 
        } 
    } 
    
  • 답변

    1

    저도 같은 문제가 있습니다. 나는 SDHC 카드에 STM32F107VC 보드를 인터페이스했다. 그리고 나는 FatF를 사용하는데 성공했다. 이 문제 야 듀폰 Line.Like 그런 다음 일이 (连接)

    와 SD 모듈과 연결된 SD를 사용하여 forwent에 대해 는 사실 내가 어떤 단서를 찾을 수 없을 ... 나는 또한 mircoSD이 인터페이스도 성공.

    내 코드 :

    SD_SPI_Mode.c

    #include <stdio.h> 
    #include "SD_SPI_Mode.h" 
    #include "hdware.h" 
    
    SD_INFO G_SDCARD_INFO; 
    
    SDErrorType SDInit(void) 
    { 
        u16 Response1; 
        u16 Buff[6] = {0}; 
        u16 Retry; 
    
        SPI_SetSpeed(SPI_BaudRatePrescaler_256); 
    
        for (Retry = 0; Retry < 10; Retry++) //至少74个时钟的高电平 
        { 
         SPI_ReadWriteByte2(DUMMY_BYTE); 
        } 
        Retry = 0; 
        sdEnable(); 
        for (Retry = 0; Retry < 0xFFF; Retry++) 
        { 
         Response1 = SDSendCommand(CMD0, 0, 0x95); 
         if (Response1 == 0x01) 
         { 
          Retry = 0; 
          break; 
         } 
        } 
    
        if (Retry == 0xFFF) 
        { 
         //printf("Reset card into IDLE state failed!\r\n"); 
         return ERROR_NOT_IN_IDLE; 
        } 
    
        Response1 = SDSendCommandHold(CMD8, 0x1AA, 0x87); 
    
        if (Response1 == 0x05) 
        { 
         G_SDCARD_INFO.CardType = CARDTYPE_SDV1; 
         sdDisable(); 
         //SPI_ReadWriteByte2(DUMMY_BYTE); 
    
         for (Retry = 0; Retry < 0xFFF; Retry++) 
         { 
          Response1 = SDSendCommand(CMD55, 0, 0); 
          if (Response1 != 0x01) 
          { 
           return ERROR_CMD55; 
          } 
          Response1 = SDSendCommand(ACMD41, 0, 0); 
          if (Response1 == 0x00) 
          { 
           Retry = 0; 
           break; 
          } 
         } 
    
         if (Retry == 0xFFF) 
         { 
          for (Retry = 0; Retry < 0xFFF; Retry++) 
          { 
           Response1 = SDSendCommand(CMD1, 0, 0); /* should be return 0x00 */ 
           if (Response1 == 0x00) 
           { 
            Retry = 0; 
            break; 
           } 
          } 
          if (Retry == 0xFFF) 
          { 
           return ERROR_CMD1; 
          } 
          G_SDCARD_INFO.CardType = CARDTYPE_MMC; 
          //printf("Card Type: MMC\r\n"); 
         } 
         else 
         { 
          G_SDCARD_INFO.CardType = CARDTYPE_SDV1; 
          //printf("Card Type: SD V1\r\n"); 
         } 
    
          Response1 = SDSendCommand(CMD16, BLOCKSIZE, 0xFF); 
    
          if (Response1 != 0x00) 
          { 
           return ERROR_CMD16; 
          } 
        } 
        else if (Response1 == 0x01) 
        { 
         Buff[0] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x00 
         Buff[1] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x00 
         Buff[2] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x01 
         Buff[3] = SPI_ReadWriteByte2(DUMMY_BYTE); //0xAA 
    
         sdDisable(); 
    
         if (Buff[2] == 0x01 && Buff[3] == 0xAA) //检查电压范围 
         { 
          for (Retry = 0; Retry < 0xFFF; Retry++) 
          { 
           Response1 = SDSendCommand(CMD55, 0, 0x01); 
           sdEnable(); 
           Response1 = SPI_ReadWriteByte2(DUMMY_BYTE); 
           sdDisable(); 
    
           Response1 = SDSendCommand(ACMD41, 0x40FF8000, 0xFF); 
           if (Response1 == 0x00) 
           { 
            Retry = 0; 
            break; 
           } 
          } 
          if (Retry == 0xFFF) 
          { 
           return ERROR_ACMD41; 
          } 
           Response1 = SDSendCommandHold(CMD58, 0, 0); 
          if (Response1 != 0x00) 
          { 
           return ERROR_CMD58; 
          } 
    
          Buff[0] = SPI_ReadWriteByte2(DUMMY_BYTE); 
          Buff[1] = SPI_ReadWriteByte2(DUMMY_BYTE); 
          Buff[2] = SPI_ReadWriteByte2(DUMMY_BYTE); 
          Buff[3] = SPI_ReadWriteByte2(DUMMY_BYTE); 
    
          sdDisable(); 
    
          if (Buff[0] & 0x40) // OCR -> CCS(bit30) 1: SDV2HC 0: SDV2 
          { 
           G_SDCARD_INFO.CardType = CARDTYPE_SDV2HC; 
           //printf("Card Type: SD V2HC\r\n"); 
          } 
          else 
          { 
           G_SDCARD_INFO.CardType = CARDTYPE_SDV2; 
           //printf("Card Type: SD V2\r\n"); 
          } 
         } 
        } 
        SPI_SetSpeed(SPI_BaudRatePrescaler_2); 
        return ERROR_NOP; 
    } 
    
    SDErrorType getCardInfo(SD_INFO *G_SDCARD_INFO) 
    { 
        u8 CSD_Tab[16]; 
        u8 CID_Tab[16]; 
    
        if (SDSendCommand(CMD9, 0, 0x01)) //读CSD 
        { 
         return ERROR_CMD9; 
        } 
    
        sdEnable(); 
        if (SDReadToBuffer(CSD_Tab, 16, RELEASE)) 
        { 
         return ERROR_CSD_READ; 
        } 
        sdDisable(); 
    
        if (SDSendCommand(CMD10, 0, 0xFF)) //读CID 
        { 
         return ERROR_CMD10; 
        } 
    
        sdEnable(); 
        if (SDReadToBuffer(CID_Tab, 16, RELEASE)) 
        { 
         return ERROR_CID_READ; 
        } 
        sdDisable(); 
    
        /* Byte 0 */ 
        G_SDCARD_INFO->CSD.CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; 
        G_SDCARD_INFO->CSD.SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2; 
        G_SDCARD_INFO->CSD.Reserved1 = CSD_Tab[0] & 0x03; 
        /* Byte 1 */ 
        G_SDCARD_INFO->CSD.TAAC = CSD_Tab[1]; 
        /* Byte 2 */ 
        G_SDCARD_INFO->CSD.NSAC = CSD_Tab[2]; 
        /* Byte 3 */ 
        G_SDCARD_INFO->CSD.MaxBusClkFrec = CSD_Tab[3]; 
        /* Byte 4 */ 
        G_SDCARD_INFO->CSD.CardComdClasses = CSD_Tab[4] << 4; 
        /* Byte 5 */ 
        G_SDCARD_INFO->CSD.CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4; 
        G_SDCARD_INFO->CSD.RdBlockLen = CSD_Tab[5] & 0x0F; 
        /* Byte 6 */ 
        G_SDCARD_INFO->CSD.PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; 
        G_SDCARD_INFO->CSD.WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; 
        G_SDCARD_INFO->CSD.RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; 
        G_SDCARD_INFO->CSD.DSRImpl = (CSD_Tab[6] & 0x10) >> 4; 
        G_SDCARD_INFO->CSD.Reserved2 = 0; /* Reserved */ 
        G_SDCARD_INFO->CSD.DeviceSize = (CSD_Tab[6] & 0x03) << 10; 
        /* Byte 7 */ 
        G_SDCARD_INFO->CSD.DeviceSize |= (CSD_Tab[7]) << 2; 
        /* Byte 8 */ 
        G_SDCARD_INFO->CSD.DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6; 
        G_SDCARD_INFO->CSD.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; 
        G_SDCARD_INFO->CSD.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); 
        /* Byte 9 */ 
        G_SDCARD_INFO->CSD.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; 
        G_SDCARD_INFO->CSD.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; 
        G_SDCARD_INFO->CSD.DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1; 
        /* Byte 10 */ 
        G_SDCARD_INFO->CSD.DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7; 
        G_SDCARD_INFO->CSD.EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2; 
        G_SDCARD_INFO->CSD.EraseGrMul = (CSD_Tab[10] & 0x03) << 3; 
        /* Byte 11 */ 
        G_SDCARD_INFO->CSD.EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5; 
        G_SDCARD_INFO->CSD.WrProtectGrSize = (CSD_Tab[11] & 0x1F); 
        /* Byte 12 */ 
        G_SDCARD_INFO->CSD.WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; 
        G_SDCARD_INFO->CSD.ManDeflECC = (CSD_Tab[12] & 0x60) >> 5; 
        G_SDCARD_INFO->CSD.WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; 
        G_SDCARD_INFO->CSD.MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2; 
        /* Byte 13 */ 
        G_SDCARD_INFO->CSD.MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6; 
        G_SDCARD_INFO->CSD.WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5; 
        G_SDCARD_INFO->CSD.Reserved3 = 0; 
        G_SDCARD_INFO->CSD.ContentProtectAppli = (CSD_Tab[13] & 0x01); 
        /* Byte 14 */ 
        G_SDCARD_INFO->CSD.FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; 
        G_SDCARD_INFO->CSD.CopyFlag = (CSD_Tab[14] & 0x40) >> 6; 
        G_SDCARD_INFO->CSD.PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; 
        G_SDCARD_INFO->CSD.TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; 
        G_SDCARD_INFO->CSD.FileFormat = (CSD_Tab[14] & 0x0C) >> 2; 
        G_SDCARD_INFO->CSD.ECC = (CSD_Tab[14] & 0x03); 
        /* Byte 15 */ 
        G_SDCARD_INFO->CSD.CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1; 
        G_SDCARD_INFO->CSD.Reserved4 = 1; 
    
        if (G_SDCARD_INFO->CardType == CARDTYPE_SDV2HC) 
        { 
         /* Byte 7 */ 
         G_SDCARD_INFO->CSD.DeviceSize = (u16)(CSD_Tab[8]) * 256; 
         /* Byte 8 */ 
         G_SDCARD_INFO->CSD.DeviceSize += CSD_Tab[9]; 
        } 
    
        G_SDCARD_INFO->Capacity = G_SDCARD_INFO->CSD.DeviceSize * BLOCKSIZE * 1024; 
        G_SDCARD_INFO->BlockSize = BLOCKSIZE; 
    
        /* Byte 0 */ 
        G_SDCARD_INFO->CID.ManufacturerID = CID_Tab[0]; 
        /* Byte 1 */ 
        G_SDCARD_INFO->CID.OEM_AppliID = CID_Tab[1] << 8; 
        /* Byte 2 */ 
        G_SDCARD_INFO->CID.OEM_AppliID |= CID_Tab[2]; 
        /* Byte 3 */ 
        G_SDCARD_INFO->CID.ProdName1 = CID_Tab[3] << 24; 
        /* Byte 4 */ 
        G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[4] << 16; 
        /* Byte 5 */ 
        G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[5] << 8; 
        /* Byte 6 */ 
        G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[6]; 
        /* Byte 7 */ 
        G_SDCARD_INFO->CID.ProdName2 = CID_Tab[7]; 
        /* Byte 8 */ 
        G_SDCARD_INFO->CID.ProdRev = CID_Tab[8]; 
        /* Byte 9 */ 
        G_SDCARD_INFO->CID.ProdSN = CID_Tab[9] << 24; 
        /* Byte 10 */ 
        G_SDCARD_INFO->CID.ProdSN |= CID_Tab[10] << 16; 
        /* Byte 11 */ 
        G_SDCARD_INFO->CID.ProdSN |= CID_Tab[11] << 8; 
        /* Byte 12 */ 
        G_SDCARD_INFO->CID.ProdSN |= CID_Tab[12]; 
        /* Byte 13 */ 
        G_SDCARD_INFO->CID.Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; 
        /* Byte 14 */ 
        G_SDCARD_INFO->CID.ManufactDate = (CID_Tab[13] & 0x0F) << 8; 
        /* Byte 15 */ 
        G_SDCARD_INFO->CID.ManufactDate |= CID_Tab[14]; 
        /* Byte 16 */ 
        G_SDCARD_INFO->CID.CID_CRC = (CID_Tab[15] & 0xFE) >> 1; 
        G_SDCARD_INFO->CID.Reserved2 = 1; 
    
        return ERROR_NOP; 
    } 
    
    SDErrorType SDReadToBuffer(u8 *buff, u16 len, u8 release) 
    { 
        u16 Response1; 
        u16 Retry; 
    
        //Start Block 
        for (Retry = 0; Retry < 2000; Retry++) 
        { 
         Response1 = SPI_ReadWriteByte2(DUMMY_BYTE); 
         if (Response1 == 0xFE) 
         { 
          Retry = 0; 
          break; 
         } 
        } 
        //Time out 
        if (Retry == 2000) 
        { 
         return ERROR_TIME_OUT; 
        } 
    
        //Start Read 
        for (Retry = 0; Retry < len; Retry++) 
        { 
         *(buff + Retry) = SPI_ReadWriteByte2(DUMMY_BYTE); 
        } 
    
        //CRC 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        if (release) 
        { 
         sdDisable();   
         SPI_ReadWriteByte2(DUMMY_BYTE); 
        } 
    
        return ERROR_NOP; 
    } 
    
    SDErrorType SDReadSingleBlock(u32 sector, u8 *Buffer) 
    { 
        if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC) 
        { 
         sector = sector << 9; 
        } 
        if (SDSendCommand(CMD17, sector, 0x55)) 
        { 
         return ERROR_CMD17; 
        } 
    
        sdEnable(); 
    
        if (SDReadToBuffer(Buffer, BLOCKSIZE, RELEASE)) 
        { 
         return ERROR_DATA_READ; 
        } 
        sdDisable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        return ERROR_NOP; 
    } 
    
    SDErrorType SDReadMultiBlock(u32 sector, u8 *Buffer, u32 NumOfSector) 
    { 
        u32 i; 
    
        if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC) 
        { 
         sector = sector << 9; 
        } 
    
        if (SDSendCommand(CMD18, sector, 0)) 
        { 
         return ERROR_CMD18; 
        } 
    
        sdEnable(); 
    
        for (i = 0; i < NumOfSector; i++) 
        { 
         if (SDReadToBuffer(Buffer + i * BLOCKSIZE, BLOCKSIZE, HOLD)) 
         { 
          SDSendCommand(CMD12, 0, 0); 
          sdDisable(); 
          return ERROR_DATA_READ; 
         } 
        } 
    
        SDSendCommand(CMD12, 0, 0); //停止位 
    
        sdDisable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        return ERROR_NOP; 
    } 
    
    SDErrorType SDWriteFromBuffer(u8 *buffer, bool isMultiply) 
    { 
        u16 Response1; 
        u16 i; 
        if (!isMultiply) 
        { 
         SPI_ReadWriteByte2(0xFE); 
        } 
        else if (isMultiply) 
        { 
         SPI_ReadWriteByte2(0xFC); 
        } 
    
        for (i = 0; i < BLOCKSIZE; i++) 
        { 
         SPI_ReadWriteByte2(*buffer++); 
        } 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        Response1 = SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        if ((Response1 & 0x1F) != 0x05) 
        { 
         return ERROR_DATA_WRITE; 
        } 
    
        return ERROR_NOP; 
    } 
    
    SDErrorType SDWriteSingleBlock(u32 sector, u8 *buffer) 
    { 
        if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC) 
        { 
         sector = sector << 9; 
        } 
    
        if (SDSendCommand(CMD24, sector, 0)) 
        { 
         return ERROR_CMD24; 
        } 
        sdEnable(); 
    
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        SDWriteFromBuffer(buffer, false); 
    
        if(SDBusyWait()) 
        { 
         sdDisable(); 
         return ERROR_DATA_WRITE; 
        } 
    
        sdDisable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        return ERROR_NOP; 
    } 
    
    SDErrorType SDWriteMultiBlock(u32 sector, u8 *Buffer, u32 NumOfSector) 
    { 
        u32 n; 
    
        if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC) 
        { 
         sector = sector << 9; 
        } 
    
        if (G_SDCARD_INFO.CardType != CARDTYPE_MMC) 
        { 
         SDSendCommand(ACMD23, NumOfSector, 0x00); 
        } 
    
        if (SDSendCommand(CMD25, sector, 0)) 
        { 
         return ERROR_CMD25; 
        } 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        sdEnable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        for (n = 0; n < NumOfSector; n++) 
        { 
         SDWriteFromBuffer(Buffer, true); 
        } 
    
        if (SPI_ReadWriteByte2(0xFD)) 
        { 
         return ERROR_DATA_WRITE; 
        } 
    
        if(SDBusyWait()) 
        { 
         sdDisable(); 
         return ERROR_DATA_WRITE; 
        } 
    
        sdDisable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        return ERROR_NOP; 
    } 
    
    SDErrorType SDBusyWait(void) 
    { 
        u32 Retry = 0; 
        while (SPI_ReadWriteByte2(DUMMY_BYTE) == 0x00) 
        { 
         /* Timeout return */ 
         if (Retry++ == 0x40000) 
         { 
          return ERROR_TIME_OUT; 
         } 
        } 
        return ERROR_NOP; 
    } 
    
    u16 SDSendCommand(u8 cmd, u32 arg, u8 crc) 
    { 
        u16 Response1; 
        u16 Retry; 
    
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        sdEnable(); 
    
        SPI_ReadWriteByte2(cmd | 0x40); 
        SPI_ReadWriteByte2(arg >> 24); 
        SPI_ReadWriteByte2(arg >> 16); 
        SPI_ReadWriteByte2(arg >> 8); 
        SPI_ReadWriteByte2(arg); 
        SPI_ReadWriteByte2(crc | 1); 
    
        //Busy 
        for (Retry = 0; Retry < 200; Retry++) 
        { 
         Response1 = SPI_ReadWriteByte2(DUMMY_BYTE); 
         if (Response1 != 0xFF) 
         { 
          break; 
         } 
        } 
        sdDisable(); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
    
        return Response1; 
    } 
    
    u16 SDSendCommandHold(u8 cmd, u32 arg, u8 crc) 
    { 
        u16 Response1; 
        u16 Retry; 
    
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        SPI_ReadWriteByte2(DUMMY_BYTE); 
        sdEnable(); 
    
        SPI_ReadWriteByte2(cmd | 0x40); 
        SPI_ReadWriteByte2(arg >> 24); 
        SPI_ReadWriteByte2(arg >> 16); 
        SPI_ReadWriteByte2(arg >> 8); 
        SPI_ReadWriteByte2(arg); 
        SPI_ReadWriteByte2(crc); 
    
        //Busy 
        for (Retry = 0; Retry < 200; Retry++) 
        { 
         Response1 = SPI_ReadWriteByte2(DUMMY_BYTE); 
         if (Response1 != 0xFF) 
         { 
          break; 
         } 
        } 
    
        return Response1; 
    } 
    

    SD_SPI_Mode.시간이

    #ifndef _SD_SPI_MODE_H_ 
    #define _SD_SPI_MODE_H_ 
    /* Includes ------------------------------------------------------------------*/ 
    #include "DIDO.h" 
    
    /* Private define ------------------------------------------------------------*/ 
    #define CARDTYPE_MMC 0x00 
    #define CARDTYPE_SDV1 0x01 
    #define CARDTYPE_SDV2 0x02 
    #define CARDTYPE_SDV2HC 0x04 
    
    #define DUMMY_BYTE 0xFF 
    #define BLOCKSIZE 512 
    
    /* SD/MMC command list - SPI mode */ 
    #define CMD0 0 /* Reset */ 
    #define CMD1 1 /* Send Operator Condition - SEND_OP_COND */ 
    #define CMD8 8 /* Send Interface Condition - SEND_IF_COND */ 
    #define CMD9 9 /* Read CSD */ 
    #define CMD10 10 /* Read CID */ 
    #define CMD12 12 /* Stop data transmit */ 
    #define CMD16 16 /* Set block size, should return 0x00 */ 
    #define CMD17 17 /* Read single block */ 
    #define CMD18 18 /* Read multi block */ 
    #define ACMD23 23 /* Prepare erase N-blokcs before multi block write */ 
    #define CMD24 24 /* Write single block */ 
    #define CMD25 25 /* Write multi block */ 
    #define ACMD41 41 /* should return 0x00 */ 
    #define CMD55 55 /* should return 0x01 */ 
    #define CMD58 58 /* Read OCR */ 
    #define CMD59 59 /* CRC disable/enbale, should return 0x00 */ 
    
    #define sdEnable() GPIO_ResetBits(SD_CS_PORT, SD_CS_PIN) 
    #define sdDisable() GPIO_SetBits(SD_CS_PORT, SD_CS_PIN) 
    #define MSD0_card_power_on() ; 
    #define isCardInsert() 0 
    
    enum _CD_HOLD 
    { 
        HOLD = 0, 
        RELEASE = 1, 
    }; 
    
    typedef enum  
    { 
        ERROR_NOP = 0, 
        ERROR_NOT_IN_IDLE, 
        ERROR_TIME_OUT, 
        ERROR_CSD_READ, 
        ERROR_CID_READ, 
        ERROR_DATA_READ, 
        ERROR_DATA_WRITE, 
        ERROR_ACMD41, 
        ERROR_CMD1, 
        ERROR_CMD9, 
        ERROR_CMD10, 
        ERROR_CMD16, 
        ERROR_CMD17, 
        ERROR_CMD18, 
        ERROR_CMD24, 
        ERROR_CMD25, 
        ERROR_CMD55, 
        ERROR_CMD58, 
        ERROR_CMD59, 
    } SDErrorType; 
    
    typedef struct /* Card Specific Data */ 
    { 
        vu8 CSDStruct;   /* CSD structure */ 
        vu8 SysSpecVersion;  /* System specification version */ 
        vu8 Reserved1;   /* Reserved */ 
        vu8 TAAC;    /* Data read access-time 1 */ 
        vu8 NSAC;    /* Data read access-time 2 in CLK cycles */ 
        vu8 MaxBusClkFrec;  /* Max. bus clock frequency */ 
        vu16 CardComdClasses; /* Card command classes */ 
        vu8 RdBlockLen;   /* Max. read data block length */ 
        vu8 PartBlockRead;  /* Partial blocks for read allowed */ 
        vu8 WrBlockMisalign;  /* Write block misalignment */ 
        vu8 RdBlockMisalign;  /* Read block misalignment */ 
        vu8 DSRImpl;    /* DSR implemented */ 
        vu8 Reserved2;   /* Reserved */ 
        vu32 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 CSD_CRC;    /* CSD CRC */ 
        vu8 Reserved4;   /* always 1*/ 
    } MSD_CSD; 
    
    typedef struct /*Card Identification Data*/ 
    { 
        vu8 ManufacturerID; /* ManufacturerID */ 
        vu16 OEM_AppliID; /* OEM/Application ID */ 
        vu32 ProdName1;  /* Product Name part1 */ 
        vu8 ProdName2;  /* Product Name part2*/ 
        vu8 ProdRev;  /* Product Revision */ 
        vu32 ProdSN;  /* Product Serial Number */ 
        vu8 Reserved1;  /* Reserved1 */ 
        vu16 ManufactDate; /* Manufacturing Date */ 
        vu8 CID_CRC;  /* CID CRC */ 
        vu8 Reserved2;  /* always 1 */ 
    } MSD_CID; 
    
    typedef struct 
    { 
        MSD_CSD CSD; 
        MSD_CID CID; 
        u32 Capacity; /* Card Capacity */ 
        u32 BlockSize; /* Card Block Size */ 
        u16 RCA; 
        u8 CardType; 
        u32 SpaceTotal; /* Total space size in file system */ 
        u32 SpaceFree; /* Free space size in file system */ 
    } SD_INFO; 
    
    extern SD_INFO G_SDCARD_INFO; 
    
    SDErrorType SDInit(void); 
    SDErrorType getCardInfo(SD_INFO *G_SDCARD_INFO); 
    SDErrorType SDReadSingleBlock(u32 sector, u8 *buffer); 
    SDErrorType SDReadMultiBlock(u32 sector, u8 *buffer, u32 NumOfSector); 
    SDErrorType SDWriteSingleBlock(u32 sector, u8 *buffer); 
    SDErrorType SDWriteMultiBlock(u32 sector, u8 *buffer, u32 NumOfSector); 
    
    static SDErrorType SDWriteFromBuffer(u8 *buffer,bool isMultiply); 
    static u16 SDSendCommand(u8 cmd, u32 arg, u8 crc); 
    static u16 SDSendCommandHold(u8 cmd, u32 arg, u8 crc); 
    static SDErrorType SDReadToBuffer(u8 *buff, u16 len, u8 release); 
    static SDErrorType SDBusyWait(void); 
    #endif 
    

    Additionly, 내 파일 작업 코드 :

    FileOperation.c

    #include "stdlib.h" 
    #include <stdbool.h> 
    #include "string.h" 
    #include "FileOperation.h" 
    
    
    static FATFS Fs;   //逻辑磁盘工作区. 
    static FIL File;   //文件 
    static FILINFO FileInfo; //文件信息 
    static DIR Dir;  //目录 
    static u8 SDBuf;   //SD缓存 
    
    FRESULT SDMount(u8 device) 
    { 
        return f_mount(device, &Fs); 
    } 
    
    FRESULT SDCreateDir(const u8 *pname) 
    { 
        return f_mkdir((const TCHAR *)pname); 
    } 
    
    FRESULT SDDirOpen(const u8 *path) 
    { 
        return f_opendir(&Dir, (const TCHAR *)path); 
    } 
    
    FRESULT SDDirRead(void) 
    { 
        FRESULT res; 
        char *FileName; 
        FileInfo.lfsize = _MAX_LFN * 2 + 1; 
        FileInfo.lfname = malloc(FileInfo.lfsize); 
        res = f_readdir(&Dir, &FileInfo); //读取一个文件的信息 
        if (res != FR_OK || FileInfo.fname[0] == 0) 
        { 
         free((void *)FileInfo.lfname); 
         return res; //读完了. 
        } 
        FileName = *(FileInfo.lfname) ? FileInfo.lfname : FileInfo.fname; 
        free((void *)FileInfo.lfname); 
        return FR_OK; 
    } 
    
    FRESULT SDFileRead(u8 *buf, u16 len) 
    { 
        u16 i; 
        FRESULT res; 
        UINT ByteCount; 
        for (i = 0; i < len/512; i++) 
        { 
         res = f_read(&File, buf, 512, &ByteCount); 
         if (res) 
         { 
          break; 
         } 
        } 
        if (len % 512) 
        { 
         res = f_read(&File, buf, len % 512, &ByteCount); 
        } 
        return res; 
    } 
    
    TCHAR *SDReadString(u16 size) 
    { 
        TCHAR *rbuf; 
        rbuf = f_gets((TCHAR *)&SDBuf, size, &File); 
        if (*rbuf == 0) 
         return NULL; //没有数据读到 
        else 
        { 
         return rbuf; 
        } 
    } 
    
    FRESULT SDFileWrite(const u8 *data, u16 len) 
    { 
        UINT ByteCount; 
        return f_write(&File, data, len, &ByteCount); 
    } 
    
    FRESULT SDScanFiles(const u8 *path, char **FileName) 
    { 
        FRESULT res; 
        u16 FileNum = 0; 
        FileInfo.lfsize = _MAX_LFN * 2 + 1; 
        FileInfo.lfname = malloc(FileInfo.lfsize); 
    
        res = f_opendir(&Dir, (const TCHAR *)path); //打开一个目录 
        if (res == FR_OK) 
        { 
         while (1) 
         { 
          res = f_readdir(&Dir, &FileInfo); //读取目录下的一个文件 
          if (res != FR_OK || FileInfo.fname[0] == 0) 
           break; //错误了/到末尾了,退出 
          FileName[FileNum] = *FileInfo.lfname ? FileInfo.lfname :  FileInfo.fname; 
          FileNum++; 
         } 
        } 
        free(FileInfo.lfname); 
        return res; 
    } 
    
    FRESULT SDShowFree(const u8 *drv, u32 *FreeSector, u32 *TotalSector) 
    { 
        FATFS *fs1; 
        FRESULT res; 
        u32 FreeClust = 0; 
        res = f_getfree((const TCHAR *)drv, (DWORD *)&FreeClust, &fs1); 
        if (res == FR_OK) 
        { 
         *TotalSector = (fs1->n_fatent - 2) * fs1->csize; //总扇区数 
         *FreeSector = FreeClust * fs1->csize;   //空闲扇区数 
         (*TotalSector) >>= 11; 
         (*FreeSector) >>= 11; 
        } 
        return res; 
    } 
    
    FRESULT SDFormat(u8 device, u8 mode, u16 au) 
    { 
        return f_mkfs(device, mode, au); //格式化,drv:盘符;mode:模式;au:簇大小 
    } 
    
    FRESULT SDRemoveFileOrDir(const u8 *pname) 
    { 
        return f_unlink((const TCHAR *)pname); 
    } 
    
    FRESULT SDRename(const u8 *oldname, const u8 *newname) 
    { 
        return f_rename((const TCHAR *)oldname, (const TCHAR *)newname); 
    } 
    
    FRESULT SDFileOpen(const u8 *path, u8 mode) 
    { 
        return f_open(&File, (const TCHAR *)path, mode); 
    } 
    
    FRESULT SDFileClose(void) 
    { 
        return f_close(&File); 
    } 
    
    u32 SDFileSize(void) 
    { 
        return f_size(&File); 
    } 
    
    FRESULT SDArgumentRead(const u8 *path, ArgumentInfo *argument, UINT *RecordNum) 
    { 
        FRESULT res; 
        u8 *PointToBuff; 
        UINT ByteCount; 
    
        res = SDFileOpen(path, FA_READ); 
        if (res != FR_OK) 
         return res; 
    
        PointToBuff = malloc(File.fsize); 
    
        res = f_read(&File, PointToBuff, File.fsize, &ByteCount); 
        if (res != FR_OK) 
        { 
         return res; 
        } 
    
        SDDataSolve(PointToBuff, argument, ByteCount, RecordNum); 
    
        free(PointToBuff); 
    
        return SDFileClose(); 
    } 
    
    FRESULT SDFileAppend(const u8 *path, const u8 *filename, const u8 *buff) 
    { 
        FRESULT res; 
        u16 len = strlen((const char*)buff); 
        u8 *FullPath; 
    
        res = SDCreateDir(path); 
        FullPath = malloc(strlen((const char*)path) + strlen((const char*)filename) + 2); 
    
        SDComplatePath(path, filename, FullPath); 
    
        res = SDFileOpen(FullPath, FA_OPEN_EXISTING | FA_WRITE); 
    
        if (res == FR_NO_FILE) 
         res = SDFileOpen(FullPath, FA_CREATE_ALWAYS | FA_WRITE); 
    
        if (res != FR_OK) 
         return res; 
    
        free(FullPath); 
    
        SDLseek(File.fsize); 
        res = SDFileWrite(buff, len); 
    
        if (res != FR_OK) 
         return res; 
    
        return SDFileClose(); 
    } 
    
    float stringToFloat(u8 *InputString) 
    { 
        return atof((const char*)(InputString)); 
    } 
    
    int stringToInt(u8 *InputString) 
    { 
        return atoi((const char*)(InputString)); 
    } 
    
    FRESULT SDLseek(u32 offset) 
    { 
        return f_lseek(&File, offset); 
    } 
    
    void SDDataSolve(u8 *buff, ArgumentInfo *argument, UINT ByteCount, UINT *RecordNum) 
    { 
        u8 col = 0; 
        UINT fileRow = 0, CharNum = 0; 
        u8 *CorChar = buff; 
        bool isValueRegion = false; 
    
        while (CharNum != ByteCount) 
        { 
         if (*CorChar == '=') 
         { 
          isValueRegion = true; 
          argument[fileRow].key[col] = '\0'; 
          col = 0; 
         } 
         else if (*CorChar == '\r' && *(CorChar + 1) == '\n') 
         { 
          CorChar++; 
          argument[fileRow].value[col] = '\0'; 
          isValueRegion = false; 
          col = 0; 
          fileRow++; 
         } 
         else 
         { 
          if (isValueRegion) 
          { 
           argument[fileRow].value[col] = *CorChar; 
          } 
          else 
          { 
           argument[fileRow].key[col] = *CorChar; 
          } 
          col++; 
         } 
         CorChar++; 
         CharNum++; 
        } 
        *RecordNum = CharNum; 
    } 
    
    void SDComplatePath(const u8 *Path,const u8 *FileName, u8 *FullPath) 
    { 
        u8 TempPath = '/'; 
    
        strcpy((char*)FullPath, (const char*)Path); 
        strcat((char*)FullPath, (const char*)&TempPath); 
        strcat((char*)FullPath, (const char*)FileName); 
    
    } 
    

    그냥 test.May에 대한 나의 가난한 영어

    죄송합니다 ... 도움이 될, 그것은이다 내 혀가 아니야.

    +0

    코드를 제공해 주셔서 감사합니다. 나는 그것을 확실히 시도 할 것이다. 외부 풀업 저항이나 내부 저항을 사용 했습니까? 외부에서 사용하는 경우 어떤 가치가 있습니까? 그리고 어떤 라인을 위해? MISO 만 또는 MOSI? – Alek

    +0

    47k 외부 풀업 저항, MISO 전용. – user8873052

    +0

    귀하의 CPHA와 CPOL이 제 회사와 다릅니다. \t \t SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; \t SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; – user8873052

    관련 문제