⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 基于DALLAS 51单片机的SD/MMC卡驱动程序(C语言源代码)
💻 C
📖 第 1 页 / 共 3 页
字号:
   *  
   * Important note:
   *  - Must be augmented with 7 zeros!
   *
   */
  
  new_crc = old_crc;
  for (x = 7; x >= 0; x--) {
    new_crc <<= 1;
    new_crc |= GETBIT(data,x);
    if (GETBIT(new_crc, 7) == 1) {
      new_crc ^= 0x89; /* XOR with poly -- this clears the top bit, too!*/
    }
  }

  return new_crc;
}

/* Provides the zero-padding final step to CRC-7
 *
 * Input arguments:      
 *
 *   old_crc - value from last call to crc_7()
 *
 * Returns:
 *
 *   Finalized CRC-7 checksum 
 *
 */
uint8_t crc_7augment(uint8_t old_crc)
{
  unsigned char new_crc;
  int x;
  
  new_crc = old_crc;
  for (x = 0; x < 7; x++) {
    new_crc <<= 1;
    if (GETBIT(new_crc, 7) == 1) {
      new_crc ^= 0x89; /* XOR with poly -- this clears the top bit, too!*/
    }
  }
  
  return new_crc;
}


/* CRC-16 (CCITT) as described in the Secure Digital spec
 *
 * Input arguments:      
 *
 *   old_crc - 0x0000 to start new CRC, or value from previous call to continue
 *   data    - data byte to add to CRC computation
 *
 * Returns:
 *
 *   CRC-16 checksum which MUST be augmented by crc_16augment() before use
 *
 */
uint16_t crc_16(uint16_t old_crc, uint8_t data)
{
  uint16_t new_crc;
  uint8_t flipit;
  int x;

  /* CRC-16's polynomial is x^16 + x^12 + x^5 + 1 */

  new_crc = old_crc;
  for (x = 7; x >= 0; x--) {
    flipit = GETBIT(new_crc, 15); /* Carry-out from shift */
    new_crc <<= 1;
    new_crc |= GETBIT(data,x);
    if (flipit == 1) {
      /* Unlike CRC-7, we leave out the x^16 term because */
      /* the carry bit has left our register */
      new_crc ^= 0x1021; 
    }
  }

  return new_crc;
}

/* Provides the zero-padding final step to CRC-16
 *
 * Input arguments:      
 *
 *   old_crc - value from last call to crc_16()
 *
 * Returns:
 *
 *   Finalized CRC-16 checksum 
 *
 */
uint16_t crc_16augment(uint16_t old_crc)
{
  uint16_t new_crc;
  uint8_t flipit;
  int x;
  
  new_crc = old_crc;
  for (x = 0; x < 16; x++) {
    flipit = GETBIT(new_crc, 15);
    new_crc <<= 1;
    if (flipit == 1) {
      new_crc ^= 0x1021; 
    }
  }
  
  return new_crc;
}

/* Verifies CRC-7 or CRC-16 against expected value
 *
 * Input arguments:      
 *
 *   type       - SD_CRC7 or SD_CRC16
 *   b          - pointer to character data
 *   len        - length of data to check (must not be 0, 
 *                  which returns CRC_FAIL)
 *   expect     - expected CRC-7 (only LSB is significant) or CRC-16 value.
 *
 * Returns:
 *
 *   CRC_OK (0) - Data passes integrity check by selected CRC algorithm
 *   CRC_FAIL (-1) - Data fails integrity check or wrong
 */
int verifyCRC(int type, uint8_t *b, uint32_t len, uint16_t expect)
{
  uint16_t crc = 0x0000;
  int i;

  /* Sanity check arguments */
  if ((b == NULL) || (len < 1) || 
      (type != SD_CRC7) && (type != SD_CRC16)) {
    return CRC_FAIL;
  }

  for (i = 0; i < len; i++) {
    if (type == SD_CRC16) {
      crc = crc_16(crc, *(b+i));
    } else {
      crc = crc_7((uint8_t)(crc & 0x00ff), *(b+i));
    }
  }

  if (type == SD_CRC16) {
    crc = crc_16augment(crc);
  } else {
    crc = crc_7augment(crc);
  }

  if (type == SD_CRC16) {
    if (crc == expect) {
      return CRC_OK;
    }
  } else {
    if ((crc & 0x00ff) == (expect & 0x00ff)) {
      return CRC_OK;
    }
  }

  /* Always error out with failure by default. */
  return CRC_FAIL;
}

/* Decode Card Identification register into human-readable format
 *
 * Input arguments:
 *
 *   b          - pointer to data buffer holding CID
 *
 * Returns:
 *
 *   <none>
 *
 */
void decodeCID(uint8_t *b)
{
  cprintf(C"  Manufacturer ID: 0x%02x\r\n", b[0]);
  cprintf(C"  OEM/Application ID: %c%c\r\n", b[1], b[2]);
  cprintf(C"  Product Name: %c%c%c%c%c\r\n", b[3], b[4], b[5], b[6], b[7]);
  cprintf(C"  Product Revision: %u.%u\r\n", b[8], b[9]);
  cprintf(C"  Serial Number: 0x%04x%04x\r\n", 
	 (b[10] << 8)+b[11], (b[12] <<8) + b[13]);
  cprintf(C"  Date Code: 0x%04x\r\n", ((b[13] & 0x0f) << 8) + b[14]);
  return;
}

/* Transmit command to card. Calculates the proper CRC and handles framing 
 *
 * Input arguments:
 *
 *   cmd          - one of the SD card commands
 *   arg          - four bytes which hold the SD command argument
 *
 * Returns:
 *
 *   <none>
 *
 */
void xmitcmd(uint8_t cmd, uint8_t *arg)
{
  uint8_t crcb = 0x00; 
  uint8_t out;

  /* First byte has framing bits and command */
  out = 0x40 | (cmd & 0x3f);
  crcb = crc_7(crcb, out);
  xferSPI(out);
  /* Next five bytes hold arguments, if any */
  crcb = crc_7(crcb, arg[0]);
  xferSPI(arg[0]);
  crcb = crc_7(crcb, arg[1]);
  xferSPI(arg[1]);
  crcb = crc_7(crcb, arg[2]);
  xferSPI(arg[2]);
  crcb = crc_7(crcb, arg[3]);
  xferSPI(arg[3]);
  /* Finally, crc byte is transmitted, 
   * shifted left by one and the stop bit added 
   */
  crcb = crc_7augment(crcb);
  out = (crcb << 1) | 0x01;
  xferSPI(out);
}

/* Initialize SD card in SPI mode
 *
 * Input arguments:
 *
 *   retries - number of retries to attempt before erroring out
 *
 * Returns:
 *
 *   <none>
 *
 */
int init_sd_card(int retries)
{
  uint8_t rxdata;
  int status, errors, i;

  status = -1; /* Currently in error */
  errors = 0; /* Retry counter */

  CLEAR_ARGS(arg);

  /* Just in case the card is in some unknown state */
  /* Flush out all data and attempt to get back to an idle bus */
  flush_spi(516);

  /* Sent the CMD0_GO_IDLE_STATE while CS is asserted */
  /* This signals the SD card to fall back to SPI mode */
  while ((status == -1) && (errors < retries)) {
    cprintf(C"-> Send CMD0_GO_IDLE_STATE\r\n");
    xmitcmd(CMD0_GO_IDLE_STATE, arg);
    if ((i = waitForR1(&rxdata, 0)) < 0) {
      if (i == TR_TIMEOUT) {
	cprintf(C"ERROR: Timeout\r\n");
      }
      if (i == TR_NOT_IDLE) {
	cprintf(C"ERROR: Bus not idle\r\n");
      }
      errors++;
      continue;
    }
    if (rxdata != R1_IDLE) {
      cprintf(C"ERROR: R1 != R1_IDLE\r\n");
      errors++;
      continue;
    }
    status = 0; /* We're talking to the card */
    cprintf(C"-> Got Idle Card State\r\n");
  }

  if (status < 0) {
    /* Failure to talk to card */
    return TR_FAILURE;
  }

  /* Now that card is in SPI mode with IDLE bit set, we need */
  /*  to send the command to start its initialization process */
  /*  and wait for R1_IDLE to disappear before issuing other commands */
  status = 1;
  errors = 0;
  while(status && (errors < retries)) {
    cprintf(C"-> Send CMD55_APP_CMD\r\n");
    xmitcmd(CMD55_APP_CMD, arg);
    if (waitForR1(&rxdata, 0) < 0) {
      /* If this is a MultiMediaCard (not SD), it won't respond here */
      cprintf(C"ERROR: Timeout! Perhaps this is a MMC card?\r\n");
      return TR_TIMEOUT;
    }
    check_r1(rxdata, R1_IDLE);

    cprintf(C"-> Send ACMD41_SEND_OP_COND\r\n");
    xmitcmd(ACMD41_SEND_OP_COND, arg);
    if (waitForR1(&rxdata, 0) < 0) {
      cprintf(C"ERROR: Timeout on ACMD41_SEND_OP_COND\r\n");
      return TR_TIMEOUT;
    }
    status = rxdata & R1_IDLE;
    if (status) {
      /* Pause here for a bit to let the card start up */
      for (i = 0; i < 10000; i++); /* busy loop */
    }
  }
  if (status) {
    /* Card never signaled ready */
    return TR_FAILURE;
  }
    
  /* Enable CRC to protect against bus-induced data errors */
  
  cprintf(C"-> Send CMD59_CRC_ON_OFF\r\n");
  arg[3] = 0x01; /* LSB set to 1 enables CRC verification */
  xmitcmd(CMD59_CRC_ON_OFF, arg);
  CLEAR_ARGS(arg);
  if (waitForR1(&rxdata, 0) < 0) {
    cprintf(C"ERROR: Timeout on CMD59_CRC_ON_OFF\r\n");
    return TR_TIMEOUT;
  }
  check_r1(rxdata, R1_NOERROR);

  return TR_OK;
}

/* Retrieve the Card-specific Data register and decode
 *
 * Input arguments:
 *
 *   <none>
 *
 * Returns:
 *
 *   TR_OK if successful, TR_FAILURE otherwise
 *
 */
int get_sd_csd(void)
{
  uint8_t multiplier;
  uint32_t cardsize;

  CLEAR_ARGS(arg);

  cprintf(C"-> Requesting CSD (Card Specific Data)\r\n");
  xmitcmd(CMD9_SEND_CSD, arg);
  if (waitForR1(rxbuf, 18) < 0) {
    cprintf(C"ERROR: Timeout on CMD9_SEND_CSD\r\n");
    return -1;
  }
  check_r1(rxbuf[0], R1_NOERROR);

  if (verifyCRC(SD_CRC16, &rxbuf[1], 16, (rxbuf[17]<<8) + rxbuf[18]) 
      != CRC_OK) {
    cprintf(C"ERROR: Data block did not pass CRC16 check\r\n");
    return TR_FAILURE;
  }

  if (verifyCRC(SD_CRC7, &rxbuf[1], 15, (rxbuf[16] >> 1)) != CRC_OK) {
    cprintf(C"ERROR: CSD failed internal CRC7 check\r\n");
    return TR_FAILURE;
  }

  /* Decode Card Specific Data */
  /* A couple of items are of interest to us here: 
   * 
   *  - block size of card (typically 512, but may differ) from READ_BL_LEN
   *  - total size of card from C_SIZE, C_SIZE_MULT, and READ_BL_LEN
   *
   */

  /* Blocksize is easy to decode */
  blocksize = 0x01 << (rxbuf[6] & 0x0f);

  /* Cardsize is split over several bytes */
  cardsize = ((rxbuf[7] & 0x03) << 10) | (rxbuf[8] << 2) | (rxbuf[9] & 0xc0);

  /* Multiplier is also split over several bytes */
  multiplier = ((rxbuf[10] & 0x03) << 1) | (rxbuf[11] >> 7);

  /* Compute final card size */
  cardsize <<= (multiplier + 2); /* Multiplier is 2^(m+2) */

  switch (blocksize) {
    case 512:
      cardsize >>= 11;
      break;
    case 1024:
      break;
    case 2048:
      cardsize <<= 9;
      break;
    default:
      cprintf(C"Unsupported blocksize!\r\n");
      return TR_FAILURE;
      break;
  }

  cprintf(C"Card size: %uMB\r\n", cardsize);
  return TR_OK;
}

/* Retrieve the Card Identification register and decode
 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -