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

📄 main.c

📁 基于DALLAS 51单片机的SD/MMC卡驱动程序(C语言源代码)
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Input arguments:
 *
 *   <none>
 *
 * Returns:
 *
 *   TR_OK if successful, TR_FAILURE otherwise
 *
 */
int get_sd_cid(void)
{
  CLEAR_ARGS(arg);

  cprintf(C"-> Requesting CID (Card Identification)\r\n");
  xmitcmd(CMD10_SEND_CID, arg);
  if (waitForR1(rxbuf, 18) < 0) {
    cprintf(C"ERROR: Timeout on CMD10_SEND_CID\r\n");
    return TR_FAILURE;
  }
  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: CID failed internal CRC7 check\r\n");
    return TR_FAILURE;
  }

  /* Dump human-readable Card Identification data */
  decodeCID(&rxbuf[1]);

  return 0;
}

/* Dump a buffer in hexadecimal and printable ASCII format to the console
 *
 * Input arguments:
 *
 *   b - byte buffer to dump
 *   len - number of bytes to dump
 *
 * Returns:
 *
 *   <none>
 *
 */
void hexdump(uint8_t *b, uint16_t len)
{
  int x, c;
  int line;

  cprintf(C"ADDR|  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F | ASCII\r\n");
  cprintf(C"------------------------------------------------------------------------\r\n");
  for (line = 0; line < ((len % 16) ? (len / 16) + 1 : (len / 16)); line++) {
    cprintf(C"%04X| ", line * 16);
    for (x = 0; x < 16; x++) {
      if (x + (line * 16) < len) {
	c = b[x+line*16];
	cprintf(C"%02x ", c);
      } else {
	cprintf(C"   ");
      }
    }
    cprintf(C"| ");
    for (x = 0; x < 16; x++) {
      if (x + (line * 16) < len) {
	c = b[x+line*16];
	if ((c > 0x1f) && (c < 0x7f)) {
	  cprintf(C"%c", c);
	} else {
	  cprintf(C".");
	}
      } else {
	cprintf(C" ");
      }
    }
    cprintf(C"\r\n");
  }
  cprintf(C"------------------------------------------------------------------------\r\n");
}

/* Read a block from the SD card into the block buffer
 *
 * Input arguments:
 *
 *   blocknr - block address to read 
 *
 * Returns:
 *
 *   TR_OK if successful, TR_FAILURE otherwise
 *
 */
int readblock(uint32_t blocknr)
{
  int result;
  /* Read a block from the card */

  cprintf(C"-> Reading block %u from card\r\n", blocknr);

  /* The SD card read command requires a byte address aligned on */
  /*  block boundaries. Compute this address from the block address */
  blocknr *= blocksize;

  /* This byte address is stored MSB-first in the argument buffer */
  arg[0] = (blocknr & 0xff000000L) >> 24;
  arg[1] = (blocknr & 0x00ff0000L) >> 16;
  arg[2] = (blocknr & 0x0000ff00L) >> 8;
  arg[3] = blocknr & 0x000000ffL;

  /* Transmit the read command plus the byte address argument */
  xmitcmd(CMD17_READ_SINGLE_BLOCK, arg);
  
  /* We read 514 bytes as this is the blocksize (512) plus two CRC-16 bytes */
  if ((result = waitForR1(rxbuf, 514)) < 0) {
    switch (result) {
      case TR_INVALID_ARG:
	cprintf(C"Invalid argument\r\n");
	break;
      case TR_TIMEOUT:
	cprintf(C"Data timeout\r\n");
	break;
      case TR_ERROR_TOKEN:
	cprintf(C"Error token: 0x%02x\r\n", rxbuf[1]);
	break;
      case TR_NOT_IDLE:
	cprintf(C"Bus not idle at end of transaction\r\n");
	break;
    }
    return TR_FAILURE;
  }
  if (check_r1(rxbuf[0], R1_NOERROR) < 0) {
    cprintf(C"Read failure\r\n");
    return TR_FAILURE;
  }

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

  /* Dump the data for the user to examine */
  hexdump(rxbuf+1, 512);

  return TR_OK;
}

/* Write the block buffer into the SD card at the specified address
 *
 * Input arguments:
 *
 *   blocknr - block address to write
 *
 * Returns:
 *
 *   TR_OK if successful, TR_FAILURE otherwise
 *
 */
int writeblock(uint32_t blocknr)
{
  uint8_t rxdata;
  uint16_t i, crc = 0x0000;
  int result;

  /* Write the block buffer back to card */

  cprintf(C"-> Write block %u to card\r\n", blocknr);

  /* Prepare the block buffer by adding the data start token */
  rxbuf[0] = 0xfe; 

  /* Run a CRC-16 over the 512 bytes of data and append this to the end */
  for (i = 1; i < 513; i++) {
    crc = crc_16(crc, rxbuf[i]);
  }
  crc = crc_16augment(crc);
  rxbuf[513] = crc >> 8;
  rxbuf[514] = crc & 0x00ff;

  /* The SD card read command requires a byte address aligned on */
  /*  block boundaries. Compute this address from the block address */
  blocknr *= blocksize;

  /* This byte address is stored MSB-first in the argument buffer */
  arg[0] = (blocknr & 0xff000000L) >> 24;
  arg[1] = (blocknr & 0x00ff0000L) >> 16;
  arg[2] = (blocknr & 0x0000ff00L) >> 8;
  arg[3] = blocknr & 0x000000ffL;

  /* Transmit the write command plus the byte address argument */
  xmitcmd(CMD24_WRITE_BLOCK, arg);

  /* The card will respond with a R1 format response indicating the */
  /*  validity of the command and argument before a write can begin */
  if ((result = waitForR1(&rxdata, 0)) < 0) {
    switch (result) {
      case TR_INVALID_ARG:
	cprintf(C"Invalid argument\r\n");
	break;
      case TR_TIMEOUT:
	cprintf(C"Data timeout\r\n");
	break;
      case TR_NOT_IDLE:
	cprintf(C"Bus not idle at end of transaction\r\n");
	break;
    }
    return TR_FAILURE;
  }
  if (check_r1(rxdata, R1_NOERROR) < 0) {
    return TR_FAILURE;
  }

  /* Send the block of data to the SD card */
  for (i = 0; i < BLOCK_BUFFER_LEN; i++) {
    rxdata = xferSPI(rxbuf[i]);
    if (rxdata != 0xff) {
      /* The bus should be idle whilst we are transmitting */
      /* If this is not the case, flag it */
      cprintf(C"During write, strange readback 0x%x\r\n", rxdata);
    }
  }

  /* Wait for the data response token */
  i = 0;
  rxdata = xferSPI(0xff);
  /* The format of the data response token is: xxx0ddd1 */
  /*  where x is don't-care, and ddd is the three-bit response code */
  while ((rxdata & 0x10) || ((rxdata & 0x01) == 0)) {
    i++;
    if (i > WAIT_WRITE_TIMEOUT) {
      /* After an arbitrarily large wait, give up and signal error */
      /* A fully-compliant SD host would use the timeout calculated */
      /*  from the CSD register to time out the write transaction */
      cprintf(C"Timeout\r\n");
      return TR_TIMEOUT; /* Write timeout */
    }
  }

  /* Interpret the response */
  switch ((rxdata & 0x0e) >> 1) {
    case 0x02:
      cprintf(C"Data accepted!\r\n");
      break;
    case 0x05:
      cprintf(C"Rejected (CRC)\r\n");
      break;
    case 0x06:
      cprintf(C"Rejected (Write)\r\n");
      break;
    default:
      cprintf(C"Illegal response!", rxdata);
      break;
  }

  /* The SD card will now send a stream of idle tokens (0x00) on its DO */
  /*  line to indicate that it is busy writing the requested data to */
  /*  the non-volatile storage. We must wait until the bus returns to */
  /*  idle (0xff) before issuing any other commands */
  i = 0;
  rxdata = xferSPI(0xff);
  while (rxdata != 0xff) {
    /* Busy token sent back. Keep looping until timeout */
    i++;
    if (i > WAIT_WRITE_TIMEOUT) {
      return TR_TIMEOUT; 
    }
    rxdata = xferSPI(0xff);
  }

  return TR_OK;
}

int main(void)
{
  uint8_t done, i, numarg, inbuf[INPUT_BUFFER_LEN];
  uint16_t blocknr;

  /* Set up the serial port for 115200 bps, no parity, 8 bits, 1 stop bit */
  SCON0 = SCON0_REN | SCON0_SM1;
  SMD0 = SMD0_SMOD0;   
  PR0 = 0x3afb;            /* 115200 bps for 16MHz HF xtal */

  /* Set up the SPI port */
  SPICF = 0x00;       /* Rising clock latches data, 8-bit */
  SPICK = 0x28;       /* div 42 sysclock == 380kHz */
  SPICN |= 0x03;      /* Enable SPI master */
  PD5 |= 0x10;        /* /SS used as an output */
  PO5 |= 0x10;        /* /SS = 1 */

  cprintf(C"\r\nMAXQ2000 SD Card via SPI Demo Application\r\n");

  done = 0;
  while (!done) {
    /* Output a prompt */
    cprintf(C"> ");
    
    /* Get input */
    i = 0;
    while ((i < INPUT_BUFFER_LEN-1) && ((inbuf[i] = readuart())!= 0x0d)) {
      cprintf(C"%c", inbuf[i]);
      i++;
    }
    cprintf(C"\r\n");
    inbuf[i] = 0x00; /* Null terminate at all costs */

    /* Attempt to convert to command */
    if ((numarg = sscanf(inbuf, "%c %hu", &i, &blocknr)) < 1) {
      cprintf(C"No command.");
    } else {
      switch (i) {
	case 'd':
	  /* Dump the block buffer in a human-readable format */
	  hexdump(rxbuf, 1);
	  hexdump(rxbuf+1, 512);
	  hexdump(rxbuf+512, 2);
	  break;
	case 'c':
	  PO5 &= ~0x10; /* Select chip */
	  /* Retrieve Card Identification register */
	  get_sd_cid();
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	case 's':
	  PO5 &= ~0x10; /* Select chip */
	  /* Retrieve Card Specific Data register */
	  get_sd_csd();
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	case 'i':
	  PO5 &= ~0x10; /* Select chip */
	  /* Start the SD card in SPI mode */
	  if (init_sd_card(10) == TR_OK) {
	    cprintf(C"SD card intialized OK.\r\n");
	  } else {
	    cprintf(C"Error initializing SD card.\r\n");
	  }
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	case 'r':
	  /* Read a block into buffer and display */
	  PO5 &= ~0x10; /* Select chip */
	  if (numarg == 2) {
	    if (readblock(blocknr) == TR_OK) {
	      cprintf(C"Read successful.\r\n");
	    } else {
	      cprintf(C"Read failed.\r\n");
	    }
	  } else {
	    cprintf(C"Read requires block number <arg1>\r\n");
	  }
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	case 'w':
	  /* Write a block from buffer */
	  PO5 &= ~0x10; /* Select chip */
	  if (numarg == 2) {
	    if (writeblock(blocknr) == TR_OK) {
	      cprintf(C"Write successful.\r\n");
	    } else {
	      cprintf(C"Write failed.\r\n");
	    }
	  } else {
	    cprintf(C"Write requires block number\r\n");
	  }
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	case 'e':
	  /* Edit block buffer */
	  /* for now, simply zero buffer and put "MAXQ2000 SD SPI" in buffer */
	  cprintf(C"Block buffer cleared and set to default\r\n");
	  memset(rxbuf+1, 0x00, 512);
	  strcpy(rxbuf+1, "MAXQ2000 SD SPI");
	  break;
	case 'f':
	  /* Flush the SPI bus */
	  PO5 &= ~0x10; /* Select chip */
	  if (flush_spi(1000) == TR_TIMEOUT) {
	    cprintf(C"Error: Unable to flush SPI bus. Idle not detected.\r\n");
	  }
	  PO5 |= 0x10; /* Deselect chip */
	  break;
	default:
	  cprintf(C"Program Usage:\r\n");
	  cprintf(C" i           - Initialize card. MUST BE DONE FIRST AFTER ANY MEDIA CHANGE.\r\n");
	  cprintf(C" c           - Retrieve Card Identification register\r\n");
	  cprintf(C" s           - Retrieve Card Specific Data register\r\n");
	  cprintf(C" d           - Dump the block buffer in hexadecimal and ASCII format\r\n");
	  cprintf(C" r <address> - Reads card block <address> into the block buffer\r\n");
	  cprintf(C" w <address> - Writes the block buffer to card at block <address>\r\n");
	  cprintf(C" e           - Set block buffer to \"MAXQ2000 SD SPI\"\r\n");
	  cprintf(C" f           - Flush all SPI bus bytes until 5 idle bytes are detected\r\n");
	  break;
      }
    }
  }

  while (1); /* jump $ */
}

⌨️ 快捷键说明

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