arm - SPI 模式下 microSD 卡初始化。 ACMD41 始终返回 0x01

标签 arm stm32 sd-card spi stm32l152

我正在尝试使用 SPI 将 microSD 卡与 STM32L152-DISCOVERY 板 (STM32L152RCT6 ARM Cortex-M3) 连接。最终目标是使用 FatFs ( http://elm-chan.org/fsw/ff/00index_e.html ) 将传感器数据存储在 SD 卡上,该数据也可以在 Decktop PC 上读取。 Chan 的网站上有一个非常有用的流程图,描述了初始化过程(http://elm-chan.org/docs/mmc/im/sdinit.png)。

不幸的是,我的代码中有一个问题,导致 SDCard 无法初始化。具体来说,当我发送命令 ACMD41 (CMD55+CMD41) 时,SD 卡始终返回 0x01

我已经多次修改我的代码,遵循一些关于堆栈溢出的帖子,特别是 SDHC microSD card and SPI initialization ,但问题仍然存在。

以下是我的系统的硬件和软件设置:

硬件设置

  • micro SD卡接口(interface)为UHS-I,容量16GB
  • SD卡适配器已连接到发现板上的 SPI2 端口
  • 对于 MISO、MOSI、CLK 引脚,我已启用上拉电阻。根据 MCU 数据表,内部上拉电阻应在 45 Kohm 左右。
  • microSD 卡的电源由 arduino 板提供,使用 5V 引脚(我知道这听起来很疯狂,但我现在没有任何其他电源,而且我读到过 5V 引脚arduino 的电流可在 5V 时提供高达 400 mA 的电流)
  • arduino GND、发现GND和SD卡适配器GND都连接在一起。

软件设置 - SPI 初始化

SPI 频率最初设置在 125 KHz 之间(我读到必须在 100 KHz - 400 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;
  }
}

最佳答案

我也有同样的问题。我将SDHC卡与STM32F107VC板连接起来。并且我成功地使用了FatFs。 实际上我从来没有找到任何关于这个问题的线索。我放弃使用SD模块并用杜邦线连接SD。像这样( 连接 )

然后就成功了...我还接口(interface)了一个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.h

#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

另外,我的文件操作代码:

文件操作.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);

}

仅供测试。可能会有帮助...

抱歉我的英语不好,这不是我的母语。

关于arm - SPI 模式下 microSD 卡初始化。 ACMD41 始终返回 0x01,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47041939/

相关文章:

c - 如何避免大量写入损坏SD卡?

c++ - 在 C++/iOS 中更改默认除以 0 的行为

c++ - 在stm32上解释来自触摸屏 Controller (ADS7843)的原始数据

ssl - boringssl 可以在裸机 ARM 系统中工作吗?

使用待机模式后无法刷新代码。初始化 ST-LINK 设备时出错。原因: (4) No device found on target

microcontroller - 如何读取多 channel ADC值?

sd卡的linux设备节点作为mmcblk访问CSD寄存器

c - 检测sd卡读卡器是否插入卡

assembly - ARM 汇编遍历字符串

android - 对于以上 Android 7,Genymotion ARM 翻译失败